Un StatefulSet administra Pods que necesitan una identidad estable, almacenamiento persistente y un orden controlado de creación o actualización. Estas propiedades lo vuelven adecuado para bases de datos, pero no convierten automáticamente varias réplicas en un clúster de alta disponibilidad.

uso de profiles

En esta guía desplegarás una instancia de PostgreSQL orientada a laboratorio. El objetivo es comprender la relación entre StatefulSet, Service headless, Pod, PersistentVolumeClaim y PersistentVolume antes de evaluar una topología productiva.

Advertencia: no utilices este ejemplo como arquitectura de producción sin agregar backups, restauración probada, monitorización y automatización específica de PostgreSQL. Aumentar replicas no configura replicación, failover ni elección de primario.

Qué se va a construir

La solución tendrá:

  • Un StatefulSet con una réplica llamada postgres-0.
  • Un Service headless para proporcionar identidad DNS estable.
  • Un Service convencional para las conexiones de aplicaciones.
  • Un PVC creado mediante volumeClaimTemplates.
  • Un Secret para la contraseña.
  • Probes de arranque y disponibilidad.
  • Una prueba de persistencia después de recrear el Pod.

Los StatefulSets proporcionan nombres ordinales, almacenamiento estable y despliegue ordenado. Cada entrada de volumeClaimTemplates genera un PVC por Pod. Documentación oficial de StatefulSet.

Qué no resuelve un StatefulSet

Un StatefulSet no configura por sí solo:

  • Replicación entre instancias.
  • Consenso o elección de primario.
  • Promoción automática de réplicas.
  • Backups y restauración.
  • Migraciones de esquema.
  • Recuperación ante corrupción lógica.
  • Distribución segura de lecturas y escrituras.

Para producción suele utilizarse un operador específico del motor. Los operadores pueden automatizar backups, restauraciones, actualizaciones y tareas que Kubernetes no conoce de forma nativa. Patrón Operator en Kubernetes.

Requisitos previos

Necesitas:

  • Un clúster Kubernetes operativo.
  • kubectl configurado.
  • Permisos para crear StatefulSets, Services, Secrets y PVC.
  • Un StorageClass con aprovisionamiento dinámico o un PV preparado manualmente.
  • Capacidad suficiente en los nodos y en el backend de almacenamiento.
  • Un entorno de prueba sin datos productivos.

Comprueba el contexto y la comunicación con el clúster:

kubectl config current-context
kubectl version
kubectl cluster-info
kubectl get nodes

Verifica tus permisos:

kubectl auth can-i create statefulsets.apps -n donweb-lab
kubectl auth can-i create persistentvolumeclaims -n donweb-lab
kubectl auth can-i create secrets -n donweb-lab

Paso 1: comprobar el almacenamiento

Lista los StorageClass disponibles:

kubectl get storageclass

Identifica cuál está marcado como predeterminado y revisa sus propiedades:

kubectl describe storageclass NOMBRE_STORAGECLASS

Comprueba especialmente:

  • Provisioner.
  • ReclaimPolicy.
  • VolumeBindingMode.
  • AllowVolumeExpansion.

Los volúmenes creados dinámicamente heredan la política de recuperación del StorageClass. Si no se especifica otra, normalmente es Delete: eliminar el PVC puede provocar también la eliminación del volumen subyacente. StorageClass y políticas de recuperación.

Paso 2: crear el namespace

kubectl create namespace donweb-lab \
  --dry-run=client \
  -o yaml |
kubectl apply -f -

Comprueba el resultado:

kubectl get namespace donweb-lab

Paso 3: crear el Secret

Crea un archivo temporal protegido y escribe una contraseña ficticia o de laboratorio:

install -m 600 /dev/null postgres-password.txt
${EDITOR:-vi} postgres-password.txt

Crea el Secret sin imprimir su contenido:

kubectl create secret generic postgres-auth \
  --namespace donweb-lab \
  --from-file=POSTGRES_PASSWORD=./postgres-password.txt

Elimina la copia local:

rm -f postgres-password.txt

Comprueba únicamente los metadatos:

kubectl get secret postgres-auth -n donweb-lab

No utilices kubectl get secret -o yaml durante comprobaciones rutinarias. Los valores están codificados en Base64, pero eso no equivale a cifrado. Kubernetes recomienda cifrado en reposo, RBAC de mínimo privilegio y, cuando corresponda, un almacén externo. Buenas prácticas para Secrets.

Paso 4: preparar el manifiesto

Guarda lo siguiente como postgres-statefulset.yaml:

apiVersion: v1
kind: Service
metadata:
  name: postgres-headless
  labels:
    app.kubernetes.io/name: postgres
spec:
  clusterIP: None
  selector:
    app.kubernetes.io/name: postgres
  ports:
    - name: postgres
      port: 5432
      targetPort: postgres
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-rw
  labels:
    app.kubernetes.io/name: postgres
spec:
  selector:
    app.kubernetes.io/name: postgres
  ports:
    - name: postgres
      port: 5432
      targetPort: postgres
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  labels:
    app.kubernetes.io/name: postgres
