Postgres Operator (CloudNativePG) · MemphisLab Docs
MemphisLab Docs
k3s Platform

Postgres Operator (CloudNativePG)

Como o CloudNativePG opera um Postgres por cliente via operator pattern

Operator pattern

Kubernetes só entende nativamente objetos genéricos (Pod, Service, Deployment). Ele não sabe o que é “um Postgres com replicação e backup automático” — não existe esse conceito embutido. Um operator ensina isso ao cluster em duas partes: uma CRD (Custom Resource Definition) que declara um tipo de objeto novo na API do cluster, e um controller que roda dentro do cluster e implementa o control loop (ver orchestration-fundamentals) daquele objeto — observa instâncias da CRD e cria/ajusta os objetos nativos (StatefulSet, Service, Secret, PVC) necessários para realizar o que foi declarado.

CloudNativePG é o operator de Postgres deste cluster. A CRD que ele expõe é Cluster (postgresql.cnpg.io/v1), e o controller dele é quem lê um Cluster e materializa um Postgres de verdade a partir disso.

O Cluster deste chart

# charts/app/templates/postgresql.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
spec:
  instances: {{ .Values.postgresql.instances }}
  storage:
    size: {{ .Values.postgresql.storage.size }}
  bootstrap:
    initdb:
      database: {{ .Values.db.database }}
      owner: {{ .Values.db.username }}
      secret:
        name: {{ include "app.dbSecretName" . }}
  backup:
    retentionPolicy: {{ .Values.postgresql.backup.retentionPolicy }}
    barmanObjectStore:
      destinationPath: {{ printf "s3://%s/%s" .Values.postgresql.backup.bucket (include "app.fullname" .) | quote }}
      wal:
        compression: gzip
      data:
        compression: gzip

Declarar isso não sobe um Postgres sozinho — é o controller do CloudNativePG que lê esse Cluster, cria o StatefulSet com o container postgres de verdade, o Service que os outros pods usam para conectar, e o Secret de credenciais (referenciando db.username, gerado a partir do SealedSecret — ver secrets-encryption). instances: 1 neste chart significa sem réplica de leitura — cada cliente roda uma única instância de Postgres, não um cluster de alta disponibilidade com failover automático. Isso é intencional para o tamanho de carga por cliente aqui, não uma limitação do CloudNativePG (que suporta múltiplas instâncias com failover).

Backup: streaming de WAL + base diária

barmanObjectStore é a integração do CloudNativePG com Barman, a ferramenta de backup/restore de Postgres que ele usa por baixo. Duas coisas acontecem em paralelo, não uma ou outra:

  • Streaming contínuo de WAL (Write-Ahead Log) — toda transação commitada gera entradas de WAL, e o CloudNativePG as envia para o MinIO (S3) continuamente, à medida que são geradas. Isso é o que permite restaurar para “agora” ou para qualquer ponto no tempo entre dois backups base, não só para o horário exato de um snapshot.
  • Backup base diário, agendado via a CRD ScheduledBackup (schedule: {{ .Values.postgresql.backup.schedule }}, 0 0 3 * * * por padrão — 03:00) — uma cópia completa e consistente do banco naquele momento, que serve de ponto de partida para uma restauração (aplicar WAL a partir dali é mais rápido que reconstruir tudo desde o início dos tempos).

Restaurar significa criar um Cluster novo com bootstrap.recovery apontando para o mesmo barmanObjectStore de origem — o controller do CloudNativePG reconstrói o banco a partir do backup base mais próximo e replay do WAL até o ponto pedido. Nunca testado neste cluster; ver a recomendação em topology para testar antes de depender.

helm.sh/resource-policy: keep na anotação do Cluster é o que impede o Helm de apagar o Postgres se o release for desinstalado — sem essa anotação, um helm uninstall acidental apagaria dados de cliente junto com o resto do release.