Toulouse, le 17 octobre 2023
Aujourd’hui, nous annonçons la version 1.0 de pglift, un nouvel outil pour déployer et exploiter PostgreSQL à grande échelle. Le projet fournit à la fois une interface en ligne de commande pour gérer le cycle de vie de vos bases de données et une collection de modules Ansible pour piloter votre infrastructure as code dans un contexte de production.
À partir de ce jalon 1.0, l’interface utilisateur est stable et le produit considéré comme apte à une utilisation générale.
Qu’est-ce que pglift ?
Le projet vient du besoin des clients de Dalibo de déployer et d’exploiter un grand nombre d’instances PostgreSQL dans leur contexte de production, et ce d’une manière uniforme au sein de leur infrastructure :
- L’aspect production signifie que PostgreSQL, le moteur de base de données, a souvent besoin d’être complété par d’autres services de sauvegarde, supervision ou haute disponibilité.
- L’aspect uniforme fait typiquement référence à l’automatisation, ce qui signifie que les DBAs veulent rationaliser le déploiement de leur service de base de données afin de l’exploiter d’une manière plus sûre.
pglift essaie de répondre à ces enjeux en fournissant :
- une ligne de commande unifiée et accessible pour exploiter les instances de bases de données d’un site, et,
- une collection de modules Ansible pour automatiser le déploiement et l’exploitation au sein d’une infrastructure.
Dans les deux cas, le comportement de pglift est très configurable, depuis la façon dont l’instance PostgreSQL est déployée (authentification, stockage, journalisation, sauvegarde) jusqu’aux composants qui sont configurés à coté de l’instance pour permettre son exploitation dans un contexte de production (sauvegarde physique, supervision, haute disponibilité).
Quiconque souhaitant déployer et exploiter PostgreSQL à un niveau plus élevé
que les commandes initdb
ou pg_ctl
ou avec un besoin plus important
d’automatisation pourra trouver un intérêt dans pglift.
Ceci va des services informatiques de l’entreprise aux devops qui gèrent
leurs infrastructures en suivant les principes du GitOps.
D’un autre coté, pglift n’a pas vocation à être l’unique solution à tous les cas d’usage mais plutôt à être une brique logicielle composable avec d’autres. De ce fait, alors que pglift est un outil local et indépendant d’un framework de gestion d’infrastructure particulier, il s’intègre d’ores et déjà avec Ansible et pourrait être interfacé avec Terraform (ou Kubernetes) de manière similaire.
Même s’il reste aussi configurable que possible, son comportement résulte parfois de choix métiers particuliers, en général guidés par l’expertise de Dalibo.
Fini la théorie, voyons maintenant ce que pglift peut faire !
La ligne de commande
L’élément fondamental de pglift est l’instance, qui est constituée a minima d’une instance PostgreSQL mais inclut généralement des composants satellites. La création d’une instance en ligne de commande se fait comme suit :
$ pglift instance create main --pgbackrest-stanza=main
INFO initializing PostgreSQL
INFO configuring PostgreSQL authentication
INFO configuring PostgreSQL
INFO starting PostgreSQL 16-main
INFO creating role 'powa'
INFO creating role 'prometheus'
INFO creating role 'backup'
INFO altering role 'backup'
INFO creating 'powa' database in 16/main
INFO creating extension 'btree_gist' in database powa
INFO creating extension 'pg_qualstats' in database powa
INFO creating extension 'pg_stat_statements' in database powa
INFO creating extension 'pg_stat_kcache' in database powa
INFO creating extension 'powa' in database powa
INFO configuring Prometheus postgres_exporter 16-main
INFO configuring pgBackRest stanza 'main' for
pg1-path=/srv/pgsql/16/main/data
INFO creating pgBackRest stanza main
INFO starting Prometheus postgres_exporter 16-main
Nous voyons que, à coté de PostgreSQL, l’instance inclut un ensemblre d’extensions nécessaires à l’utilisation de PoWA, un service de supervision Prometheus postgres_exporter et un service pgBackRest pour la sauvegarde physique. Ces intégrations ne sont pas déclarées au moment de l’exploitation, mais plutôt configurées en avance de phase, localement, via ce que l’on appelle la configuration du site, sous la forme d’un fichier YAML tel que :
# file: /etc/pglift/settings.yaml
prefix: /srv
postgresql:
auth:
host: scram-sha-256
prometheus:
execpath: /usr/bin/prometheus-postgres-exporter
pgbackrest:
repository:
mode: path
path: /srv/pgsql-backups
powa: {}
systemd: {}
rsyslog: {}
En plus des services qui tournent à coté de PostgreSQL (supervision,
sauvegarde), pglift gère aussi des intégrations “système” telles que systemd
ou rsyslog
comme dans notre exemple. Tout ceci fonctionne sans privilège
root
pour une meilleure séparation des responsabilités et une meilleure
sécurité.
Une caractéristique fondamentale de pglift est d’être sans état tout en restant conscient de l’état des objets qu’il gère à l’exécution ; typiquement, cela permet de récupérer l’état d’une instance (à un moment donné) :
$ pglift instance get main -o json
{
"name": "main",
"version": "16",
"port": 5432,
"settings": {
"unix_socket_directories": "/run/user/1000/pglift/postgresql",
"shared_buffers": "1 GB",
"wal_level": "replica",
"archive_mode": true,
"archive_command": "/usr/bin/pgbackrest --config-path=/etc/pgbackrest --stanza=main --pg1-path=/srv/pgsql/16/main/data archive-push %p",
"effective_cache_size": "4 GB",
"log_destination": "syslog",
"logging_collector": true,
"log_directory": "/var/log/postgresql",
"log_filename": "16-main-%Y-%m-%d_%H%M%S.log",
"syslog_ident": "postgresql-16-main",
"cluster_name": "main",
"lc_messages": "C",
"lc_monetary": "C",
"lc_numeric": "C",
"lc_time": "C",
"shared_preload_libraries": "pg_qualstats, pg_stat_statements, pg_stat_kcache"
},
"data_checksums": false,
"locale": "C",
"encoding": "UTF8",
"standby": null,
"state": "started",
"pending_restart": false,
"wal_directory": "/srv/pgsql/16/main/wal",
"prometheus": {
"port": 9187
},
"data_directory": "/srv/pgsql/16/main/data",
"powa": {},
"pgbackrest": {
"stanza": "main"
}
}
ou de modifier l’instance :
$ pglift pgconf -i main set log_connections=on
INFO configuring PostgreSQL
INFO instance 16/main needs reload due to parameter changes: log_connections
INFO reloading PostgreSQL configuration for 16-main
log_connections: None -> True
$ pglift instance alter main --prometheus-port 8188
INFO configuring PostgreSQL
INFO reconfiguring Prometheus postgres_exporter 16-main
INFO instance 16/main needs reload due to parameter changes: log_connections
INFO reloading PostgreSQL configuration for 16-main
INFO starting Prometheus postgres_exporter 16-main
$ pglift instance get main
name version port data_checksums locale encoding pending_restart prometheus pgbackrest
main 16 5432 False C UTF8 False port: 9187 stanza: main
pglift peut aussi exploiter des objets PostgreSQL : bases de données, rôles, schémas, privilèges, etc.
De plus, les instances et les autres objets PostgreSQL peuvent être manipulés à l’aide des outils natifs de PostgreSQL depuis la ligne de commande pglift qui est composable en cela qu’elle transmet l’environnement de l’instance à la commande invoquée :
$ pglift instance exec main -- pgbench -i bench
creating tables...
generating data (client-side)...
100000 of 100000 tuples (100%) done (elapsed 0.06 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done in 0.18 s (drop tables 0.00 s, create tables 0.01 s, client-side generate 0.08 s, vacuum 0.04 s, primary keys 0.05 s).
$ pglift instance exec main -- pgbench bench
pgbench (16.0 (Debian 16.0-1.pgdg120+1))
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
maximum number of tries: 1
number of transactions per client: 10
number of transactions actually processed: 10/10
number of failed transactions: 0 (0.000%)
latency average = 1.669 ms
initial connection time = 4.544 ms
tps = 599.125277 (without initial connection time)
Ceci s’applique aussi à des outils tiers, par exemple :
$ pglift instance exec main -- pgbackrest info
stanza: main
status: ok
cipher: none
db (current)
wal archive min/max (16): 000000010000000000000001/000000010000000000000007
full backup: 20231016-092726F
timestamp start/stop: 2023-10-16 09:27:26+02 / 2023-10-16 09:27:31+02
wal start/stop: 000000010000000000000004 / 000000010000000000000004
database size: 32.0MB, database backup size: 32.0MB
repo1: backup set size: 4.2MB, backup size: 4.2MB
diff backup: 20231016-092726F_20231016-092821D
timestamp start/stop: 2023-10-16 09:28:21+02 / 2023-10-16 09:28:24+02
wal start/stop: 000000010000000000000007 / 000000010000000000000007
database size: 54.5MB, database backup size: 22.6MB
repo1: backup set size: 6MB, backup size: 1.8MB
backup reference list: 20231016-092726F
Pour plus de détails, voir le tutoriel de la ligne de commande.
Les modules Ansible
pglift fournit une collection de modules Ansible, sous l’espace de noms
dalibo.pglift
. Voici un exemple de playbook illustrant ses capacités :
- name: Set up database instances
hosts: dbserver
tasks:
- name: main instance
dalibo.pglift.instance:
name: main
state: started
port: 5444
settings:
max_connections: 100
shared_buffers: 1GB
shared_preload_libraries: 'pg_stat_statements, passwordcheck'
surole_password: '{{ postgresql_surole_password }}'
pgbackrest:
stanza: main
password: '{{ backup_role_password }}'
prometheus:
password: '{{ prometheus_role_password }}'
port: 9186
roles:
- name: admin
login: true
password: '{{ admin_password }}'
connection_limit: 10
validity: '2025-01-01T00:00'
in_roles:
- pg_read_all_stats
- pg_signal_backend
databases:
- name: main
owner: admin
settings:
work_mem: 3MB
extensions:
- name: unaccent
schema: public
Nous voyons que le module dalibo.pglift.instance
permet de gérer non
seulement l’instance, mais aussi les objets reliés comme des rôles ou des
bases de données. Les données sensibles (comme les mots de passe) peuvent être
pris en charge par une solution de gestion de secrets, telle que Ansible
vault. Les modules Ansible permettent un contrôle plus important que la ligne
de commandes, au sens où les champs imbriquées ou complexes, tels que les
la configuration de l’instance ou des bases de données, les extensions, etc.
Cette interface est complètement déclarative et idempotente, mais reste sans état (comme le sont les modules Ansible en général). Comme pour la ligne de commande, référez-vous au tutoriel Ansible de la documentation pour plus de détails. Notons aussi que ces modules fonctionnent avec d’autres modules Ansible, tels que community.postgresql.
À propos du projet
Sous le capôt, toute la logique métier est implémentée sous la forme d’une API Python. L’idée phare de pglift est de rendre la gestion d’infrastructure PostgreSQL déclarative et sans état afin de l’exploiter selon les principes de l’infrastructure-as-code. Cette conception a permis de développer à la fois une interface impérative en ligne de commandes et une interface déclarative, sous la forme de modules Ansible.
Le projet est nativement open source, mis à disposition sous licence GPLv3. Il est le fruit du travail d’une équipe de développeurs et d’administrateurs poursuivant l’objectif de pérenniser l’expertise de Dalibo dans un outil puissant, souple et accessible pour l’administration quotidienne de PostgreSQL. Son développement se passe en public :
- à https://gitlab.com/dalibo/pglift/, pour le projet principal (API Python et interface en ligne de commande), et,
- à https://gitlab.com/dalibo/pglift-ansible/, pour la collection Ansible
dalibo.pglift
.
Enfin, une grande attention a été portée à l’écriture d’une documentation exhaustive et accessible, incluant des tutoriels, des guides d’utilisations ou des recettes.