spec:
  serviceName: postgres-headless
  replicas: 1
  podManagementPolicy: OrderedReady

  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain
    whenScaled: Retain

  updateStrategy:
    type: RollingUpdate

  selector:
    matchLabels:
      app.kubernetes.io/name: postgres

  template:
    metadata:
      labels:
        app.kubernetes.io/name: postgres
    spec:
      automountServiceAccountToken: false
      terminationGracePeriodSeconds: 60

      containers:
        - name: postgres
          image: postgres:17-alpine
          imagePullPolicy: IfNotPresent

          ports:
            - name: postgres
              containerPort: 5432

          env:
            - name: POSTGRES_DB
              value: appdb
            - name: POSTGRES_USER
              value: app
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-auth
                  key: POSTGRES_PASSWORD

          startupProbe:
            exec:
              command:
                - sh
                - -ec
                - 'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"'
            periodSeconds: 5
            failureThreshold: 30

          readinessProbe:
            exec:
              command:
                - sh
                - -ec
                - 'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"'
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3

          resources:
            requests:
              cpu: 250m
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 1Gi

          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data

  volumeClaimTemplates:
    - metadata:
        name: data
        labels:
          app.kubernetes.io/name: postgres
      spec:
        accessModes:
          - ReadWriteOncePod
        resources:
          requests:
            storage: 10Gi

ReadWriteOncePod restringe el volumen a un único Pod en todo el clúster y es la opción recomendada para producción cuando el controlador CSI la soporta. Si el provisioner no es compatible, evalúa ReadWriteOnce y documenta sus implicaciones.

En producción, sustituye la etiqueta de la imagen por un digest verificado. Ajusta CPU, memoria, almacenamiento y probes utilizando mediciones reales.

No se incluye una livenessProbe en el ejemplo: una comprobación mal diseñada puede reiniciar una base de datos sana pero temporalmente saturada. Kubernetes advierte que probes de vida incorrectas pueden causar fallos en cascada. Guía oficial de probes.

Paso 5: validar antes de aplicar

Consulta el esquema correcto. El borrador utilizaba deployment.spec, aunque el recurso es un StatefulSet:

kubectl explain statefulset.spec
kubectl explain statefulset.spec.volumeClaimTemplates
kubectl explain statefulset.spec.persistentVolumeClaimRetentionPolicy

Realiza la validación en el servidor sin persistir cambios:

kubectl apply \
  --namespace donweb-lab \
  --dry-run=server \
  -f postgres-statefulset.yaml

Revisa las diferencias:

kubectl diff \
  --namespace donweb-lab \
  -f postgres-statefulset.yaml

kubectl diff devuelve código 1 cuando existen diferencias y un código mayor cuando ocurre un error. No añadas || true indiscriminadamente, porque ocultaría fallos reales de autenticación, validación o conexión.

Paso 6: aplicar y observar

kubectl apply \
  --namespace donweb-lab \
  -f postgres-statefulset.yaml

Espera a que finalice el despliegue:

kubectl rollout status \
  statefulset/postgres \
  --namespace donweb-lab \
  --timeout=5m

Observa los recursos:

kubectl get statefulset,pod,service,pvc -n donweb-lab
kubectl get persistentvolume
kubectl get events -n donweb-lab --sort-by=.lastTimestamp

El PVC esperado se llamará:

data-postgres-0

El nombre combina el template data con el Pod postgres-0. Si el PVC permanece Pending, no continúes: revisa el StorageClass, el modo de acceso, la capacidad, la topología de nodos y los eventos.

Paso 7: comprobar DNS y disponibilidad

Comprueba PostgreSQL desde el propio Pod:

kubectl exec -n donweb-lab postgres-0 -- \
  pg_isready -U app -d appdb

Consulta el nombre asignado:

kubectl exec -n donweb-lab postgres-0 -- hostname -f

El DNS estable dentro del namespace será:

postgres-0.postgres-headless

Su forma completa suele ser:

postgres-0.postgres-headless.donweb-lab.svc.cluster.local

Las aplicaciones deben conectarse normalmente a postgres-rw:5432. El DNS individual resulta útil cuando la topología del motor necesita identificar una instancia concreta.

Paso 8: probar la persistencia

Ejecuta esta prueba únicamente en el laboratorio:

kubectl exec -n donweb-lab postgres-0 -- \
  psql -U app -d appdb -c \
  "CREATE TABLE IF NOT EXISTS validacion (mensaje text); INSERT INTO validacion VALUES ('persistente');"

Elimina el Pod, pero no el PVC:

kubectl delete pod postgres-0 -n donweb-lab

StatefulSet creará otro Pod llamado postgres-0 y volverá a asociarlo con data-postgres-0.

Espera a que esté disponible:

kubectl rollout status \
  statefulset/postgres \
  -n donweb-lab \
  --timeout=5m

Comprueba que el dato continúa:

kubectl exec -n donweb-lab postgres-0 -- \
  psql -U app -d appdb -c \
  "SELECT * FROM validacion;"

