Remarque :

Déployer un cluster Postgres hautement disponible sur Oracle Cloud Infrastructure

Introduction

Ce tutoriel décrit la conception et l'implémentation de Postgres dans une configuration HA à l'aide de Patroni et d'autres composants. PostgreSQL ne dispose pas du basculement automatique intégré et du mécanisme automatique permettant d'ajouter le maître défaillant au cluster. Patroni est la nouvelle solution haute disponibilité (HA) d'âge pour PostgreSQL avec des fonctionnalités cloud natives et des options avancées pour le basculement/la permutation, ainsi que la configuration automatisée des processus d'initialisation et des répliques.

Patroni est un modèle qui vous permet de créer votre propre solution HA personnalisée à l'aide de Python et pour une accessibilité maximale, un magasin de configuration distribué comme etcd.

Voici quelques limitations avec la réplication Postgres native et sa solution avec Patroni :

Limites relatives à la réplication Postgres native Solutions basées sur Patroni
Le mécanisme de réplication par défaut ne prend pas en charge le basculement automatique. Patroni assure le basculement automatique.
L'utilisation d'outils externes pour le basculement peut nécessiter des efforts supplémentaires pour les maintenir opérationnels. Patroni se charge du basculement.
La surveillance des postes peut également être un défi. Patroni dispose d'un mécanisme intégré qui surveille le service Postgres.
L'ajout automatique du noeud défaillant au cluster nécessite des compétences de génération de scripts avancées. Patroni dispose d'une automatisation intégrée permettant de ramener un noeud défaillant dans le cluster.
Impossible de gérer les scénarios Split Brain. Patroni avec l'aide de l'ETCD sera en mesure d'élire un nouveau leader.

Les autres solutions PostgreSQL HA incluent :

Toutefois, l'utilisation de Patroni avec l'implémentation Postgres simplifie considérablement le cycle de vie global de gestion de cluster.

Objectif

Ce tutoriel répertorie une solution fiable hautes performances avec des alternatives potentielles pour les clients qui souhaitent migrer des bases de données Postgres (d'AWS ou d'autres fournisseurs cloud) vers OCI. Les principales exigences en matière de haute disponibilité et de migration des données en temps réel.

Architecture

L'architecture suivante se compose de 3 serveurs ETCD, 3 (Postgres + Patroni + Pgbackrest), du bucket Object Storage et de l'équilibreur de charge réseau.

Diagramme d'architecture

Recommandations

  1. Pour la haute disponibilité : utilisez 3 serveurs ETCD, 3 noeuds pour PostgreSQL et placez-les dans différents domaines de disponibilité.
  2. Pour un meilleur débit, créez des volumes de blocs distincts pour les fichiers de données, temporaires, noyaux et journaux.
  3. Définissez tous les paramètres personnalisés dans la section bootstrap patroni.yaml au moment de la création du cluster.

Configurer et installer les composants HA PostgreSQL

La configuration est divisée en deux parties :

Tâche 1 : provisionner l'infrastructure

  1. Créer des machines virtuelles de calcul :

    • 3 serveurs ETCD
    • 3 serveurs pour Postgres + Patroni (1 leader et 2 réplique)
  2. Créez un bucket Object Storage pour le stockage des sauvegardes.

  3. Créez un utilisateur de location OCI avec un accès READ/WRITE sur le bucket de banque d'objets ci-dessus.

