NLEN
Direct technisch advies?
Home > Blog

How to run Postgres on Docker deel 3

Craig Healey 11-12-2019 10:17
Categorieën: BLOG, DBMS, Open Source, PostgreSQL, Technisch

In een vorige blogpost heb ik uitgelegd hoe je een PostgreSQL-database in een container kunt implementeren vanuit een standaard-image. In deze post bekijk ik de implementatie van een PostgreSQL-cluster. Nou ja, soort van…. PostgreSQL gebruikt de term cluster om te verwijzen naar ‘een verzameling databases beheerd door een enkele PostgreSQL-serverinstantie’. Ik gebruik het in meer algemene zin om te verwijzen naar High Availability.

Basis replicatie met behulp van een pre-built project

PostgreSQL beschikt sinds versie 9.0 over streamingreplicatie, waarbij de WAL-logs worden overgedragen tussen de masterdatabase en de read-only slave (meer informatie vind je hier). Het is vrij eenvoudig in te stellen, dus wat Docker toevoegt? Je kunt de docker-compose-opdracht en het bestand docker-compose.yml gebruiken om een aantal docker-containers te besturen. De master- en slave-database wordt dus als één eenheid behandeld.

Ik ga hiervoor Hamed Momeni’s Medium post, gebruiken maar met een aantal veranderingen.

Ten eerste moet er een dockernetwerk worden gecreëerd zodat onze containers met elkaar kunnen communiceren:

docker network create bridge-docker

Vervolgens halen wij de bestanden en directories uit BitBucket:

git clone https://bitbucket.org/CraigOptimaData/docker-pg-cluster.git

Verander directory naar de nieuw gecreëerde directory die docker-pg-cluster heet.

cd docker-pg-cluster

Daarna kun je gewoon de docker-compose up command gebruiken:

docker-compose up

Je moet nu even geduld hebben, want er moeten een aantal zaken gebeuren tijden het bouwen van de master- en slave-images. Je ziet een paar rode signalen die waarschuwen dat de pakketconfiguratie moet worden vertraagd. Dat is normaal. Uiteindelijk zijn de images klaar en worden ze daadwerkelijk uitgevoerd. Op dit punt moeten de logs van pg_master_1 en pg_slave_1 worden weergegeven terwijl ze worden geïnitialiseerd. Als alles goed is gegaan, zullen de logs niet meer omhoog scrollen.

Als dat het geval is zijn zowel master als slave operationeel. Maar omdat we de opdracht docker-compose zijn gestart zonder de flag, om fouten te kunnen zien, moeten we deze afsluiten en opnieuw opstarten op de achtergrond. Met Ctrl-C verlaten we de container waardoor deze ook stopt. Vervolgens voeren we de opdracht ‘docker compose up’ uit met de flag -d:

docker-compose up -d

The docker-compose files

Als je kijkt naar de docker-pg-cluster directory, dan zie je de volgende structuur:

Docker-pg-cluster:
docker-compose.yml

master:

Dockerfile
setup-master.sh

slave:

Dockerfile
setup-slave.sh

Het hoofdbestanddeel is het YAML-bestand dat is samengesteld uit de docker. Omdat het een YAML-bestand is, moet je voorzichtig zijn met de opmaak. Het is opgesplitst in drie secties, de declarations voor de master, de slave, en tot slot general settings. De data in het groen zijn de data die docker-compose gebruikt om de containers te maken. De containernamen zijn als volgt:

Docker-compose.yml

version: "3"
services:

 

De build line geeft de subdirectory.

Environmental variables worden in het paars weergegeven zoals poortnummers,

PostgreSQL-users en passwords.

 

Dan de naam van het netwerk (die wij bij het begin hebben gemaakt).
De restart line geeft docker het commando te herstarten als het stopt.

 

 

Ik heb beide containers hun eigen volumes met namen gegeven zodat het makkelijk te vinden is later.

 

 

 

 

 

 

 

Master Dockerfile

FROM postgres:11
COPY ./setup-master.sh /docker-entrypoint-initdb.d/setup-master.sh
RUN chmod 0666 /docker-entrypoint-initdb.d/setup-master.sh
RUN apt-get update && apt-get --assume-yes install iputils-ping && apt-get install --assume-yes ssh && apt-get install --assume-yes net-tools