La prueba demuestra persistencia ante la recreación del Pod. No demuestra backup, alta disponibilidad ni recuperación ante corrupción del volumen.

Actualizaciones y rollback

Consulta las revisiones:

kubectl rollout history statefulset/postgres -n donweb-lab

Después de modificar la imagen, observa el rollout:

kubectl rollout status statefulset/postgres -n donweb-lab

Para volver a la plantilla anterior:

kubectl rollout undo statefulset/postgres -n donweb-lab

StatefulSet es un tipo admitido por kubectl rollout. Referencia oficial de rollout.

El rollback solo revierte la plantilla de los Pods. No restaura:

  • Datos eliminados o corruptos.
  • Cambios de esquema.
  • Credenciales rotadas.
  • Contenido de los PVC.
  • Configuración externa al StatefulSet.

Si un rollout queda bloqueado por un Pod que nunca alcanza Ready, revierte primero la plantilla y revisa cuidadosamente si es necesario eliminar el Pod defectuoso para que sea recreado.

Escalado y alta disponibilidad

No ejecutes simplemente:

kubectl scale statefulset postgres --replicas=3

Cada Pod recibiría identidad y volumen propios, pero PostgreSQL no comenzaría a replicar datos por ese motivo. Tampoco existirían promoción de primario, quorum ni enrutamiento de escrituras.

Para producción, utiliza una arquitectura validada para PostgreSQL, preferiblemente mediante un operador mantenido, que gestione:

  • Inicialización de réplicas.
  • Elección y promoción de primario.
  • Backups consistentes.
  • Restauración y recuperación a un punto temporal.
  • Actualizaciones compatibles.
  • Certificados y credenciales.
  • Métricas de replicación y alertas.

La propia guía oficial de MySQL replicado aclara que su ejemplo didáctico no es una configuración de producción. Aplicación stateful replicada.

Eliminación y retención

La política del manifiesto es:

persistentVolumeClaimRetentionPolicy:
  whenDeleted: Retain
  whenScaled: Retain

Por ello, eliminar o reducir el StatefulSet no debería eliminar automáticamente sus PVC. Compruébalo siempre:

kubectl get pvc -n donweb-lab

No elimines un PVC hasta confirmar:

  1. Que existe un backup utilizable.
  2. Que se probó su restauración.
  3. Que el volumen ya no contiene datos necesarios.
  4. Qué reclaimPolicy tiene el PV.

Eliminar el PVC puede activar la eliminación del volumen subyacente. Kubernetes recomienda no asumir que será posible acceder al volumen después de borrar el claim.

gestion de identidades mediante almacenamiento estable

Problemas frecuentes

El PVC permanece en Pending

Revisa:

kubectl describe pvc data-postgres-0 -n donweb-lab
kubectl get storageclass
kubectl get events -n donweb-lab --sort-by=.lastTimestamp

Las causas habituales son ausencia de StorageClass predeterminado, modo de acceso incompatible, falta de capacidad o restricciones de zona.

El Pod entra en CrashLoopBackOff

Consulta el contenedor actual y el anterior:

kubectl logs postgres-0 -n donweb-lab
kubectl logs postgres-0 -n donweb-lab --previous
kubectl describe pod postgres-0 -n donweb-lab

Revisa permisos del volumen, contraseña, memoria, compatibilidad de la imagen y archivos de datos creados por otra versión mayor.

El Service no tiene endpoints disponibles

kubectl get endpointslice -n donweb-lab \
  -l kubernetes.io/service-name=postgres-rw

Comprueba que las etiquetas coincidan y que la readiness probe sea correcta.

El volumen no puede montarse

Busca eventos FailedAttachVolume, FailedMount o Multi-Attach. No fuerces la eliminación del Pod o del PVC hasta entender si el volumen continúa conectado a otro nodo.

El rollout queda detenido

Revisa el Pod ordinal que no alcanza Ready, sus logs y eventos. Un StatefulSet con OrderedReady no continúa hasta que la instancia precedente esté disponible.

Buenas prácticas para producción

  • Usa un operador específico y mantenido para el motor.
  • Conserva backups fuera del clúster y prueba restauraciones periódicamente.
  • Define RPO y RTO antes de elegir la arquitectura.
  • Separa credenciales, configuración y datos.
  • Habilita cifrado en tránsito y en reposo.
  • Aplica RBAC y NetworkPolicy de mínimo privilegio.
  • Monitoriza capacidad, latencia, conexiones y replicación.
  • Distribuye réplicas entre nodos y zonas solo cuando el motor esté configurado para ello.
  • Fija imágenes por digest y planifica las actualizaciones de versión mayor.
  • Trata snapshots de volumen y backups lógicos como mecanismos diferentes.


uso de stateful set

Conclusión

StatefulSet proporciona la base de identidad y almacenamiento que necesita una aplicación con estado. Su valor está en mantener nombres, DNS, PVC y orden de operación estables cuando los Pods se recrean.

La disponibilidad real de una base de datos depende además del motor, su estrategia de replicación, los backups y la capacidad de restaurarlos. Kubernetes organiza los recursos; no reemplaza la administración especializada de los datos.

Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting