En esta guía se explica cómo usar el operador de Zalando Postgres para desplegar clústeres de Postgres en Google Kubernetes Engine (GKE).
PostgreSQL es un sistema de base de datos relacional de objetos de código abierto potente con varias décadas de desarrollo activo que le han valido una sólida reputación por su fiabilidad, la solidez de sus funciones y su rendimiento.
Esta guía está dirigida a administradores de plataformas, arquitectos de soluciones en la nube y profesionales de operaciones que quieran ejecutar PostgreSQL como aplicación de base de datos en GKE en lugar de usar Cloud SQL para PostgreSQL.
Configurar un entorno
Para configurar tu entorno, sigue estos pasos
Define las variables de entorno:
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1
Sustituye
PROJECT_ID
por el Google Cloud ID de tu proyecto.Clona el repositorio de GitHub:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
Cambia al directorio de trabajo:
cd kubernetes-engine-samples/databases/postgres-zalando
Crear la infraestructura del clúster
En esta sección, ejecutarás una secuencia de comandos de Terraform para crear un clúster de GKE privado, regional y de alta disponibilidad.
Puedes instalar el operador con un clúster estándar o Autopilot.
Estándar
En el siguiente diagrama se muestra un clúster de GKE estándar regional privado desplegado en tres zonas diferentes:
Implementa esta infraestructura:
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}
Cuando se te solicite, escribe yes
. Este comando puede tardar varios minutos en completarse y el clúster en mostrar el estado "Listo".
Terraform crea los siguientes recursos:
- Una red de VPC y una subred privada para los nodos de Kubernetes
- Un router para acceder a Internet a través de NAT
- Un clúster de GKE privado en la región
us-central1
- Un grupo de nodos con el autoescalado habilitado (de uno a dos nodos por zona, con un mínimo de un nodo por zona)
- Un
ServiceAccount
con permisos de registro y monitorización - Copia de seguridad de GKE para la recuperación tras fallos
- Google Cloud Managed Service para Prometheus para la monitorización de clústeres
El resultado debería ser similar al siguiente:
...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...
Autopilot
En el siguiente diagrama se muestra un clúster de Autopilot de GKE regional privado:
Despliega la infraestructura:
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}
Cuando se te solicite, escribe yes
. Este comando puede tardar varios minutos en completarse y el clúster en mostrar el estado "Listo".
Terraform crea los siguientes recursos:
- Una red de VPC y una subred privada para los nodos de Kubernetes
- Un router para acceder a Internet a través de NAT
- Un clúster de GKE privado en la región
us-central1
- Un
ServiceAccount
con permiso de registro y monitorización - Google Cloud Managed Service para Prometheus para la monitorización de clústeres
El resultado debería ser similar al siguiente:
...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...
Conéctate al clúster
Configura kubectl
para que se comunique con el clúster:
gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}
Desplegar el operador de Zalando en el clúster
Despliega el operador de Zalando en tu clúster de Kubernetes mediante un gráfico de Helm.
Añade el repositorio del gráfico de Helm del operador de Zalando:
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
Crea un espacio de nombres para el operador de Zalando y el clúster de PostgreSQL:
kubectl create ns postgres kubectl create ns zalando
Despliega el operador de Zalando con la herramienta de línea de comandos 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"
No puedes configurar los ajustes de
podAntiAffinity
directamente en el recurso personalizado que representa el clúster de Postgres. En su lugar, definepodAntiAffinity
los ajustes de forma global para todos los clústeres de Postgres en la configuración del operador.Comprueba el estado de implementación del operador de Zalando con Helm:
helm ls -n zalando
El resultado debería ser similar al siguiente:
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
Desplegar Postgres
La configuración básica de la instancia del clúster de Postgres incluye los siguientes componentes:
- Tres réplicas de PostgreSQL: una principal y dos de reserva.
- Asignación de recursos de CPU con una solicitud de CPU y dos límites de CPU, con solicitudes y límites de memoria de 4 GB.
- Las tolerancias,
nodeAffinities
ytopologySpreadConstraints
configuradas para cada carga de trabajo aseguran una distribución adecuada entre los nodos de Kubernetes, utilizando sus respectivos grupos de nodos y diferentes zonas de disponibilidad.
Esta configuración representa la configuración mínima necesaria para crear un clúster de Postgres listo para producción.
El siguiente manifiesto describe un clúster de Postgres:
Este manifiesto tiene los siguientes campos:
spec.teamId
: prefijo de los objetos del clúster que elijasspec.numberOfInstances
: número total de instancias de un clústerspec.users
: la lista de usuarios con privilegiosspec.databases
: la lista de bases de datos en el formatodbname: ownername
spec.postgresql
: parámetros de PostgreSQLspec.volume
: parámetros de Persistent Diskspec.tolerations
: la plantilla de tolerancias de pods que permite programar pods de clúster en nodospool-postgres
spec.nodeAffinity
: la plantilla denodeAffinity
Pod que indica a GKE que los pods del clúster prefieren programarse en nodospool-postgres
.spec.resources
: solicitudes y límites de los pods de clústerspec.sidecars
: una lista de contenedores sidecar que contienepostgres-exporter
Para obtener más información, consulta la referencia del manifiesto de clúster en la documentación de Postgres.
Crear un clúster de Postgres básico
Crea un clúster de Postgres con la configuración básica:
kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml
Este comando crea un recurso personalizado de PostgreSQL del operador de Zalando con lo siguiente:
- Solicitudes y límites de CPU y memoria
- Intolerancias y afinidades para distribuir las réplicas de pods aprovisionadas entre los nodos de GKE.
- Una base de datos
- Dos usuarios con permisos de propietario de la base de datos
- Un usuario sin permisos
Espera a que GKE inicie las cargas de trabajo necesarias:
kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres
Este comando puede tardar unos minutos en completarse.
Comprueba que GKE haya creado las cargas de trabajo de Postgres:
kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres
El resultado debería ser similar al siguiente:
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
El operador crea los siguientes recursos:
- Un StatefulSet de Postgres, que controla tres réplicas de Pod para Postgres
- Un
PodDisruptionBudgets
, que garantiza que haya al menos una réplica disponible - El servicio
my-cluster
, que solo se dirige a la réplica principal - El servicio
my-cluster-repl
, que expone el puerto de Postgres para las conexiones entrantes y para la replicación entre réplicas de Postgres - El servicio
my-cluster-config
sin encabezado para obtener la lista de réplicas de Pod de Postgres en ejecución - Secretos con credenciales de usuario para acceder a la base de datos y a la replicación entre nodos de Postgres
Autenticarse en PostgreSQL
Puede crear usuarios de PostgreSQL y asignarles permisos de base de datos. Por ejemplo, el siguiente manifiesto describe un recurso personalizado que asigna usuarios y roles:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
users:
mydatabaseowner:
- superuser
- createdb
myuser: []
databases:
mydatabase: mydatabaseowner
En este manifiesto:
- El usuario
mydatabaseowner
tiene los rolesSUPERUSER
yCREATEDB
, que le permiten tener derechos de administrador completos (es decir, gestionar la configuración de Postgres, crear nuevas bases de datos, tablas y usuarios). No debes compartir este usuario con los clientes. Por ejemplo, Cloud SQL no permite que los clientes tengan acceso a usuarios con el rolSUPERUSER
. - El usuario
myuser
no tiene ningún rol asignado. De esta forma, se sigue la práctica recomendada de usarSUPERUSER
para crear usuarios con los mínimos privilegios.mydatabaseowner
concede derechos granulares amyuser
. Para mantener la seguridad, solo debes compartir las credenciales demyuser
con aplicaciones cliente.
Almacenar contraseñas
Debes usar el scram-sha-256
método recomendado para almacenar contraseñas. Por ejemplo, el siguiente manifiesto describe un recurso personalizado que especifica el cifrado scram-sha-256
mediante el campo postgresql.parameters.password_encryption
:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
postgresql:
parameters:
password_encryption: scram-sha-256
Rotar credenciales de usuario
Puedes rotar las credenciales de usuario que se almacenan en secretos de Kubernetes con Zalando. Por ejemplo, el siguiente manifiesto describe un recurso personalizado que define la rotación de credenciales de usuario mediante el campo usersWithSecretRotation
:
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
usersWithSecretRotation:
- myuser
- myanotheruser
- ...
Ejemplo de autenticación: conectarse a Postgres
En esta sección se muestra cómo desplegar un cliente de Postgres de ejemplo y conectarse a la base de datos mediante la contraseña de un secreto de Kubernetes.
Ejecuta el pod del cliente para interactuar con tu clúster de Postgres:
kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
Las credenciales de los usuarios
myuser
ymydatabaseowner
se toman de los secretos relacionados y se montan como variables de entorno en el pod.Conéctate al Pod cuando esté listo:
kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres kubectl exec -it postgres-client -n postgres -- /bin/bash
Conéctate a PostgreSQL e intenta crear una tabla con las credenciales de
myuser
:PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"
El comando debería fallar y mostrar un error similar al siguiente:
ERROR: permission denied for schema public LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...
El comando falla porque, de forma predeterminada, los usuarios sin privilegios asignados solo pueden iniciar sesión en PostgreSQL y enumerar bases de datos.
Crea una tabla con las credenciales
mydatabaseowner
y concede todos los privilegios en la tabla amyuser
: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;"
El resultado debería ser similar al siguiente:
CREATE TABLE GRANT GRANT
Inserta datos aleatorios en la tabla con las credenciales de
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
El resultado debería ser similar al siguiente:
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
Obtén los valores que has insertado:
PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "SELECT * FROM test;"
El resultado debería ser similar al siguiente:
id | randomdata ----+--------------- 1 | jup9HYsAjwtW4 2 | 9rLAyBlcpLgNT 3 | wcXSqxb5Yz75g 4 | KoDRSrx3muD6T 5 | b9atC7RPai7En 6 | 20d7kC8E6Vt1V 7 | GmgNxaWbkevGq 8 | BkTwFWH6hWC7r 9 | nkLXHclkaqkqy 10 | HEebZ9Lp71Nm3 (10 rows)
Sal del shell del pod:
exit
Información sobre cómo recoge Prometheus las métricas de tu clúster de PostgreSQL
En el siguiente diagrama se muestra cómo funciona la recogida de métricas de Prometheus:
En el diagrama, un clúster privado de GKE contiene lo siguiente:
- Un pod de Postgres que recoge métricas en la ruta
/
y el puerto9187
- Recogedores basados en Prometheus que procesan las métricas del pod de PostgreSQL
- Un recurso
PodMonitoring
que envía métricas a Cloud Monitoring
Google Cloud Managed Service para Prometheus admite la recogida de métricas en formato Prometheus. Cloud Monitoring usa un panel de control integrado para las métricas de PostgreSQL.
Zalando expone las métricas de clúster en formato Prometheus mediante el componente postgres_exporter como contenedor sidecar.
Crea el recurso
PodMonitoring
para recoger métricas porlabelSelector
:kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yaml
En la Google Cloud consola, ve a la página Panel de control de clústeres de GKE.
Ir al panel de control de clústeres de GKE
El panel de control muestra una tasa de ingestión de métricas distinta de cero.
En la Google Cloud consola, ve a la página Paneles de control.
Abre el panel de control de resumen de PostgreSQL Prometheus. En el panel de control se muestra el número de filas obtenidas. El aprovisionamiento automático del panel de control puede tardar varios minutos.
Conéctate al pod del cliente:
kubectl exec -it postgres-client -n postgres -- /bin/bash
Insertar datos aleatorios:
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
Actualiza la página. Los gráficos Filas y Bloques se actualizan para mostrar el estado real de la base de datos.
Sal del shell del pod:
exit