PostgreSQL wie von Zauberhand: Automation mit Ansible

Zaubertrick

Sollen mehrere ähnliche oder sogar identische Systeme aufgesetzt werden, eignet sich häufig das Werkzeug Ansible zur Automatisierung  so auch bei PostgreSQL. Ansible selbst bietet bereits 20 integrierte Module, mit denen eine PostgreSQL-Datenbank administriert werden kann. Damit lassen sich beispielsweise User und Datenbanken mit Tabellen anlegen, aber auch Einträge in der Datei pg_hba.conf verändern oder allgemeine Konfigurationsparameter definieren. Zusätzlich lassen sich viele weitere, von der Community erstellte Ansible-Rollen finden, die genutzt werden können. So hat auch EDB Rollen auf GitHub bereitgestellt, die in eigene Playbooks eingebunden werden können.

Installation von PostgreSQL mit Ansible

PostgreSQL wird mit Ansible am besten mit Hilfe des Paketmanagers des jeweiligen Betriebssystems installiert, denn dadurch wird die Idempotenz gewährleistet, die Ansible bietet. Hierbei kann zwischen zwei Ansätzen gewählt werden:
  1. Eigenständiges Einbinden und Installieren gemäß der PostgreSQL-Dokumentation
  2. Nutzung vorgefertigter Ansible-Rollen, die durch EDB bereitgestellt werden
Grundsätzlich führen beide Optionen zum gewünschten Ziel, dennoch gibt es bei beiden Vor- und Nachteile. Bei der ersten Option hat man die volle Kontrolle und kann das Playbook perfekt an die unternehmensinternen Gegebenheiten anpassen. Allerdings ist diese Vorgehensweise erheblich aufwändiger, als die vorgefertigten Rollen von EDB zu nutzen. Diese sind als Open-Source-Variante auf GitHub veröffentlicht und somit frei zugänglich. Hierbei wird dem Anwender bereits viel "abgenommen" und es müssen theoretisch nur das Betriebssystem und die gewünschte PostgreSQL-Version angegeben werden. Der größte "Nachteil" ist aber, dass diese Rollen auf die Repositories von EDB zugreifen und auch für die Community-Version von PostgreSQL ein Account bei EDB benötigt wird.

Manuelle Installation

Die eigenständige Lösung lässt sich sehr einfach realisieren. Es wird das Modul des jeweiligen Paketmanagers, in diesem Fall yum bei CentOS7, genutzt und das Repository von PostgreSQL eingebunden. Im nächsten Schritt kann der PostgreSQL-Server bereits installiert werden. Hierbei lassen sich alle Major-Versionen ab 9.5 bis Version 13 auswählen. Das folgende Beispiel zeigt einen Auszug eines Ansible-Playbooks. Der erste Task fügt das PostgreSQL Repository dem Paketmanager yum hinzu. Der zweite Task installiert die Pakete postgresql12, postgresql12-server und postgresql12-contrib. Weiterhin werden noch die beiden Pakete sslutils_12 und python-psycopg2 installiert. Durch die Installation mit Hilfe des Paketmanagers wird das PostgreSQL-Servicemodul automatisch beim systemd hinterlegt und gestartet.

- name: Install the postgresql repository RPM
  become: yes
  yum:
    name: https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    state: present

- name: Install postgresql server
  become: yes
  yum:
    name:
      - python-psycopg2
      - postgresql12
      - postgresql12-server
      - postgresql12-contrib
      - sslutils_12
    state: present 

Nutzung der EDB-Rollen

Sollen die von EDB bereitgestellten Ansible-Rollen genutzt werden, gibt es einige Beschränkungen:
  • OS: Es werden nur die folgenden vier Betriebssysteme unterstützt: CentOS7, CentOS8, RHEL7 und RHEL8
  • PostgreSQL-Versionen: Es werden nur die Major-Versionen 10 bis 13 unterstützt
  • Variante: Neben der Community-Edition wird auch die EDB-Version angeboten
pre_tasks:
  - name: Initialisierung der Variablen 
    set_fact:
      os: "CentOS7"
      pg_version: 12
      pg_type: "PG"
      yum_username: "<EDB-Benutzername>"
      yum_password: "<EDB-Passwort>"
roles:
  - setup_repo
  - install_dbserver 

Im Block pre_tasks werden die benötigten Variablen definiert. Dazu zählen das OS, die PostgreSQL-Version, der Typ, also Community- oder EDB-Edition, und die YUM-Zugangsdaten für die EDB-Repositories. Die beiden zur Installation benötigten Rollen lassen sich dann einfach aufrufen.

