O guia mostra como usar o operador Zalando Postgres para implantar clusters do Postgres no Google Kubernetes Engine (GKE).
O PostgreSQL é um poderoso sistema de banco de dados relacional de objetos de código aberto com várias décadas de desenvolvimento ativo. Ele ganhou uma forte reputação de confiabilidade, robustez de recursos e desempenho.
Este guia é destinado a administradores de plataformas, arquitetos de nuvem e profissionais de operações interessados em executar o PostgreSQL como um aplicativo de banco de dados no GKE, em vez de usar o Cloud SQL para PostgreSQL.
Objetivos
- Planejar e implantar a infraestrutura do GKE para Postgres
- Implantar e configurar o operador Zalando Postgres
- Configurar o Postgres usando o operador para garantir disponibilidade, segurança, observabilidade e desempenho
Benefícios
O Zalando oferece os seguintes benefícios:
- Uma maneira declarativa e nativa do Kubernetes de gerenciar e configurar os clusters do PostgreSQL
- Alta disponibilidade fornecida pela Patroni
- Suporte ao gerenciamento de backups usando buckets do Cloud Storage
- Atualizações graduais nas alterações de cluster do Postgres, incluindo atualizações rápidas de versões secundárias
- Gerenciamento declarativo de usuários com geração e rotação de senhas usando recursos personalizados.
- Suporte para TLS, rotação de certificados e pools de conexão
- Clonagem de clusters e replicação de dados
Arquitetura de implantação
Neste tutorial, você usa o operador Zalando Postgres para implantar e configurar um cluster Postgres altamente disponível no GKE. O cluster tem uma réplica líder e duas réplicas em espera (somente leitura) gerenciadas pelo Patroni. O Patroni é uma solução de código aberto mantida pela Zalando para fornecer recursos de alta disponibilidade e failover automático ao Postgres. Em caso de falha do líder, uma réplica em espera é promovida automaticamente para o papel de líder.
Você também vai implantar um cluster do GKE regional altamente disponível para o Postgres, com vários nós do Kubernetes espalhados por várias zonas de disponibilidade. Essa configuração ajuda a garantir tolerância a falhas, escalonabilidade e redundância geográfica. Ela permite atualizações e manutenção graduais, fornecendo SLAs para tempo de atividade e disponibilidade. 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:
No diagrama, o StatefulSet
do Postgres é implantado em três nós em três zonas diferentes. É possível controlar como o GKE é implantado em nós
definindo as regras necessárias de
afinidade e antiafinidade
do pod no
postgresql
. Se uma zona falhar, usando a configuração recomendada, o GKE vai reprogramar os pods em outros nós disponíveis no cluster. Para dados persistentes, use discos SSD (premium-rwo
StorageClass), que são
recomendados na maioria dos casos para bancos de dados
altamente carregados por causabaixa latência e alta IOPS.
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.
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.
- 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.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
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.
-
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine, IAM, GKE, Backup for GKE APIs:
gcloud services enable compute.googleapis.com
iam.googleapis.com container.googleapis.com gkebackup.googleapis.com - Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
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.
-
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Compute Engine, IAM, GKE, Backup for GKE APIs:
gcloud services enable compute.googleapis.com
iam.googleapis.com container.googleapis.com gkebackup.googleapis.com -
Grant roles to your user account. Run the following command once for each of the following IAM roles:
roles/storage.objectViewer, roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin, roles/gkebackup.admin, roles/monitoring.viewer
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.
- Replace
configurar o ambiente
Para configurar seu ambiente, siga estas etapas:
Defina as variáveis de ambiente:
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1
Substitua
PROJECT_ID
pelo ID do projeto do Google Cloud.Clone o repositório do GitHub:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
Mude para o diretório de trabalho:
cd kubernetes-engine-samples/databases/postgres-zalando
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:
Implante esta infraestrutura:
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);
- Um
ServiceAccount
com permissões de registro e monitoramento - Backup do GKE para recuperação de desastres.
- Google Cloud Managed Service para Prometheus para monitoramento de clusters.
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:
Implante a infraestrutura:
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 do Zalando no cluster
Implante o operador Zalando no cluster do Kubernetes usando um gráfico do Helm.
Adicionar o repositório de gráficos Helm do operador Zalando:
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
Criar um namespace para o operador Zalando e o cluster do Postgres:
kubectl create ns postgres kubectl create ns zalando
Implantar o operador do Zalando usando a ferramenta de linha de comando Helm:
helm install postgres-operator postgres-operator-charts/postgres-operator -n zalando \ --set configKubernetes.enable_pod_antiaffinity=true \ --set configKubernetes.pod_antiaffinity_preferred_during_scheduling=true \ --set configKubernetes.pod_antiaffinity_topology_key="topology.kubernetes.io/zone" \ --set configKubernetes.spilo_fsgroup="103"
Não é possível definir as configurações de
podAntiAffinity
diretamente no recurso personalizado que representa o cluster do Postgres. Em vez disso, defina as configurações depodAntiAffinity
globalmente para todos os clusters do Postgres nas configurações do operador.Verifique o status da implantação do operador do Zalando usando o Helm:
helm ls -n zalando
O resultado será assim:
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION postgres-operator zalando 1 2023-10-13 16:04:13.945614 +0200 CEST deployed postgres-operator-1.10.1 1.10.1
Implantar o Postgres
A configuração básica da instância do cluster do Postgres inclui os seguintes componentes:
- Três réplicas do Postgres: uma líder e duas réplicas em espera.
- Alocação de recursos da CPU de uma solicitação de CPU e dois limites de CPU, com solicitações e limites de memória de 4 GB.
- As tolerâncias,
nodeAffinities
etopologySpreadConstraints
configurados para cada carga de trabalho, garantindo a distribuição adequada entre os nós do Kubernetes, utilizando os respectivos pools de nós e as diferentes zonas de disponibilidade.
Essa configuração representa a configuração mínima necessária para criar um cluster do Postgres pronto para produção.
O manifesto a seguir descreve um cluster do Postgres:
Esse manifesto tem os seguintes campos:
spec.teamId
: um prefixo para os objetos de cluster escolhidosspec.numberOfInstances
: o número total de instâncias de um clusterspec.users
: a lista de usuários com privilégiosspec.databases
: a lista de bancos de dados no formatodbname: ownername
.spec.postgresql
: parâmetros postgresspec.volume
: parâmetros do Persistent Diskspec.tolerations
: o modelo de pod de tolerância que permite que os pods de cluster sejam programados em nóspool-postgres
.spec.nodeAffinity
: o modelo de podnodeAffinity
que informa ao GKE que os pods de cluster preferem ser programados nos nóspool-postgres
.spec.resources
: solicitações e limites para pods de clusterspec.sidecars
: uma lista de contêineres de arquivos secundários, que contémpostgres-exporter
.
Para mais informações, consulte a Referência do manifesto de cluster na documentação do Postgres.
Criar um cluster básico do Postgres
Crie um novo cluster do Postgres usando a configuração básica:
kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml
Este comando cria um recurso personalizado do PostgreSQL do operador Zalando com:
- Solicitações e limites de CPU e memória
- Taints e afinidades para distribuir as réplicas de pod provisionadas entre os nós do GKE.
- Um banco de dados.
- Dois usuários com permissões de proprietário do banco de dados
- Um usuário sem permissões
Aguarde o GKE iniciar as cargas de trabalho necessárias:
kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres
Isso pode demorar alguns minutos.
Verifique se o GKE criou as cargas de trabalho do Postgres:
kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres
O resultado será assim:
NAME READY STATUS RESTARTS AGE pod/my-cluster-0 1/1 Running 0 6m41s pod/my-cluster-1 1/1 Running 0 5m56s pod/my-cluster-2 1/1 Running 0 5m16s pod/postgres-operator-db9667d4d-rgcs8 1/1 Running 0 12m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-cluster ClusterIP 10.52.12.109 <none> 5432/TCP 6m43s service/my-cluster-config ClusterIP None <none> <none> 5m55s service/my-cluster-repl ClusterIP 10.52.6.152 <none> 5432/TCP 6m43s service/postgres-operator ClusterIP 10.52.8.176 <none> 8080/TCP 12m NAME READY AGE statefulset.apps/my-cluster 3/3 6m43s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/postgres-operator 1/1 1 1 12m NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE poddisruptionbudget.policy/postgres-my-cluster-pdb 1 N/A 0 6m44s NAME TYPE DATA AGE secret/my-user.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m45s secret/postgres.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/sh.helm.release.v1.postgres-operator.v1 helm.sh/release.v1 1 12m secret/standby.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/zalando.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s
O operador cria os seguintes recursos:
- Um StatefulSet do Postgres, que controla três réplicas de pod para o Postgres
- Uma
PodDisruptionBudgets
, garantindo pelo menos uma réplica disponível - O serviço
my-cluster
, que segmenta apenas a réplica líder - O serviço
my-cluster-repl
, que expõe a porta Postgres para conexões de entrada e para replicação entre as réplicas do Postgres - O serviço sem comando
my-cluster-config
para receber a lista de réplicas de pod do Postgres em execução. - Secrets com credenciais de usuário para acessar o banco de dados e a replicação entre os nós do Postgres
Autenticar no Postgres
É possível criar usuários do Postgres e atribuir a eles permissões de banco de dados. Por exemplo, o manifesto a seguir descreve um recurso personalizado que atribui usuários e papéis:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
users:
mydatabaseowner:
- superuser
- createdb
myuser: []
databases:
mydatabase: mydatabaseowner
Nesse manifesto:
- O usuário
mydatabaseowner
tem os papéisSUPERUSER
eCREATEDB
, que permitem todos os direitos de administrador, (por exemplo, gerenciar a configuração do Postgres, criar novos bancos de dados tabelas e usuários). Não compartilhe esse usuário com clientes. Por exemplo, o Cloud SQL não permite que os clientes tenham acesso a usuários com o papelSUPERUSER
. - O usuário
myuser
não tem papéis atribuídos. Isso segue a prática recomendada de usarSUPERUSER
para criar usuários com privilégios mínimos. Direitos granulares são concedidos amyuser
pormydatabaseowner
. Para manter a segurança, só compartilhe credenciaismyuser
com aplicativos clientes.
Armazenar senhas
Use o
método scram-sha-256
recomendado para armazenar senhas. Por exemplo, o manifesto a seguir descreve um recurso
personalizado que especifica a criptografia scram-sha-256
usando o
campo postgresql.parameters.password_encryption
:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
postgresql:
parameters:
password_encryption: scram-sha-256
Alternar credenciais do usuário
É possível alternar as credenciais de usuários armazenadas em secrets do Kubernetes com o Zalando. Por exemplo, o manifesto
abaixo descreve um recurso personalizado que define a rotação de credenciais do usuário usando
o campo usersWithSecretRotation
:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
usersWithSecretRotation:
- myuser
- myanotheruser
- ...
Exemplo de autenticação: conectar ao Postgres
Nesta seção, mostramos como implantar um exemplo de cliente Postgres e se conectar ao banco de dados usando a senha de um secret do Kubernetes.
Execute o pod cliente para interagir com o cluster do Postgres:
kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
As credenciais dos usuários
myuser
emydatabaseowner
são recebidas dos secrets relacionados e montadas como variáveis de ambiente para o pod.Conecte-se ao pod quando ele estiver pronto:
kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres kubectl exec -it postgres-client -n postgres -- /bin/bash
Conecte-se ao Postgres e tente criar uma nova tabela usando as credenciais
myuser
:PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"
O comando falhará com um erro semelhante ao seguinte:
ERROR: permission denied for schema public LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...
O comando falha porque os usuários sem privilégios atribuídos por padrão só podem fazer login no Postgres e listar bancos de dados.
Crie uma tabela com as credenciais
mydatabaseowner
e conceda todos os privilégios na tabela paramyuser
:PGPASSWORD=$OWNERPASSWORD psql \ -h my-cluster \ -U $OWNERUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);GRANT ALL ON test TO myuser;GRANT ALL ON SEQUENCE test_id_seq TO myuser;"
O resultado será assim:
CREATE TABLE GRANT GRANT
Insira dados aleatórios na tabela usando credenciais
myuser
:for i in {1..10}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" done
O resultado será assim:
INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1
Acesse os valores que você inseriu:
PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "SELECT * FROM test;"
O resultado será assim:
id | randomdata ----+--------------- 1 | jup9HYsAjwtW4 2 | 9rLAyBlcpLgNT 3 | wcXSqxb5Yz75g 4 | KoDRSrx3muD6T 5 | b9atC7RPai7En 6 | 20d7kC8E6Vt1V 7 | GmgNxaWbkevGq 8 | BkTwFWH6hWC7r 9 | nkLXHclkaqkqy 10 | HEebZ9Lp71Nm3 (10 rows)
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 porta9187
. - Coletores baseados em Prometheus que processam as métricas do pod do Postgres.
- Um recurso
PodMonitoring
que envia métricas ao Cloud Monitoring.
O Google Cloud Managed Service para Prometheus é compatível com a coleta de métricas no formato do Prometheus. O Cloud Monitoring usa um painel integrado para métricas do Postgres.
O Zalando expõe as métricas de cluster no formato do Prometheus usando o componente postgres_exporter como um contêiner de arquivo secundário.
Crie o recurso
PodMonitoring
para coletar métricas porlabelSelector
:kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yaml
No console do Google Cloud, acesse a página Painel de clusters do GKE.
Acessar o painel de clusters do GKE
O painel mostra uma taxa de ingestão de métricas diferente de zero.
No console do Google Cloud, acesse a página Painéis.
Abra o painel Visão geral do Prometheus do PostgreSQL. O painel mostra o número de linhas buscadas. Pode levar vários minutos para que o painel seja provisionado automaticamente.
Conecte-se ao pod cliente:
kubectl exec -it postgres-client -n postgres -- /bin/bash
Inserir dados aleatórios:
for i in {1..100}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" done
Atualize a página. Os gráficos de Linhas e Blocos são atualizados para mostrar o estado real do banco de dados.
Saia do shell do pod:
exit
Limpar
Excluir o projeto
Delete a Google Cloud project:
gcloud projects delete PROJECT_ID
Excluir recursos individuais
Defina variáveis de ambiente.
export PROJECT_ID=${PROJECT_ID} export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1
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
porgke-autopilot
ougke-standard
.Quando solicitado, digite
yes
.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)")
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
Para excluir o repositório do GitHub, faça o seguinte:
rm -r ~/kubernetes-engine-samples/
A seguir
- Confira arquiteturas de referência, diagramas, tutoriais e práticas recomendadas do Google Cloud. Confira o Centro de arquitetura do Cloud.