Tâche 2 : installer et configurer le logiciel

  1. Configurer ETCD.

    • Installez ETCD sur 3 serveurs.

      cd /tmp
      wget https://github.com/etcd-io/etcd/releases/download/v3.5.2/etcd-v3.5.2-linux-amd64.tar.gz
      tar xzvf /tmp/etcd-v3.5.2-linux-amd64.tar.gz
      cd etcd-v3.5.2-linux-amd64
      cp etcdutl etcdctl etcd /usr/local/bin/
      mkdir -p /etc/etcd
      mkdir -p /var/lib/etcd
      groupadd -f -g 1501 etcd
      useradd -c "etcd user" -d /var/lib/etcd -s /bin/false -g etcd -u 1501 etcd
      chown -R etcd:etcd /var/lib/etcd
      
    • Configurez et démarrez ETCD sur les 3 serveurs.

      Voici les détails du serveur ETCD :

      | Hostname | IP Address | Availability Domain |
      | --- | --- | --- |    
      | pg-etcd-01 | 192.0.2.4  | AD1 |
      | pg-etcd-02 | 192.0.2.5  | AD2 |
      | pg-etcd-03 | 192.0.2.6  | AD3 |
      

      Remarque : modifiez les adresses IP conformément aux exigences.

      pg-etcd-01

      vi /etc/etcd/etcd.conf
      
      ###Node1
      ##192.0.2.4
      
      ETCD_NAME="pg-etcd-01"
      ETCD_INITIAL_CLUSTER="pg-etcd-01=http://192.0.2.4:2380"
      ETCD_LISTEN_CLIENT_URLS="http://192.0.2.4:2379,http://127.0.0.1:2379"
      ETCD_ADVERTISE_CLIENT_URLS="http://192.0.2.4:2379"
      ETCD_LISTEN_PEER_URLS="http://192.0.2.4:2380,http://127.0.0.1:7001"
      ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.0.2.4:2380"
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="new"
      ETCD_DATA_DIR="/var/lib/etcd"
      ETCD_ELECTION_TIMEOUT="5000"
      ETCD_HEARTBEAT_INTERVAL="1000"
      ETCD_ENABLE_V2="true"
      
      

      pg-etcd-02

      vi /etc/etcd/etcd.conf
      
      ##Node2
      ##192.0.2.5
      ETCD_NAME=" pg-etcd-02"
      ETCD_INITIAL_CLUSTER="pg-etcd-01=http://192.0.2.4:2380,pg-etcd-02=http://192.0.2.5:2380"
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="existing"
      ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.0.2.5:2380"
      ETCD_LISTEN_PEER_URLS="http://192.0.2.5:2380,http://127.0.0.1:7001"
      ETCD_LISTEN_CLIENT_URLS="http://192.0.2.5:2379,http://127.0.0.1:2379"
      ETCD_ADVERTISE_CLIENT_URLS="http://192.0.2.5:2379"
      ETCD_DATA_DIR="/var/lib/etcd"
      ETCD_ELECTION_TIMEOUT="5000"
      ETCD_HEARTBEAT_INTERVAL="1000"
      ETCD_ENABLE_V2="true"
      

      pg-etcd-03

      vi /etc/etcd/etcd.conf
      
      ##Node3
      ##192.0.2.6
      ETCD_NAME="pg-etcd-03"
      ETCD_INITIAL_CLUSTER="pg-etcd-01=http://192.0.2.4:2380,pg-etcd-02=http://192.0.2.5:2380,pg-etcd-03=http://192.0.2.6:2380"
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="existing"
      ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.0.2.6:2380"
      ETCD_LISTEN_PEER_URLS="http://192.0.2.6:2380,http://127.0.0.1:7001"
      ETCD_LISTEN_CLIENT_URLS="http://192.0.2.6:2379,http://127.0.0.1:2379"
      ETCD_ADVERTISE_CLIENT_URLS="http://192.0.2.6:2379"
      ETCD_DATA_DIR="/var/lib/etcd"
      ETCD_ELECTION_TIMEOUT="5000"
      ETCD_HEARTBEAT_INTERVAL="1000"
      ETCD_ENABLE_V2="true"
      
    • Ajoutez des membres à pg-etcd-01.

      etcdctl member add pg-etcd-02 --peer-urls=http://192.0.2.5:2380
      etcdctl member add pg-etcd-03 --peer-urls=http://192.0.2.6:2380
      
    • Exécutez la commande suivante pour afficher la liste des membres.

      etcdctl member list
      
    • Créez un service.

      vi /etc/systemd/system/etcd.service
      
      [Unit]
      Description=Etcd Server
      After=network.target
      After=network-online.target
      Wants=network-online.target
      
      [Service]
      Type=notify
      WorkingDirectory=/var/lib/etcd
      EnvironmentFile=-/etc/etcd/etcd.conf
      User=etcd
      # set GOMAXPROCS to number of processors
      ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/local/bin/etcd"
      Restart=on-failure
      LimitNOFILE=65536
      IOSchedulingClass=best-effort
      IOSchedulingPriority=0
      
      [Install]
      WantedBy=multi-user.target
      
      systemctl daemon-reload
      
      systemctl enable etcd
      
  2. Installez Postgres sur tous les noeuds. Exécutez le script suivant pour installer Postgres :

    • Script d'installation Postgres

      Remarque : pour la réplique, arrêtez postgresql et supprimez le répertoire de données car il sera copié à partir du leader une fois la configuration Patroni terminée.

      /opt/pgsql/bin/pg_ctl -D /opt/pgsql/data/$MAJORVERSION stop
      cd /opt/pgsql/data/
      rm *
      
  3. Installer les extensions : pg_squeeze et pgaudit.

    • Installer PGAUDIT

      cd /usr/local/src/postgresql-12.6/contrib/
      wget https://github.com/pgaudit/pgaudit/archive/refs/heads/REL_12_STABLE.zip
      unzip REL_12_STABLE.zip
      make install USE_PGXS=1 PG_CONFIG=/opt/pgsql/bin/pg_config
      
    • Installer PG_SQUEEZE

      cd /usr/local/src/postgresql-12.6/contrib/
      wget https://github.com/cybertec-postgresql/pg_squeeze/archive/refs/heads/master.zip
      unzip master.zip
      make install USE_PGXS=1 PG_CONFIG=/opt/pgsql/bin/pg_config
      
  4. Installez Patroni sur tous les noeuds.

    yum update –y
    yum -y install epel-release
    yum -y install python3
    yum install -y python3-devel
    yum install -y psutils
    yum install -y gcc
    yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    yum install python3-psycopg2
    pip3 install python-etcd
    pip3 install patroni
    
  5. Installez et configurez pgBackrest sur tous les noeuds.

    • Installer Pgbackrest

      yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
      sudo yum install pgbackrest -y
      
    • Configurer Pgbackrest sur tous les noeuds

      /etc/pgbackrest.conf
      [global]
      repo1-type=s3
      repo1-path=/backup
      repo1-s3-uri-style=path
      repo1-s3-region=us-ashburn-1
      repo1-s3-endpoint=https://xxxxx0011.compat.objectstorage.us-ashburn-1.oraclecloud.com
      repo1-s3-key=0000000a90d57eddexxxxxa3dc7c4f700000ed2e6
      repo1-s3-key-secret=1UhXj69xxxx1e6OyF+00000cccccyyyuuu=
      repo1-s3-bucket=pg_backup
      repo1-retention-full=10
      log-level-console=info
      log-level-file=debug
      log-path=/var/log/pgbackrest/
      
      [stanza-name]
      pg1-path=/opt/pgsql/data
      pg1-user=Postgres
      
    • Créer un fichier bootstrap sur tous les noeuds

      vi /etc/patroni/boot_pgbackrest.sh
      
      #!/ usr / bin /env bash
      while getopts ": -:" optchar ; do
              [[ "${ optchar }" == "-" ]] || continue
              case "${ OPTARG }" in
              datadir =* )
                      DATA_DIR =${ OPTARG #*=}
                      ;;
              scope =* )
                      SCOPE =${ OPTARG #*=}
                      ;;
              esac
      done
      /bin/pgbackrest --stanza=$SCOPE --link-all restore
      
  6. Configurez Patroni sur tous les noeuds.

    Nom d'hôte Adresse IP Domaine de disponibilité
    pg-db-01 192.0.2.1 AD1
    pg-db-02 192.0.2.2 AD2
    pg-db-03 192.0.2.3 AD3

    Remarque : modifiez les adresses IP conformément aux exigences.

    mkdir -p /etc/patroni
    mkdir -p /opt/pgsql/patroni
    chown postgres:postgres -R /opt/pgsql/patroni
    chmod 700 /opt/pgsql/patroni
    
    vi /etc/patroni/patroni.yml
    
    scope:pg-ha-cluster
    name:pg-db-01
    namespace:/opt/pgsql/patroni/
    ###
    restapi:
      listen: "192.0.2.1:8008"
      connect_address: "192.0.2.1:8008"
    ###ETCD Configuration
     etcd:
       hosts: "192.0.2.4:2379,192.0.2.5:2379, 192.0.2.6:2379"
     ###Bootstrap
     bootstrap:
       dcs:
         ttl: 120
         loop_wait: 10
         retry_timeout: 10
         maximum_lag_on_failover: 1048576
         postgresql:
           use_pg_rewind: true
           use_slots: true
         parameters:
           archive_command: "pgbackrest --stanza=<stanza-name> archive-push %p"
           archive_mode: on
           archive_timeout: 900s
           log_file_mode: "0640"
           log_filename: postgresql-%u.log
           log_rotation_age: 1d
           log_truncate_on_rotation: "on"
           logging_collector: "on"
           max_connections: 2000
           max_replication_slots: 10
           max_wal_senders: 10
           max_wal_size: 5GB
           max_worker_processes: 40
           min_wal_size: 1GB
           wal_level: "replica"
           password_encryption: scram-sha-256
           superuser_reserved_connections: 200
           create_replica_methods:
             - pgbackrest
           pgbackrest:
             command: "/usr/bin/pgbackrest --stanza=<stanza-name>  restore --delta --link-all"
             keep_data: True
             no_params: True
         recovery_conf:
           recovery_target_timeline: latest
           restore_command: '/usr/bin/pgbackrest --stanza=<stanza-name>  archive-get %f %P'
        method: pgbackrest
        pgbackrest:
          command: /etc/patroni/boot_pgbackrest.sh
          keep_existing_recovery_conf: False
          recovery_conf:
            recovery_target_timeline: latest
            restore_command: '/usr/bin/pgbackrest --stanza=<stanza-name>  archive-get %f %P'
       initdb:
         - encoding: UTF8
         - data-checksums
       pg_hba:
         - host replication replicator 127.0.0.1/32 md5
         - host replication replicator 192.0.2.1/32 md5
         - host replication replicator 192.0.2.2/32 md5
         - host replication replicator 192.0.2.3/32 md5
         - host all all x.x.x.0/0 md5
       users:
         admin:
           password: admin
           options:
             - createrole
             - createdb
     #####Local Postgresql Parameters
     postgresql:
     listen: "192.0.2.1:5432"
     connect_address: "192.0.2.1:5432"
     data_dir: /opt/pgsql/data
     pgpass: /opt/pgsql/patroni/pgpass
     authentication:
       replication:
         username: replicator
         password: password
       superuser:
         username: postgres
         password: password
     #    rewind:
     #      username: replicator
     #      password: password
     parameters:
       unix_socket_directories: "/var/run/postgresql, /tmp"
     ###Any Tags
     tags:
       nofailover: false
       noloadbalance: false
       clonefrom: false
       nosync: false
    

    Remarque : modifiez l'adresse IP de chaque noeud, respectivement.

    chmod 640 /etc/patroni/patroni.yml
    chown postgres:postgres -R /etc/patroni/patroni.yml
    
    • Créer un service Patroni sur tous les noeuds
    vi /etc/systemd/system/patroni.service
    
    [Unit]
    Description=Runners to orchestrate a high-availability PostgreSQL - patroni
    After=syslog.target network.target
    
    [Service]
    Type=simple
    
    User=postgres
    Group=postgres
    
    # Read in configuration file if it exists, otherwise proceed
    EnvironmentFile=-/etc/patroni_env.conf
    
    WorkingDirectory=~
    
    # Where to send early-startup messages from the server
    # This is normally controlled by the global default set by systemd
    # StandardOutput=syslog
    
    # Pre-commands to start watchdog device
    # Uncomment if watchdog is part of your patroni setup
    #ExecStartPre=-/usr/bin/sudo /sbin/modprobe softdog
    #ExecStartPre=-/usr/bin/sudo /bin/chown postgres /dev/watchdog
    
    # Start the patroni process
    ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
    
    # Send HUP to reload from patroni.yml
    ExecReload=/bin/kill -s HUP $MAINPID
    
    # Only kill the patroni process, not its children, so it will gracefully stop postgres
    KillMode=process
    
    # Give a reasonable amount of time for the server to start up/shut down
    TimeoutSec=60
    
    # Do not restart the service if it crashes, we want to manually inspect database on failure
    Restart=no
    
    [Install]
    WantedBy=multi-user.target
    
    sudo systemctl daemon-reload
    sudo systemctl enable patroni
    sudo systemctl start patroni
    sudo systemctl status patroni
    

    Remarque : sur les noeuds de réplique, configurez Patroni, mais ne démarrez pas les services.

    • Exécutez la commande suivante pour voir le statut du cluster Patroni sur le maître.

      patronictl -c /etc/patroni/patroni.yml list
      
      [root@pg-db-01 ~]# /usr/local/bin/patronictl -c /etc/patroni/patroni.yml list
      +--------------+-------------+---------+---------+----+-----------+
      | Member       | Host        | Role    | State   | TL | Lag in MB |
      + Cluster: pg-ha-cluster (7089354141421597068) --+----+-----------+
      | pg-db-01 | 192.0.2.1 | Leader  | running | 1 |           |
      +--------------+-------------+---------+---------+----+-----------+
      
  7. Créez Stanza et effectuez une sauvegarde complète.

    pgbackrest --stanza=<stanza-name> stanza-create
    pgbackrest  --type=full --stanza= pgha --process-max=10 backup
    pgbackrest info
    
  8. Démarrez Patroni sur les noeuds de réplique et commencez à effectuer un rattrapage automatique à partir du leader.

    sudo systemctl start patroni
    sudo systemctl status patroni
    
    • Exécutez la commande suivante pour afficher le statut du cluster :
    patronictl -c /etc/patroni/patroni.yml list
    

    Le statut doit être le suivant :

    [root@pg-db-01 ~]# /usr/local/bin/patronictl -c /etc/patroni/patroni.yml list
    +--------------+-------------+---------+---------+----+-----------+
    | Member       | Host        | Role    | State   | TL | Lag in MB |
    + Cluster: pg-ha-cluster (7089354141421597068) --+----+-----------+
    | pg-db-01 | 192.0.2.1 | Leader  | running | 2 |           |
    | pg-db-02 | 192.0.2.2  | Replica | running |2 |         0 |
    | pg-db-03 | 192.0.2.3  | Replica | running | 2 |         0 |
    +--------------+-------------+---------+---------+----+-----------+
    
  9. Enfin, configurez les travaux cron pour le nettoyage des journaux, les sauvegardes, etc.

    crontab –e
    #Pgbackrest FULL Backup on Sunday @1AM
    00 01 * * 0 postgres pgbackrest  --type=full --stanza=ash1-adeprod1-pgcluster --process-max=10 backup  &> /dev/null
    #Pgbackrest INC Backup on Mon-Sat @1AM
    00 01 * * 1-6 postgres pgbackrest  --type=diff --stanza=ash1-adeprod1-pgcluster --process-max=10 backup &> /dev/null
    #Delete PostgreSQL logs
    08 * * * find /opt/pgsql/log/* -mtime +15 -exec rm {} \; &>/dev/null
    

Commandes Patroni supplémentaires

Accusés de réception

Ressources de formation supplémentaires

Explorez d'autres exercices sur docs.oracle.com/learn ou accédez à davantage de contenu de formation gratuit sur le canal Oracle Learning YouTube. En outre, accédez à education.oracle.com/learning-explorer pour devenir explorateur Oracle Learning.

Pour consulter la documentation du produit, consultez Oracle Help Center.