Implantar o PostgreSQL no GKE usando o CloudNativePG


O guia mostra como implantar clusters do PostgreSQL no Google Kubernetes Engine (GKE) usando o operador CloudNativePG.

O PostgreSQL é um banco de dados relacional de objeto de código aberto com várias décadas de desenvolvimento ativo, garantindo um desempenho estável do cliente. Ele oferece uma variedade de recursos, incluindo replicação, recuperação pontual, recursos de segurança e extensibilidade. O PostgreSQL é compatível com os principais sistemas operacionais e está em total conformidade com os padrões ACID (atomicidade, consistência, isolamento e durabilidade).

Este guia é destinado a administradores de plataformas, arquitetos de nuvem e profissionais de operações interessados em implantar clusters do Postgres no GKE. A execução do Postgres no GKE em vez de usar o Cloud SQL pode oferecer mais flexibilidade e controle de configuração para administradores de bancos de dados experientes.

Benefícios

O CloudNativePG é um operador de código aberto desenvolvido pelo EDB sob uma licença Apache 2. Ele traz os seguintes recursos para a implantação do PostgreSQL:

  • Uma maneira declarativa e nativa do Kubernetes de gerenciar e configurar os clusters do PostgreSQL
  • Gerenciamento de backup usando snapshots de volume ou o Cloud Storage
  • Conexão TLS criptografada em trânsito, a capacidade de usar sua própria autoridade de certificação e a integração com o Gerenciador de certificados para a emissão e a rotação automatizadas de certificados TLS.
  • Atualizações graduais para versões secundárias do PostgreSQL
  • Uso do servidor da API Kubernetes para manter um status do cluster do PostgreSQL e failovers para alta disponibilidade sem a necessidade de outras ferramentas
  • Configuração de exportador integrada do Prometheus por meio de métricas definidas pelo usuário e escritas em SQL

Objetivos

  • Planejar e implantar a infraestrutura do GKE para Postgres
  • Implante e configure o operador CloudNativePG Postgres com o Helm
  • Implantar um cluster do PostgreSQL
  • Configurar a autenticação e a observabilidade do PostgreSQL

Arquitetura de implantação

O PostgreSQL tem várias opções de implantação, de um servidor de banco de dados independente para um cluster de alta disponibilidade replicado. Este tutorial se concentra na implantação de clusters altamente disponível no GKE.

Nesta implantação, as cargas de trabalho do cluster do PostgreSQL são distribuídas por várias zonas de disponibilidade no cluster regional do GKE, garantindo alta disponibilidade e redundância. Para mais informações, consulte Clusters regionais.

O diagrama a seguir mostra um cluster do Postgres em execução em vários nós e zonas em um cluster do GKE:

Cluster do Postgres no GKE

  • A configuração padrão inclui um servidor PostgreSQL principal e dois servidores de backup prontos para serem usados caso o servidor principal falhe, garantindo a disponibilidade contínua do banco de dados.

  • Os recursos do operador CloudNativePG usam um namespace separado do cluster do GKE para melhorar o isolamento de recursos e a abordagem recomendada de microsserviços de um banco de dados por cluster do PostgreSQL. O banco de dados e o usuário correspondente (usuário do app) são definidos no recurso personalizado do Kubernetes que representa o cluster.

  • O armazenamento é um componente crucial quando se trata de bancos de dados. O armazenamento precisa ter um desempenho eficiente, garantir a disponibilidade contínua e a consistência dos dados. Por esses motivos, recomendamos a classe de armazenamento premium-rwo, que é baseada em discos SSD. O operador CloudNativePG cria PersistentVolumeClaims automaticamente conforme necessário ao configurar pods para o cluster do PostgreSQL.

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.

Antes de começar