The master\Dockerfile werkt redelijk simpel. Het gebruikt PostgreSQL 11 omdat er enkele wijzigingen in de replicatie zijn in PostgreSQL 12. Het kopieert setup-master.sh naar de container en stelt de juiste machtigingen in. Vervolgens installeert het verschillende pakketten die we willen gebruiken, zoals iputils, net-tools en ssh. Je zou het cluster kunnen maken met een Alpine-image, die een veel kleinere footprint zou hebben. Maar de laatste stap die ik wil doen, is het importeren in ControlControl en daarvoor heb ik ssh nodig dat niet gemakkelijk beschikbaar is in Alpine. Als je dit in een echte omgeving zou doen, wil je misschien een ssh-server opzetten, voor deze demonstratie voeg ik gewoon ssh rechtstreeks toe aan de containers.

Setup-master.sh

#!/bin/bash
echo "host replication all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER $PG_REP_USER REPLICATION LOGIN CONNECTION LIMIT 100 ENCRYPTED PASSWORD '$PG_REP_PASSWORD';
CREATE USER postgres;
EOSQL
cat >> ${PGDATA}/postgresql.conf <

wal_level = hot_standby
archive_mode = on
archive_command = 'cd .'
max_wal_senders = 8
wal_keep_segments = 8
hot_standby = on
EOF

Het bestand setup-master.sh voegt een line toe aan het bestand PostgreSQL pg_hba.conf om replicatie mogelijk te maken. Nogmaals, voor een echte installatie moet je misschien de beveiligingsimplicaties hiervan overwegen. Vervolgens voegt het een aantal postgres-gebruikers toe, een uit de omgevingsvariabelen in het bestand docker-compose.yml en de andere een standaard postgres-gebruiker. Vervolgens voegt het enkele regels toe aan het postgresql.conf-bestand dat dit als master instelt.

Slave Dockerfile

FROM postgres:11
RUN apt-get update && apt-get --assume-yes install iputils-ping && apt-get install --assume-yes ssh && apt-get install --assume-yes net-tools && apt-get install --assume-yes gosu
COPY ./setup-slave.sh /setup-slave.sh
RUN chmod +x /setup-slave.sh
ENTRYPOINT ["/setup-slave.sh"]
CMD ["gosu","postgres","postgres"]

De slave\Dockerfile is gelijk aan de master.

Setup-slave.sh

#!/bin/bash
if [ ! -s "$PGDATA/PG_VERSION" ]; then

echo "*:*:*:$PG_REP_USER:$PG_REP_PASSWORD" > ~/.pgpass
chmod 0600 ~/.pgpass
until ping -c 1 -W 1 pg_master_1
do

echo "Waiting for master to ping..."
sleep 1s

done
until pg_basebackup -h pg_master_1 -D ${PGDATA} -U ${PG_REP_USER} -vP -W
do

echo "Waiting for master to connect..."
sleep 1s

done
echo "host replication all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"
set -e
cat > ${PGDATA}/recovery.conf <

standby_mode = on
primary_conninfo = 'host=pg_master_1 port=5432 user=$PG_REP_USER password=$PG_REP_PASSWORD'
trigger_file = '/tmp/touch_me_to_promote_to_me_master'

EOF

chown postgres. ${PGDATA} -R
chmod 700 ${PGDATA} -R

fi

sed -i 's/wal_level = hot_standby/wal_level = replica/g' ${PGDATA}/postgresql.conf
exec "$@"

Bij het bestand setup-slave.sh zijn een aantal zaken op te merken. Het zet een loop op om te controleren of hij de master kan pingen en vervolgens een andere om gegevens te repliceren met behulp van de PG_REP_USER van docker-compose.yml. Controleer of de naam van de master overeenkomt met de naam die voor de service in het bestand docker-compose.yml zijn gebruikt. Dus, als je het PostgreSQL-cluster hebt laten draaien en de bestanden hebt bekeken die het heeft gemaakt, kunt je het in actie zien. Je kunt natuurlijk inloggen op PostgreSQL en SQL-opdrachten uitvoeren om het te laten werken. Maar deze blog gaat over Docker, niet over PostgreSQL, dus we gaan een pgAdmin4-container maken om ons cluster te bekijken.

docker run -p 80:80 --name pgadmin --restart always -e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' -e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' -d dpage/pgadmin4

Docker-containers hebben meestal geen GUI's, dus om pgAdmin4 te bekijken, open je deze in een browservenster. Het IP-adres is dat van de docker-machine en de poort is 80. Log in met het e-mailadres en wachtwoord dat je hebt gebruikt om de container te maken (in mijn geval user@domain.com en SuperSecret).

Voeg beide servers toe aan pgAdmin. Het enige verschil tussen hen zijn de namen die je geeft en de poortnummers. Het IP-adres zal opnieuw dat van je docker-machine zijn.

Connection:
Host name/address: docker-machine IP
Port: 5445 or 5446
Maintenance database: postgres
Username: optima
Password: 123456

Navigeer in de hoofddatabases naar pg_stat_replication (Databases -> postgres -> Catalogi -> PostgreSQL Catalog (pg_catalog) -> Views) en bekijk alle rijen. Je ziet een enkele rij met gegevens als deze correct wordt gerepliceerd. Je kunt ook tabellen en gegevens toevoegen aan de master en controleren of deze naar de slave worden gekopieerd.

ClusterControl

Hoewel we zeker een werkend databasecluster hebben, is dit niet zichtbaar. Dus voegen wij een container toe met ClusterControl van SeveralNines, die wordt geleverd met een proeflicentie van 30 dagen. Daarna ga je verder op de community-editie:

docker run -d --name clustercontrol --restart always --network bridge-docker -p 5000:80 severalnines/clustercontrol

Ook nu heb ik een flag toegevoegd om de container opnieuw te starten als deze stopt en om hem op hetzelfde netwerk te plaatsen als de andere containers. Open een ander browsertabblad op hetzelfde IP-adres als je docker-machine, met poort 5000 (e.g. 192.168.99.105:5000/clustercontrol). Je wordt gevraagd om een e-mailadres en wachtwoord op te geven om in te loggen en te registreren, maar deze hoeven niet geldig te zijn. Voordat we de servers aan ClusterControl kunnen toevoegen, moeten we ssh op de servers instellen.

Maak verbinding met de ClusterControl-container om het IP-adres te vinden en het rootwachtwoord in te stellen.

docker exec -it clustercontrol bash
passwd
ip addr show 

Nu kun je inloggen op beide servers

docker exec -it docker-pg-cluster_pg_master_1_1 bash
docker exec -it docker-pg-cluster_pg_slave_1_1 bash

Voor het inloggen als root gebruik je het volgende commando

sed -i 's|^#PermitRootLogin.*|PermitRootLogin yes|g' /etc/ssh/sshd_config

start dan ssh

service ssh start

Zet het root-wachtwoord

passwd

en vind het IP-adres van de servers

ifconfig 

Maak een ssh key op beide servers

mkdir -p $HOME/.ssh
chmod 0700 $HOME/.ssh
ssh-keygen -t rsa 

ssh-copy-id -i $HOME/.ssh/id_rsa.pub root@[ClusterControl IP address]
ssh root@[ClusterControl IP address] 

Op de ClusterControl container

ssh-copy-id [master IP address]
password
ssh [master IP address]
ssh-copy-id [slave IP address]
password
ssh [slave IP address] 

In ClusterControl, voeg het cluster toe:

Import
PostgreSQL
SSH User:root
Cluster Name:blog3a
Server port: 5432 NOTE, NOT THE CONTAINER’S PORT
User: optima
Password: 123456
Version:11
Basedir: /var/lib/postgresql/data
Add Nodes:IP address of the master and slave, pressing after each one
Import 

Heb even geduld terwijl de import job loopt.

Op de tab overview kun je gemakkelijk de replicatiestatus zien.

En daar hebben wij het: een 2-node PostgreSQL 11 databasecluster met pgAdmin4 en ClusterContol in vier containers. Het is leuk om wat te spelen met het starten en stoppen en om te zien hoe gemakkelijk het is om nieuwe clusters te maken. 

Meer weten?

Dit is zeker niet alles wat Docker te bieden heeft maar hopelijk is het genoeg om je enthousiast te maken om ermee te beginnen. Wil je meer weten of heb je hulp nodig bij het ontwerpen met en implementeren van Docker, Kubernetes, ClusterControl, PostgreSQL? Neem gerust eens vrijblijvend contact op! We denken graag met je mee.

Route naar effectief databasebeheer?

Wat is nu de route naar effectief databasebeheer? Wat zijn de valkuilen ? Om een aantal handvatten aan te reiken hebben we daar een whitepaper over geschreven.

Download whitepaper

Blog Postgres on Docker deel 1

Blog Postgres on Docker deel 2

 

terug naar blogoverzicht

Reageer