Initialisierung der Datenbank

EDB bietet für die Initialisierung der Datenbank eine Rolle - init_dbserver. Alternativ kann auch eine komplett eigene Lösung implementiert werden, allerdings lässt sich die Rolle von EDB - init_dbserver - auch in die eigene Installationslösung einbinden. Da sich die Rolle leicht an eigene Gegebenheiten anpassen lässt und bereits viele Konfigurationsoptionen bietet, soll nur die Arbeit mit der existierenden Rolle von EDB betrachtet werden.

EDB hat für die init_dbserver-Rolle alle verfügbaren Konfigurationsparameter in der Datei PG.yml abgelegt. Diese findet sich im vars-Ordner der Rolle (roles/init_dbserver/vars/PG.yml). Zu den Wichtigsten gehören aber wohl die Optionen, die letztendlich dem Befehl initdb übergeben werden, also die Angabe von Verzeichnissen, wie dem WAL-Verzeichnis oder dem Home-Verzeichnis. Es ist ebenfalls möglich, den Datenbank-Superuser - default postgres - zu verändern oder ihm ein Passwort mitzugeben. All diese Optionen können entweder direkt in der Datei ./vars/PG.yml oder im eigenen Playbook über die Option set_fact gesetzt werden.

pre_tasks:
  - name: Initialisierung der Variablen 
    set_fact:
      os: "CentOS7"
      pg_version: 12
      pg_type: "PG"
      pg_ssl: false
      pg_superuser_password: "postgres"
      pg_port: 5432
roles:
    - install_own_postgres
    - init_dbserver  

Zwischenstand: Bis zu diesem Schritt wurde eine PostgreSQL-Datenbank in der gewünschten Version installiert, initialisiert und bereits gestartet. Nun folgen Konfigurationsmöglichkeiten und allgemeine User- und Datenbankverwaltung.

Verwaltung von PostgreSQL mit Ansible

Um eine PostgreSQL-Instanz zu verwalten, eignen sich die integrierten PostgreSQL-Module sehr gut. Hier werden bereits die wichtigsten und für den täglichen Gebrauch notwendigen Module geboten. Dabei kann es sich um Monitoring-Aufgaben, also verwendete Datenbankversionen, in der Datenbank verfügbare und genutzte Rollen und Tablespaces handeln, oder um User- und Datenbankadministration.

Konfigurationen ändern

Ist eine PostgreSQL-Instanz initialisiert, sollen typischerweise direkt Änderungen in der Konfiguration getätigt werden. Bei PostgreSQL unterteilt sich dies in "allgemeine" Konfigurationen, die in der Datei postgresql.conf getätigt werden und in Änderungen der Datei pg_hba.conf. In letzterer wird festgelegt, welche User sich von welchem Host mit welcher Methode an der Datenbank anmelden können.

pg_hba.conf
Änderungen in der Datei pg_hba.conf können über das fast gleichnamige Modul postgresql_pg_hba durchgeführt werden. Die meisten Parameter sind wie üblich selbsterklärend. Über dest wird der Pfad zur Datei festgelegt und address definiert die Adressen, über die sich ein User anmelden darf. Hier sind neben der IP-Adresse auch die Optionen samehost, host, samenet oder all möglich. Mit der Option method wird in diesem Beispiel der Login per verschlüsseltem Passwort ermöglicht.

- name: Den Usern ordix und readOnly via Passwort Zugang gewähren
  postgresql_pg_hba:
    dest: /var/lib/pgsql/{{pg_version}}/data/pg_hba.conf
	address: all
    contype: host
    users: ordix,readOnly
    databases: ordix
    method: scram-sha-256 

Allgemeine Konfigurationen
Prinzipiell lassen sich alle Konfigurationsparameter durch das Modul postgresql_set verändern. Ansible nutzt hierbei den ALTER SYSTEM -Befehl, das heißt es wird der Benutzername eines Superusers und ein Passwort benötigt, um sich einzuloggen. Bei den meisten Parametern genügt ein reload der Konfiguration, dies geschieht auch automatisch. Dennoch gibt es Einstellungen, die einen Neustart des Servers erfordern. Ansible führt diesen nicht automatisch durch, gibt aber in diesen Fällen einen entsprechenden Hinweis über die Ausgabevariable restart_required. Dies kann im Playbook entsprechend abgefangen werden, dann kann ein separater Neustart über das Service-Modul erfolgen.

- name: Log rotation auf 10MB ändern
  become: yes
  become_user: "postgres"
  postgresql_set:
    name: log_rotation_size
    value: 10mb
    login_password: postgres
    login_user: postgres
  register: values

- name: Gebe die Rückgabewerte aus
  debug:
    msg: "{{ restart_req: {{ values.restart_required }} }}"

- name: Log rotation auf max. 120 Minuten ändern
  become: yes
  become_user: "postgres"
  postgresql_set:
    name: log_rotation_age
    value: 120 
    login_password: postgres
    login_user: postgres 

Eine Beispielausgabe des Playbooks wäre Folgende:

TASK [Gebe die Rückgabewerte aus]
********************************************************************************
*********************************************************************
ok: [postgres] => {
"msg": "restart_req: False"
} 

Ein Neustart des PostgreSQL-Servers ist, wie zu sehen, bei dieser Änderung nicht notwendig.

Datenbanken und Tabellen anlegen

Um Datenbanken und Tabellen zu verwalten, können die integrierten Module von Ansible genutzt werden und es muss nicht auf externe Rollen zurückgegriffen werden. Zu den wichtigsten Modulen in diesem Bereich zählen wohl:
  • postgresql_db
  • postgresql_table
  • postgresql_tablespace
tasks:
  - name: Erstelle eine neue Datenbank 'ordix'
    become: yes
    become_user: "postgres"
    postgresql_db:
      name: ordix
      encoding: UTF-8
      lc_collate: de_DE.UTF-8
      lc_ctype: de_DE.UTF-8
      template: template0

  - name: Erstelle eine Tabelle 'users' in 'ordix'
    become: yes
    become_user: "postgres"
    postgresql_table:
      name: users
      db: ordix
      columns:
      - id bigint primary key
      - kuerzel varchar(3)
      - vorname text
      - nachname text 

Beide im Beispiel genutzte Module postgresql_db und postgresql_table müssen als Systemuser postgres aufgerufen werden.

User und Berechtigungen anlegen

Zur User- und Rechteverwaltung wird das Modul postgresql_user genutzt. Hier können wie gewohnt eine Vielzahl an Parametern definiert werden. Das Codebeispiel zeigt, wie die beiden User ordix und readOnly angelegt werden. Beide User sollen die Rechte auf der Datenbank 'ordix' bekommen. Dies wird über die Option db festgelegt. Die beiden Optionen name und password definieren den Namen und das Passwort des Users.
Für die password-Option sollte der Wert in späteren Einsätzen durch den Ansible-Vault verschlüsselt werden, sodass dieser nicht im Klartext zu sehen ist. Weitere nützliche Optionen sind priv und expires - expires gibt an, wie lange der Account 'gültig' ist. Dort gibt es auch die Möglichkeit, mit dem Wert infinity einen zeitlich unbegrenzten Zugang zu gewähren. Mit dem Parameter priv lassen sich die Privilegien des Users festlegen.
Dies geschieht in folgendem Format:

DatabaseOption/Table:TableOption 
Als DatabaseOption stehen insgesamt fünf Optionen zur Verfügung:
  • CREATE, CONNECT, TEMPORARY, TEMP oder ALL
Für den Wert TableOption kann zwischen acht Werten gewählt werden:
  • SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER oder ALL
In diesem Beispiel darf der User readOnly sich mit der Datenbank verbinden (CONNECT) und auf
die Tabelle users (/users) Select-Abfragen stellen (:SELECT).
tasks:     
  - name: Create user ordix and grant all privs to db 'ordix'
    become: yes
    become_user: "postgres"
    postgresql_user:
      db: ordix
      name: ordix
      password: my_secret_pw
      priv: "ALL/users:ALL"
      expires: "infinity"
    
  - name: Create user system-user and grant SELECT privs to table users
    become: yes
    become_user: "postgres"
    postgresql_user:
      db: ordix
      name: readOnly
      password: readOnly
      priv: "CONNECT/users:SELECT"
      expires: "Dec 31 2020"	   

Fazit

Durch die von EDB bereitgestellten Rollen lässt sich eine PostgreSQL-Datenbank sehr einfach installieren und initialisieren. Aber auch ohne Anwendung dieser Rollen kann durch die integrierten Ansible-Module eine Datenbank aufgesetzt werden. Mit Hilfe der Community-Module lassen sich Datenbanken sehr übersichtlich und schnell verwalten. Hier zeigt sich der große Vorteil vor allem, wenn mehrere Datenbanken verwaltet werden. Aber auch bei einigen wenigen Datenbanken hilft Ansible, die Konfigurationsparameter dokumentiert und übersichtlich darzustellen. 

By accepting you will be accessing a service provided by a third-party external to https://blog.ordix.de/