Implemente o PostgreSQL no GKE através do CloudNativePG

O guia mostra como implementar clusters PostgreSQL no Google Kubernetes Engine (GKE) através do operador CloudNativePG.

O PostgreSQL é uma base de dados relacional de objetos de código aberto com várias décadas de desenvolvimento ativo, o que garante um desempenho estável do cliente. Oferece uma variedade de funcionalidades, incluindo replicação, recuperação num determinado momento, funcionalidades de segurança e extensibilidade. O PostgreSQL é compatível com os principais sistemas operativos e cumpre totalmente as normas ACID (atomicidade, consistência, isolamento e durabilidade).

Este guia destina-se a administradores de plataformas, arquitetos de nuvem e profissionais de operações interessados na implementação de clusters do Postgres no GKE. A execução do Postgres no GKE em vez de usar o Cloud SQL pode dar mais flexibilidade e controlo de configuração aos administradores de bases de dados experientes.

Vantagens

O CloudNativePG é um operador de código aberto desenvolvido pela EDB ao abrigo de uma licença Apache 2. Oferece as seguintes funcionalidades à implementação do PostgreSQL:

  • Uma forma declarativa e nativa do Kubernetes de gerir e configurar clusters do PostgreSQL
  • Gestão de cópias de segurança através de momentâneos de volumes ou Cloud Storage
  • Ligação TLS encriptada em trânsito, capacidade de usar a sua própria autoridade de certificação e integração com o Gestor de certificados para emissão e rotação automáticas de certificados TLS
  • Atualizações graduais para lançamentos secundários do PostgreSQL
  • Utilização do servidor da API Kubernetes para manter o estado de um cluster PostgreSQL e failovers para alta disponibilidade sem necessidade de ferramentas adicionais
  • Uma configuração do exportador do Prometheus incorporada através de métricas definidas pelo utilizador escritas em SQL

Configure o seu ambiente

Para configurar o seu ambiente, siga estes passos:

  1. Defina variáveis de ambiente:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    

    Substitua PROJECT_ID pelo seu Google Cloud ID do projeto.

  2. Clone o repositório do GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. Mude para o diretório de trabalho:

    cd kubernetes-engine-samples/databases/postgresql-cloudnativepg
    

Crie a infraestrutura do cluster

Nesta secção, executa um script do Terraform para criar um cluster do GKE privado, de alta disponibilidade e regional.

Pode instalar o operador através de um cluster Standard ou Autopilot.

Standard

O diagrama seguinte mostra um cluster GKE padrão regional privado implementado em três zonas diferentes:

Para implementar esta infraestrutura, execute os seguintes comandos:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply \
-var project_id=${PROJECT_ID}   \
-var region=${REGION}  \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

Quando lhe for pedido, escreva yes. Este comando pode demorar vários minutos a ser concluído e o cluster a apresentar o estado pronto.

O Terraform cria os seguintes recursos:

  • Uma rede VPC e uma sub-rede privada para os nós do Kubernetes
  • Um router para aceder à Internet através de NAT
  • Um cluster do GKE privado na região de us-central1
  • Um conjunto de nós com a escala automática ativada (um a dois nós por zona, um nó por zona no mínimo)

O resultado é semelhante ao seguinte:

...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...

Piloto automático

O diagrama seguinte mostra um cluster do GKE Autopilot regional privado:

Para implementar a infraestrutura, execute os seguintes comandos:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

Quando lhe for pedido, escreva yes. Este comando pode demorar vários minutos a ser concluído e o cluster a apresentar o estado pronto.

O Terraform cria os seguintes recursos:

  • Uma rede VPC e uma sub-rede privada para os nós do Kubernetes
  • Um router para aceder à Internet através de NAT
  • Um cluster do GKE privado na região de us-central1
  • Um ServiceAccount com autorização de registo e monitorização
  • Google Cloud Managed Service for Prometheus para monitorização de clusters

O resultado é semelhante ao seguinte:

...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...

Estabeleça ligação ao cluster

Configure o kubectl para comunicar com o cluster:

gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}

Implemente o operador CloudNativePG

Implemente o CloudNativePG no seu cluster do Kubernetes através de um gráfico do Helm:

  1. Adicione o repositório do gráfico Helm do operador CloudNativePG:

    helm repo add cnpg https://cloudnative-pg.github.io/charts
    
  2. Implemente o operador CloudNativePG através da ferramenta de linha de comandos Helm:

    helm upgrade --install cnpg \
        --namespace cnpg-system \
        --create-namespace \
        cnpg/cloudnative-pg
    

    O resultado é semelhante ao seguinte:

    Release "cnpg" does not exist. Installing it now.
    NAME: cnpg
    LAST DEPLOYED: Fri Oct 13 13:52:36 2023
    NAMESPACE: cnpg-system
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    ...
    

Implemente o Postgres

O manifesto seguinte descreve um cluster do PostgreSQL conforme definido pelo recurso personalizado do operador CloudNativePG:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: gke-pg-cluster
spec:
  description: "Standard GKE PostgreSQL cluster"
  imageName: ghcr.io/cloudnative-pg/postgresql:16.2
  enableSuperuserAccess: true
  instances: 3
  startDelay: 300
  primaryUpdateStrategy: unsupervised
  postgresql:
    pg_hba:
      - host all all 10.48.0.0/20 md5
  bootstrap:
    initdb:
      database: app
  storage:
    storageClass: premium-rwo
    size: 2Gi
  resources:
    requests:
      memory: "1Gi"
      cpu: "1000m"
    limits:
      memory: "1Gi"
      cpu: "1000m"
  affinity:
    enablePodAntiAffinity: true
    tolerations:
    - key: cnpg.io/cluster
      effect: NoSchedule
      value: gke-pg-cluster
      operator: Equal
    additionalPodAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app.component
              operator: In
              values:
              - "pg-cluster"
          topologyKey: topology.kubernetes.io/zone
  monitoring:
    enablePodMonitor: true

Este manifesto tem os seguintes campos:

  • spec.instances: o número de agrupamentos
  • spec.primaryUpdateStrategy: a estratégia de atualização contínua:
    • Unsupervised: atualiza autonomamente o nó do cluster principal após os nós de réplica
    • Supervised: é necessária uma comutação manual para o nó do cluster principal
  • spec.postgresql: substituições de parâmetros de ficheiros postgres.conf, como regras pg-hba, LDAP e requisitos para o cumprimento das réplicas de sincronização.
  • spec.storage: definições relacionadas com o armazenamento, como a classe de armazenamento, o tamanho do volume e as definições do registo antecipado.
  • spec.bootstrap: parâmetros da base de dados inicial criada no cluster, credenciais do utilizador e opções de restauro da base de dados
  • spec.resources: pedidos e limites para agrupamentos de pods
  • spec.affinity: regras de afinidade e anti-afinidade das cargas de trabalho do cluster

Crie um cluster Postgres básico

  1. Crie um espaço de nomes:

    kubectl create ns pg-ns
    
  2. Crie o cluster PostgreSQL com o recurso personalizado:

    kubectl apply -n pg-ns -f manifests/01-basic-cluster/postgreSQL_cluster.yaml
    

    Este comando pode demorar alguns minutos a ser concluído.

  3. Verifique o estado do cluster:

    kubectl get cluster -n pg-ns --watch
    

    Aguarde até que o resultado apresente o estado Cluster in healthy state antes de avançar para o passo seguinte.

    NAME             AGE     INSTANCES   READY   STATUS                     PRIMARY
    gke-pg-cluster   2m53s   3           3       Cluster in healthy state   gke-pg-cluster-1
    

Inspecione os recursos

Confirme que o GKE criou os recursos para o cluster:

kubectl get cluster,pod,svc,pvc,pdb,secret,cm -n pg-ns

O resultado é semelhante ao seguinte:

NAME                                        AGE   INSTANCES   READY   STATUS                     PRIMARY
cluster.postgresql.cnpg.io/gke-pg-cluster   32m   3           3       Cluster in healthy state   gke-pg-cluster-1

NAME                   READY   STATUS    RESTARTS   AGE
pod/gke-pg-cluster-1   1/1     Running   0          31m
pod/gke-pg-cluster-2   1/1     Running   0          30m
pod/gke-pg-cluster-3   1/1     Running   0          29m

NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/gke-pg-cluster-r    ClusterIP   10.52.11.24   <none>        5432/TCP   32m
service/gke-pg-cluster-ro   ClusterIP   10.52.9.233   <none>        5432/TCP   32m
service/gke-pg-cluster-rw   ClusterIP   10.52.1.135   <none>        5432/TCP   32m

NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/gke-pg-cluster-1   Bound    pvc-bbdd1cdd-bdd9-4e7c-8f8c-1a14a87e5329   2Gi        RWO            standard       32m
persistentvolumeclaim/gke-pg-cluster-2   Bound    pvc-e7a8b4df-6a3e-43ce-beb0-b54ec1d24011   2Gi        RWO            standard       31m
persistentvolumeclaim/gke-pg-cluster-3   Bound    pvc-dac7f931-6ac5-425f-ac61-0cfc55aae72f   2Gi        RWO            standard       30m

NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
poddisruptionbudget.policy/gke-pg-cluster           1               N/A               1                     32m
poddisruptionbudget.policy/gke-pg-cluster-primary   1               N/A               0                     32m

NAME                                TYPE                       DATA   AGE
secret/gke-pg-cluster-app           kubernetes.io/basic-auth   3      32m
secret/gke-pg-cluster-ca            Opaque                     2      32m
secret/gke-pg-cluster-replication   kubernetes.io/tls          2      32m
secret/gke-pg-cluster-server        kubernetes.io/tls          2      32m
secret/gke-pg-cluster-superuser     kubernetes.io/basic-auth   3      32m

NAME                                DATA   AGE
configmap/cnpg-default-monitoring   1      32m
configmap/kube-root-ca.crt          1      135m