O Cloud Shell vem pré-instalado com o software necessário para este tutorial, incluindo o kubectl, a gcloud CLI, o Helm e o Terraform. Se você não usa o Cloud Shell, é necessário instalar a gcloud CLI.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Enable the Compute Engine, IAM, GKE, Resource Manager APIs:

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com
  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

    gcloud init
  9. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  10. Make sure that billing is enabled for your Google Cloud project.

  11. Enable the Compute Engine, IAM, GKE, Resource Manager APIs:

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com cloudresourcemanager.googleapis.com
  12. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/compute.securityAdmin, roles/compute.viewer, roles/container.clusterAdmin, roles/container.admin, roles/iam.serviceAccountAdmin, roles/iam.serviceAccountUser

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
    • Replace PROJECT_ID with your project ID.
    • Replace USER_IDENTIFIER with the identifier for your user account. For example, user:myemail@example.com.

    • Replace ROLE with each individual role.

configurar o ambiente

Para configurar o ambiente, siga estas etapas:

  1. Defina as variáveis de ambiente:

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

    Substitua o PROJECT_ID pelo ID do projeto do Google Cloud.

  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
    

Criar a infraestrutura do cluster

Nesta seção, você executa um script do Terraform para criar um cluster regional do GKE privado e altamente disponível.

É possível instalar o operador usando um cluster padrão ou Autopilot.

Padrão

O diagrama a seguir mostra um cluster regional padrão particular do GKE implantado em três zonas diferentes:

Para implantar essa 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 solicitado, digite yes. Pode levar vários minutos para que esse comando seja concluído e o cluster mostre um status pronto.

O Terraform cria os seguintes recursos:

  • Uma rede VPC e uma sub-rede particular para os nós do Kubernetes.
  • Um roteador para acessar a Internet usando NAT.
  • Um cluster particular do GKE na região us-central1.
  • Um pool de nós com escalonamento automático ativado (de um a dois nós por zona, um nó por zona no mínimo);

O resultado será assim:

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

Piloto automático

O diagrama a seguir mostra um cluster particular regional do Autopilot do GKE:

Para implantar 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 solicitado, digite yes. Pode levar vários minutos para que esse comando seja concluído e o cluster mostre um status pronto.

O Terraform cria os seguintes recursos:

  • Uma rede VPC e uma sub-rede particular para os nós do Kubernetes.
  • Um roteador para acessar a Internet usando NAT.
  • Um cluster particular do GKE na região us-central1.
  • Um ServiceAccount com permissão de geração de registros e monitoramento.
  • Google Cloud Managed Service para Prometheus para monitoramento de clusters.

O resultado será assim:

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

Conexão ao cluster

Configure kubectl para se comunicar com o cluster:

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

Implantar o operador CloudNativePG

Implante o CloudNativePG no seu cluster do Kubernetes usando um gráfico do Helm:

  1. Adicionar o repositório de gráficos Helm do operador CloudNativePG:

    helm repo add cnpg https://cloudnative-pg.github.io/charts
    
  2. Implantar o operador do CloudNativePG usando a ferramenta de linha de comando Helm:

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

    O resultado será assim:

    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
    ...
    

Implantar o Postgres

O manifesto a seguir 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

Esse manifesto tem os seguintes campos:

  • spec.instances: o número de pods do cluster
  • spec.primaryUpdateStrategy: a estratégia de atualização gradual:
    • Unsupervised: atualiza de maneira autônoma o nó do cluster principal após os nós de réplica.
    • Supervised: a alternância manual é necessária para o nó do cluster principal
  • spec.postgresql: substituições de parâmetros de arquivo postgres.conf, como regras pg-hba, LDAP e requisitos para que as réplicas de sincronização sejam atendidas.
  • spec.storage: configurações relacionadas ao armazenamento, como classe de armazenamento, tamanho do volume e configurações de registro prévio de escrita.
  • spec.bootstrap: parâmetros do banco de dados inicial criado no cluster, credenciais do usuário e opções de restauração do banco de dados
  • spec.resources: solicitações e limites para pods de cluster
  • spec.affinity: regras de afinidade e antiafinidade das cargas de trabalho do cluster

