Alta Disponibilidade PostgreSQL com Patroni e HAProxy

Enfrentando o desafio de manter um banco de dados PostgreSQL resiliente no cenário em constante mudança das demandas digitais? Se o termo “Patroni” ressoa com suas aspirações tecnológicas, você está prestes a desbloquear uma solução que eleva o PostgreSQL a uma fortaleza de alta disponibilidade.

Certamente, um desafio o aguarda, mas não tema – você está embarcando em uma jornada transformadora para construir um cluster PostgreSQL inabalável. Vislumbre um futuro onde as interrupções do banco de dados são meros pequenos problemas, e sua configuração do PostgreSQL se destaca como o epítome da confiabilidade.

Prepare-se para fortalecer seu ambiente PostgreSQL em um bastião inabalável!

Pré-requisitos

Antes de avançar na implementação de alta disponibilidade para o PostgreSQL, certifique-se de ter o seguinte em vigor:

  • Cinco (ou mais) servidores Linux – Este tutorial utiliza servidores Debian 12, cada um com um usuário não root com privilégios de sudo/administrador da seguinte forma:
Hostname IP Address Used as
postgres01 192.168.5.20 PostgreSQL Server
postgres02 192.168.5.21 PostgreSQL Server
postgres03 192.168.5.22 PostgreSQL Server
etcd 192.168.5.15 Cluster Data Store
haproxy 192.168.5.16 Load Balancer

Instalando o Servidor PostgreSQL e o Patroni

Com todos os pré-requisitos atendidos, imagine este momento como a base para um ambiente de banco de dados robusto e seguro contra falhas. O objetivo é criar uma implantação de PostgreSQL de alta disponibilidade via PostgreSQL 15. Mas primeiro, você deve instalar os pacotes necessários (Servidor PostgreSQL e Patroni) em todos os seus servidores PostgreSQL.

Patroni é uma aplicação baseada em Python para criar implantações de PostgreSQL de alta disponibilidade em seus data centers, desde hardware dedicado até Kubernetes. Patroni está disponível no repositório oficial do PostgreSQL e suporta servidores PostgreSQL 9.5-16.

Para instalar o Servidor PostgreSQL e o Patroni, siga as seguintes etapas:

? NOTA: Execute as seguintes operações nos servidores PostgreSQL. Neste caso, postgres01, postgres02 e postgres03.

1. Abra um terminal e execute o comando curl abaixo, que não tem saída, mas adiciona a chave GPG para o repositório do PostgreSQL para /usr/share/keyrings/pgdg.gpg.

? Este tutorial utiliza uma conta de root para a execução de comandos para garantir a compatibilidade de demonstração. No entanto, lembre-se de que é altamente recomendável utilizar uma conta não-root com privilégios sudo. Com uma conta não-root, você deve prefixar seus comandos com sudo para uma segurança aprimorada e boas práticas.

curl -fsSL <https://www.postgresql.org/media/keys/ACCC4CF8.asc> | sudo gpg --dearmor -o /usr/share/keyrings/pgdg.gpg

2. Em seguida, execute o seguinte comando, que não fornece saída, mas adiciona o repositório do PostgreSQL à lista de fontes de pacotes no arquivo /etc/apt/sources.list.d/pgdg.list.

sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/pgdg.gpg] <https://apt.postgresql.org/pub/repos/apt> $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

3. Depois de adicionado, execute o seguinte comando apt update para atualizar o seu índice de pacotes e obter informações sobre pacotes mais recentes.

apt update
Adding PostgreSQL repository and updating package index

4. Uma vez atualizados, execute o seguinte comando para instalar os seguintes pacotes:

  • postgresql-15 – O sistema de gerenciamento de banco de dados PostgreSQL versão 15.
  • patroni – Uma solução de código aberto para alta disponibilidade no PostgreSQL, um modelo para clusters HA do PostgreSQL usando Python e etcd.
  • python3-etcd – Uma biblioteca cliente Python para interagir com etcd, um armazenamento de chave-valor distribuído. Esta biblioteca permite que aplicativos Python comuniquem-se e gerenciem clusters etcd.
  • python3-psycopg2 – Um adaptador PostgreSQL para Python 3, conectando aplicativos Python e bancos de dados PostgreSQL.
apt install postgresql-15 postgresql-server-dev-15 patroni python3-etcd python3-psycopg2

Insira Y para prosseguir com a instalação quando solicitado.

Installing packages including PostgreSQL 15 and Patroni

5. Com os pacotes instalados, execute cada comando abaixo, que não terá saída no terminal, mas realizará o seguinte:

  • Parar os serviços postgresql e patroni. No Debian/Ubuntu, os serviços postgresql e patroni são iniciados automaticamente após a instalação.
  • Crie um symlink para os arquivos binários do PostgreSQL no diretório /usr/sbin. Fazê-lo garante que o patroni possa executar os arquivos binários do PostgreSQL para criar e gerenciar o PostgreSQL.
systemctl stop postgresql patroni
ln -s /usr/lib/postgresql/15/bin/* /usr/sbin/

6. Por último, execute os seguintes comandos para verificar o caminho binário do patroni e do psql, e a --version instalada do patroni.

which patroni
which psql
patroni --version

Abaixo estão os caminhos para os arquivos binários do patroni (/usr/bin/patroni) e do psql (/usr/sbin/psql); a versão do Patroni instalada é 3.2.1.

Verifying binary paths for Patroni and psql

Configurando e Configurando o Servidor etcd

Agora que você tem o Servidor PostgreSQL e o Patroni instalados, você precisa de uma base que solidifique a coordenação entre seus servidores PostgreSQL para alta disponibilidade sem falhas. Você vai configurar e configurar o etcd, uma loja de dados chave-valor.

Esta loja de dados chave-valor é o arquiteto silencioso nos bastidores, garantindo que os dados relacionados à implantação do seu cluster PostgreSQL sejam armazenados com segurança e gerenciados de forma eficiente.

? NOTA: Certifique-se de instalar o etcd em um servidor separado. Neste exemplo, o etcd está instalado no servidor etcd.

Para instalar e configurar o etcd, siga estas etapas:

1. No seu servidor etcd, execute o comando abaixo para atualizar o índice do repositório e obter as informações do pacote mais recentes.

apt update
Updating the Debian repository on the etcd server

2. Em seguida, execute o comando abaixo para instalar o etcd no seu servidor.

apt install etcd-server
Installing etcd

3. Depois de instalar o etcd, abra a configuração padrão /etc/default/etcd usando o editor de sua preferência e insira a seguinte configuração.

Esta configuração configura um único cluster etcd, portanto, certifique-se de substituir o endereço IP 192.168.5.15 pelo seu endereço IP interno.

ETCD_LISTEN_PEER_URLS="<http://192.168.5.15:2380>"
ETCD_LISTEN_CLIENT_URLS="<http://localhost:2379>,<http://192.168.5.15:2379>"
ETCD_INITIAL_ADVERTISE_PEER_URLS="<http://192.168.5.15:2380>"
ETCD_INITIAL_CLUSTER="default=http://192.168.5.15:2380,"
ETCD_ADVERTISE_CLIENT_URLS="<http://192.168.5.15:2379>"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new" 

Salve as alterações e saia do editor.

Configuring an etcd single cluster mode

4. Agora, execute o comando systemctl abaixo para reiniciar o etcd e aplicar suas modificações.

Este comando não possui saída, mas você verificará as alterações na etapa seguinte.

systemctl restart etcd

5. Uma vez que o etcd reinicie, verifique se o serviço etcd está em execução e habilitado.

systemctl is-enabled etcd
systemctl status etcd

Se o serviço etcd estiver em execução, você verá uma saída active (running). Quando habilitado, você verá a saída enabled, o que também significa que o etcd será iniciado automaticamente durante a inicialização.

Checking the etcd service status

6. Por fim, execute o seguinte comando etcdctl abaixo para verificar a lista de servidores disponíveis no cluster etcd.

etcdctl member list

Neste caso, o etcd é executado como um cluster de um único nó em um endereço IP local http://192.168.5.15:2379/.

Checking cluster members on etcd

Inicialização do Cluster PostgreSQL via Patroni

Com o servidor etcd agora firmemente estabelecido, você está no limiar da próxima fase crucial. Ao iniciar o processo de inicialização usando o Patroni, você eleva a configuração do seu PostgreSQL para um cluster robusto e tolerante a falhas.

? Asegure-se de fazer backup do seu banco de dados primeiro se estiver implantando um cluster PostgreSQL em um servidor PostgreSQL existente.

Para inicializar seu cluster PostgreSQL via Patroni, execute o seguinte em cada servidor PostgreSQL:

1. Abra a configuração padrão do Patroni (/etc/patroni/config.yml) no seu editor de texto e adicione a seguinte configuração.

Certifique-se de substituir o valor da opção name pelo nome do host do seu servidor PostgreSQL (ou seja, postgres01), mas não feche o editor ainda.

Essa configuração estabelece seu cluster PostgreSQL com o nome postgres.

# Escopo do PostgreSQL
scope: postgres
# Namespace para o banco de dados PostgreSQL
namespace: /db/
# Nome da instância PostgreSQL
name: postgres01

2. Em seguida, adicione a configuração abaixo para configurar a API REST do Patroni para rodar em 192.168.5.20:8008.

Você deve garantir que cada servidor PostgreSQL dentro do cluster possa se conectar via API. Portanto, altere o endereço IP 192.168.5.20 pelo endereço IP respectivo de cada servidor PostgreSQL.

# Configuração da API REST do Patroni
restapi:
    # O endereço IP e a porta nos quais a API REST deve escutar
    listen: 192.168.5.20:8008

    # O endereço IP e a porta aos quais os clientes devem se conectar
    connect_address: 192.168.5.20:8008

3. Adicione a configuração abaixo para habilitar a integração com o etcd. Neste caso, o servidor etcd está em execução no endereço IP 192.168.5.15.

# Configuração do Etcd do Patroni
etcd3:
    # O endereço do host e a porta do servidor Etcd
    host: 192.168.5.15:2379

4. Agora, adicione a configuração abaixo para inicializar o servidor PostgreSQL via initdb.

Esta configuração define as regras e configurações padrão para autenticação de cliente (pg_hba.conf) e um novo usuário admin com a senha admin.

Assegure-se de inserir os endereços IP do cluster PostgreSQL na seção pg_hba e alterar a senha padrão admin na seção usuários.

# Configuração de inicialização do Patroni
bootstrap:
    # Parâmetros de configuração para armazenamento de configuração distribuída (DCS)
    dcs:
        ttl: 30
        loop_wait: 10
        retry_timeout: 10
        maximum_lag_on_failover: 1048576
        postgresql:
            # Utilizar pg_rewind durante a inicialização
            use_pg_rewind: true

    # Configuração do initdb
    initdb:
        - auth: scram-sha-256
        - encoding: UTF8
        - data-checksums

    # Entradas pg_hba.conf para replicação e acesso geral
    pg_hba:
        - host replication replicator 127.0.0.1/32 scram-sha-256
        - host replication replicator 192.168.5.20/0 scram-sha-256
        - host replication replicator 192.168.5.21/0 scram-sha-256
        - host replication replicator 192.168.5.22/0 scram-sha-256
        - host all all 0.0.0.0/0 scram-sha-256

		# Adicionando usuário padrão admin com senha admin
		users:
        admin:
            password: admin
            options:
                - createrole
                - createdb

5. Após configurar como o PostgreSQL é inicializado, insira a seguinte configuração para definir como o PostgreSQL é executado em cada servidor.

Quanto ao servidor postgres01, o PostgreSQL será executado no endereço IP 192.168.5.20 com o diretório de dados /var/lib/patroni.

Além disso, esta configuração cria um novo usuário chamado replicator para operação de replicação, e o usuário postgres como superusuário/administrador com a senha (senhasecreta).

Assegure-se de alterar o endereço IP e a senha padrão (senhasecreta).

# Configuração do Patroni para o PostgreSQL
postgresql:
    # Endereço e porta do servidor PostgreSQL
    listen: 192.168.5.20:5432
    # Endereço de conexão para clientes PostgreSQL
    connect_address: 192.168.5.20:5432
    # Diretório de dados para o PostgreSQL
    data_dir: /var/lib/patroni
    # Caminho para o arquivo pgpass
    pgpass: /tmp/pgpass

    # Configuração de autenticação
    authentication:
        # Replicação de credenciais de usuário
        replication:
            username: replicator
            password: rep-pass
        # Credenciais de superusuário
        superuser:
            username: postgres
            password: secretpassword

    # Parâmetros adicionais do PostgreSQL
    parameters:
        # Diretório para o soquete Unix
        unix_socket_directories: '.'
        # Método de criptografia de senha
        password_encryption: 'scram-sha-256'

6. Insira a seguinte configuração para definir tags para o seu servidor PostgreSQL, determinando seu comportamento no cluster, salve as alterações e feche o arquivo.

# Configuração de Tags do Patroni
tags:
    # Impede que um nó seja promovido em caso de falha
    nofailover: false
    # Impede que o balanceador de carga considere este nó
    noloadbalance: false
    # Impede a criação de uma réplica por clonagem
    clonefrom: false
    # Impede a aplicação de replicação síncrona
    nosync: false

7. Com as configurações salvas, execute os comandos abaixo para preparar coletivamente o diretório de dados do Patroni, garantindo que esteja apropriadamente de propriedade e seguro para uso pelo PostgreSQL.

Esses comandos não geram saída, mas esta etapa é crucial na configuração de um cluster de banco de dados PostgreSQL com o Patroni para alta disponibilidade.

# Crie o diretório para os dados do Patroni
mkdir -p /var/lib/patroni

# Defina a propriedade do diretório de dados do Patroni para o usuário do PostgreSQL
chown -R postgres:postgres /var/lib/patroni

# Configure as permissões no diretório de dados do Patroni para segurança
chmod 700 /var/lib/patroni

8. Em seguida, execute os comandos systemctl abaixo para iniciar e verificar o serviço patroni.

systemctl start patroni
systemctl status patroni

No servidor postgres01, o servidor PostgreSQL é iniciado, e o cluster é inicializado. Além disso, o servidor postgres01 é selecionado como líder do cluster.

Checking the Patroni service and verifying PostgreSQL cluster initialization

No servidor postgres02, o servidor PostgreSQL é iniciado via Patroni e se junta ao cluster PostgreSQL via REST API.

Se tudo correr bem, você verá a seguinte mensagem:

Checking the Patroni service on the postgres02 server

No servidor postgres03, a saída é semelhante à do servidor postgres02.

Checking the Patroni service on the postgres03 server

9. Com o seu cluster PostgreSQL inicializado, execute o seguinte comando patronictl para exibir uma lista de instâncias PostgreSQL gerenciadas pelo Patroni.

patronictl -c /etc/patroni/config.yml list

No seguinte resultado, você pode ver o seu cluster PostgreSQL (postgres) em execução.

Observe que o seu cluster está em execução com três membros: postgres01 como Líder, postgres02, e postgres03 como Replica com modo/estado streaming.

Checking the list of servers in the PostgreSQL Cluster

10. Por último, execute o comando systemctl abaixo para desabilitar o início automático do serviço postgresql durante o boot do sistema.

Este comando não tem saída se for bem-sucedido, mas é crucial, pois o Patroni controla o novo servidor PostgreSQL.

sudo systemctl disable --now postgresql

Instalando e Configurando o HAProxy como um Balanceador de Carga

Com o seu cluster PostgreSQL implantado, como você pode torná-lo acessível a partir de clientes e habilitar a failover quando ocorrer um problema? A solução é o HAProxy como um balanceador de carga antes do seu cluster PostgreSQL.

O HAProxy é o seu elemento central que permite que o seu cluster PostgreSQL lide com cargas de trabalho variáveis, distribua solicitações de forma inteligente e mantenha alta disponibilidade.

? NOTA: Instale o HAProxy em um servidor separado. Neste caso, o servidor HAProxy é instalado no servidor haproxy com o endereço IP 192.168.5.16.

Para instalar e configurar o HAProxy como um balanceador de carga para o cluster PostgreSQL, siga estes passos:

1. Abra o arquivo /etc/hosts usando o seu editor de texto preferido, insira os endereços IP e os nomes dos servidores PostgreSQL, salve as alterações e feche o arquivo.

192.168.5.20    postgres01
192.168.5.21    postgres02
192.168.5.22    postgres03

2. Em seguida, execute o comando abaixo para atualizar o seu índice de pacotes.

apt update
Updating the repository on the HAProxy server

3. Uma vez atualizado, execute o comando abaixo para instalar o pacote haproxy no seu sistema.

apt install haproxy
Installing HAProxy via APT

4. Agora, execute o seguinte comando para fazer backup da configuração padrão do HARPOXY para /etc/haproxy/haproxy.cfg.orig.

Este comando não gera saída, mas é uma medida de precaução antes de fazer qualquer modificação.

mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.orig

5. Em seguida, crie um novo arquivo chamado /etc/haproxy/haproxy.cfg usando o seu editor preferido e insira a seguinte configuração. Certifique-se de substituir cada endereço IP do servidor PostgreSQL pelo seu, salve o arquivo e feche o editor.

Esta configuração do HAProxy configura o HAProxy como um balanceador de carga para o seu cluster PostgreSQL com dois proxies, da seguinte forma:

  • stats – Este bloco é executado na porta 8080 e monitora o desempenho do servidor HAProxy e dos backends.
  • postgres – Este bloco é a configuração do balanceador de carga para o cluster PostgreSQL.
# Configurações globais
global
    # Número máximo de conexões globais
    maxconn 100      
    # Configurações de registro      
    log 127.0.0.1 local2

# Configurações padrão
defaults
    # Configuração de registro global
    log global
    # Definindo o modo TCP
    mode tcp
    # Número de tentativas
    retries 2
    # Tempo limite do cliente
    timeout client 30m
    # Tempo limite de conexão
    timeout connect 4s
    # Tempo limite do servidor
    timeout server 30m
    # Tempo limite de verificação
    timeout check 5s

# Configuração de estatísticas
listen stats
    # Definindo o modo HTTP
    mode http
    # Vinculando à porta 8080
    bind *:8080
    # Habilitando estatísticas
    stats enable
    # URI das estatísticas
    stats uri /

# Configuração do PostgreSQL
listen postgres
    # Vinculando à porta 5432
    bind *:5432
    # Habilitando verificação HTTP
    option httpchk
    # Esperando o status 200
    http-check expect status 200
    # Configurações do servidor
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    # Definindo os servidores PostgreSQL
    server postgres01 192.168.5.20:5432 maxconn 100 check port 8008
    server postgres02 192.168.5.21:5432 maxconn 100 check port 8008
    server postgres03 192.168.5.22:5432 maxconn 100 check port 8008

6. Com o HAProxy configurado, execute os comandos systemctl abaixo para reiniciar e verificar (status) o serviço haproxy.

systemctl restart haproxy
systemctl status haproxy
Checking the HAProxy service status

7. Por fim, abra seu navegador da web preferido e visite o endereço IP do HAProxy com a porta 8080 (por exemplo, http://192.168.5.16:8080/). Na saída abaixo, você pode ver o seguinte:

Na saída abaixo, você pode ver o seguinte:

  • O proxy stats para monitoramento do status do HAProxy.
  • O proxy postgres é o balanceador de carga para o cluster do PostgreSQL.
    Observe que os servidores postgres02 e postgres03 estão marcados como inativos porque ambos estão em modo streaming.
Checking HAProxy performance and information

Testando a Falha na Recuperação do Cluster do PostgreSQL

Saindo da configuração do HAProxy como seu balanceador de carga confiável, agora é hora de testar o cluster do PostgreSQL. Este passo crucial revelará a resistência da sua configuração de alta disponibilidade. Você deve garantir que o cluster do PostgreSQL permaneça robusto e responsivo mesmo diante de possíveis falhas.

Para testar a falha na recuperação do seu cluster do PostgreSQL, você se conectará ao cluster a partir da sua máquina cliente e verificará as operações de recuperação com as seguintes etapas:

1. Faça login na sua máquina cliente, abra um terminal e execute o comando psql abaixo para se conectar ao PostgreSQL via balanceador de carga HAProxy.

psql -h 192.168.5.16 -p 5432 -U postgres

Insira sua senha do PostgreSQL quando solicitado. Você pode encontrar as informações de senha necessárias no arquivo /etc/patroni/config.yml.

Connecting to PostgreSQL cluster via HAProxy load balancer

2. Uma vez conectado, execute a seguinte consulta para descobrir a qual servidor PostgreSQL você está conectado e encerre a sessão atual do PostgreSQL usando o comando quit.

SELECT inet_server_addr() AS hostname;
quit

Se a instalação do PostgreSQL for bem-sucedida, você estará conectado ao servidor postgres01.

Checking the IP address of the PostgreSQL server

3. Agora, mude para o servidor postgres01, execute os seguintes comandos para parar o serviço patroni e listar o status dos clusters do PostgreSQL usando o comando list.

Esta etapa permite que você teste a falha na recuperação do PostgreSQL.

systemctl stop patroni
patronictl -c /etc/patroni/config.yml list

Você poderá ver que o estado do servidor postgres01 foi alterado para parado e o novo líder do cluster foi delegado para o servidor postgres03.

Stopping the Patroni service to test the failover

4. Volte para as estatísticas de monitoramento do HAProxy e você verá que o servidor postgres01 está INATIVO, enquanto o postgres03 agora está ATIVOP.

Verifying the failover works in the HAProxy monitoring stats report

Alternativamente, execute o seguinte comando patronictl para verificar o status do cluster PostgreSQL.

patronictl -c /etc/patroni/config.yml list

Como você pode ver abaixo, o servidor postgres01 não está mais no cluster.

Checking the PostgreSQL Cluster members via patronictl

5. Volte para a máquina cliente e execute o seguinte comando psql para se conectar ao servidor PostgreSQL via HAProxy.

psql -h 192.168.5.16 -p 5432 -U postgres
Connecting to the PostgreSQL server via HAProxy

6. Uma vez conectado, execute a seguinte consulta para verificar o servidor PostgreSQL atual ao qual você está conectado.

SELECT inet_server_addr() AS hostname;
quit

Se a falha foi bem-sucedida, você estará conectado a um dos servidores em execução, que neste caso é o postgres03.

Checking the PostgreSQL server IP address

Conclusão

Embarcando nesta jornada, você se imergiu nas complexidades de garantir alta disponibilidade para seu banco de dados PostgreSQL, empregando a poderosa combinação de Patroni e HAProxy. Navegando sem problemas pelas etapas de configuração do PostgreSQL e Patroni, você lidou habilmente com os detalhes de configurar o servidor etcd.

Suas habilidades de orquestração vieram à tona enquanto você construía um cluster PostgreSQL resiliente com Patroni e ajustava a arte do balanceamento de carga usando o HAProxy. A culminação desta aventura de alto risco foi o teste meticuloso das capacidades de failover do seu cluster PostgreSQL.

Considere expandir sua expertise enquanto reflete sobre suas realizações na criação de um ambiente PostgreSQL robusto e tolerante a falhas. Que tal explorar a implementação do Patroni com Kubernetes para um ambiente mais dinâmico? Ou mergulhar nas complexidades de configurar Alta Disponibilidade do PostgreSQL em múltiplos data centers?

Source:
https://adamtheautomator.com/patroni/