O operador cria os seguintes recursos:

  • Um recurso personalizado de cluster que representa o cluster PostgreSQL que é controlado pelo operador
  • Recursos PersistentVolumeClaim com volumes persistentes correspondentes
  • Informações secretas com credenciais de utilizador para aceder à base de dados e à replicação entre nós do Postgres.
  • Três serviços de pontos finais de base de dados: <name>-rw, <name>-ro e <name>-r para estabelecer ligação ao cluster. Para mais informações, consulte a arquitetura do PostgreSQL.

Autentique-se no Postgres

Pode estabelecer ligação à base de dados PostgreSQL e verificar o acesso através de diferentes pontos finais de serviço criados pelo operador. Para o fazer, usa um Pod adicional com um cliente PostgreSQL e credenciais de utilizador da aplicação sincronizadas montadas como variáveis de ambiente.

  1. Execute o pod cliente para interagir com o cluster do Postgres:

    kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
    
  2. Execute um comando exec no pod pg-client e inicie sessão no serviço gke-pg-cluster-rw:

    kubectl wait --for=condition=Ready -n pg-ns pod/pg-client --timeout=300s
    kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
    
  3. Inicie sessão na base de dados através do serviço gke-pg-cluster-rw para estabelecer uma ligação com privilégios de leitura/escrita:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app
    

    O terminal começa com o nome da base de dados:

    app=>
    
  4. Criar uma tabela:

    CREATE TABLE travel_agency_clients (
    client VARCHAR ( 50 ) UNIQUE NOT NULL,
    address VARCHAR ( 50 ) UNIQUE NOT NULL,
    phone VARCHAR ( 50 ) UNIQUE NOT NULL);
    
  5. Inserir dados na tabela:

    INSERT INTO travel_agency_clients(client, address, phone)
    VALUES ('Tom', 'Warsaw', '+55555')
    RETURNING *;
    
  6. Veja os dados que criou:

    SELECT * FROM travel_agency_clients ;
    

    O resultado é semelhante ao seguinte:

    client | address |  phone
    --------+---------+---------
    Tom    | Warsaw  | +55555
    (1 row)
    
  7. Terminar sessão da sessão de base de dados atual:

    exit
    
  8. Inicie sessão na base de dados através do gke-pg-cluster-ro serviço para validar o acesso só de leitura. Este serviço permite consultar dados, mas restringe todas as operações de escrita:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
    
  9. Tentar inserir novos dados:

    INSERT INTO travel_agency_clients(client, address, phone)
    VALUES ('John', 'Paris', '+55555')
    RETURNING *;
    

    O resultado é semelhante ao seguinte:

    ERROR:  cannot execute INSERT in a read-only transaction
    
  10. Tentativa de leitura de dados:

    SELECT * FROM travel_agency_clients ;
    

    O resultado é semelhante ao seguinte:

    client | address |  phone
    --------+---------+---------
    Tom    | Warsaw  | +55555
    (1 row)
    
  11. Terminar sessão da sessão de base de dados atual:

    exit
    
  12. Saia da shell do Pod:

    exit
    

Compreenda como o Prometheus recolhe métricas para o seu cluster do Postgres

O diagrama seguinte mostra como funciona a recolha de métricas do Prometheus:

No diagrama, um cluster privado do GKE contém:

  • Um pod do Postgres que recolhe métricas no caminho / e na porta 9187
  • Recolhedores baseados no Prometheus que processam as métricas do pod do Postgres
  • Um recurso PodMonitoring que envia métricas para o Cloud Monitoring

Para permitir a recolha de métricas dos seus Pods, siga estes passos:

  1. Crie o recurso PodMonitoring

    kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
    
  2. Na Google Cloud consola, aceda à página Explorador de métricas:

    Aceda ao explorador de métricas

    O painel de controlo mostra uma taxa de carregamento de métricas diferente de zero.

  3. Em Selecionar uma métrica, introduza Alvo do Prometheus.

  4. Na secção Categorias de métricas ativas, selecione Cnpg.

Crie um painel de controlo de métricas

Para visualizar as métricas exportadas, crie um painel de controlo de métricas.

  1. Implemente um painel de controlo:

    gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
    
  2. Na Google Cloud consola, aceda à página Painéis de controlo.

    Aceder a Painéis de controlo

  3. Selecione o painel de controlo PostgresQL Prometheus Overview.

    Para rever como os painéis de controlo monitorizam as funções, pode reutilizar ações da secção Autenticação da base de dados e aplicar pedidos de leitura e gravação na base de dados. Em seguida, reveja a visualização das métricas recolhidas num painel de controlo.

  4. Ligue-se ao pod do cliente:

    kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
    
  5. Inserir dados aleatórios:

    psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);INSERT INTO test (randomdata) VALUES (generate_series(1, 1000));"
    
  6. Atualize o painel de controlo. Os gráficos são atualizados com as métricas atualizadas.

  7. Saia da shell do Pod:

    exit