Criar um cluster básico do Postgres

  1. Para criar um namespace:

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

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

    Esse comando pode levar alguns minutos para ser concluído.

  3. Verifique o status do cluster:

    kubectl get cluster -n pg-ns --watch
    

    Antes de prosseguir, aguarde até que o status Cluster in healthy state seja exibido na saída.

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

Inspecionar os recursos

Confirme se o GKE criou os recursos para o cluster:

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

O resultado será assim:

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 do PostgreSQL controlado pelo operador
  • Recursos PersistentVolumeClaim com os volumes permanentes correspondentes
  • Secrets com credenciais de usuário para acessar o banco de dados e a replicação entre os nós do Postgres
  • Três serviços de endpoint de banco de dados: <name>-rw, <name>-ro e <name>-r para conectar-se ao cluster. Para mais informações, consulte Arquitetura do PostgreSQL.

Autenticar no Postgres

É possível se conectar ao banco de dados PostgreSQL e verificar o acesso por meio de diferentes endpoints de serviço criados pelo operador. Para fazer isso, use um pod extra com um cliente PostgreSQL e credenciais de usuário de aplicativo sincronizadas ativadas 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 faça login 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. Faça login no banco de dados usando o serviço gke-pg-cluster-rw para estabelecer uma conexão com privilégios de leitura e gravação:

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

    O terminal começa com o nome do banco de dados:

    app=>
    
  4. Crie 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. Insira dados na tabela:

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

    SELECT * FROM travel_agency_clients ;
    

    O resultado será assim:

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

    exit
    
  8. Faça login no banco de dados usando o serviço gke-pg-cluster-ro para verificar o acesso somente leitura. Esse serviço permite a consulta de dados, mas restringe qualquer operação de gravação:

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

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

    O resultado será assim:

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

    SELECT * FROM travel_agency_clients ;
    

    O resultado será assim:

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

    exit
    
  12. Saia do shell do pod:

    exit
    

Entender como o Prometheus coleta métricas para seu cluster do Redis

No diagrama a seguir, mostramos como funciona a coleta de métricas do Prometheus:

No diagrama, um cluster particular do GKE contém os seguintes componentes:

  • Um pod Postgres que coleta métricas no caminho / e na porta 9187.
  • Coletores baseados em Prometheus que processam as métricas do pod do Postgres.
  • Um recurso PodMonitoring que envia métricas ao Cloud Monitoring.

Para permitir a coleta de métricas dos pods, siga estas etapas:

  1. Crie o recurso PodMonitoring:

    kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
    
  2. No Console do Google Cloud, acesse a página do Metrics Explorer:

    Acesse o Metrics explorer

    O painel mostra uma taxa de ingestão de métricas diferente de zero.

  3. Em Selecionar uma métrica, insira Destino do Prometheus.

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

Criar um painel de métricas

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

  1. Implante um painel:

    gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
    
  2. No console do Google Cloud, acesse a página Painéis.

    Vá para Painéis

  3. Selecione o painel Visão geral do Prometheus do PostgresQL.

    Para analisar como os painéis monitoram as funções, reutilize ações da seção Autenticação do banco de dados, aplique solicitações de leitura e gravação no banco de dados e analise a visualização das métricas coletadas em um painel.

  4. Conecte-se ao pod 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. Os gráficos são atualizados com as métricas atualizadas.

  7. Saia do shell do pod:

    exit
    

Limpar

Exclua o projeto

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

Excluir recursos individuais

  1. Defina variáveis de ambiente.

    export PROJECT_ID=${PROJECT_ID}
    export KUBERNETES_CLUSTER_PREFIX=postgres
    export REGION=us-central1
    
  2. Execute o comando terraform destroy:

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

    Substitua FOLDER por gke-autopilot ou gke-standard.

    Quando solicitado, digite yes.

  3. Encontre todos os discos desanexados:

    export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
    
  4. Exclua os discos:

    for i in $disk_list; do
      disk_name=$(echo $i| cut -d'|' -f1)
      disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||')
      echo "Deleting $disk_name"
      gcloud compute disks delete $disk_name --zone $disk_zone --quiet
    done
    

A seguir