Wiki.Pilas.Guru

7. Migrar MongoDB a StatefulSet

Motivo

Un Deployment gestiona Pods intercambiables. Un StatefulSet proporciona identidad estable y almacenamiento asociado.

Deployment:
  db-<hash>-<hash>

StatefulSet:
  db-0

Services de MongoDB

Se utilizan dos Services:

db
  -> Service ClusterIP normal
  -> lo utiliza la API

db-headless
  -> Service sin ClusterIP
  -> proporciona identidad de red al StatefulSet

La API continúa utilizando:

mongodb://db/mern-crud

El Service normal db ofrece una IP virtual estable y redirige hacia los endpoints disponibles.

El Service headless tiene:

clusterIP: None

Y permite resolver el Pod por un nombre estable:

db-0.db-headless.mern.svc.cluster.local

La IP del Pod puede cambiar, pero el nombre db-0 permanece.

StatefulSet reutilizando el PVC existente

Crear k8s/05-db-statefulset.yaml:

apiVersion: v1
kind: Service
metadata:
  name: db
  namespace: mern
spec:
  type: ClusterIP
  selector:
    app: db
  ports:
    - name: mongodb
      port: 27017
      targetPort: 27017
---
apiVersion: v1
kind: Service
metadata:
  name: db-headless
  namespace: mern
spec:
  clusterIP: None
  selector:
    app: db
  ports:
    - name: mongodb
      port: 27017
      targetPort: 27017
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: mern
spec:
  serviceName: db-headless
  replicas: 1
  selector:
    matchLabels:
      app: db
  template:
    metadata:
      labels:
        app: db
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: mongo
          image: mongo:7.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: mongodb
              containerPort: 27017
          volumeMounts:
            - name: mongo-data
              mountPath: /data/db
      volumes:
        - name: mongo-data
          persistentVolumeClaim:
            claimName: mongo-data

Migrar

Eliminar el Deployment anterior:

kubectl delete deployment db -n mern

El PVC no se elimina.

Crear el StatefulSet:

kubectl apply -f k8s/05-db-statefulset.yaml

Comprobar:

kubectl get statefulset,pods,pvc -n mern -w

El Pod debe llamarse:

db-0

Probar identidad estable

kubectl delete pod db-0 -n mern

El nuevo Pod vuelve a llamarse db-0 y conserva los datos del PVC.

No escalar MongoDB a varias réplicas todavía. Un StatefulSet no convierte automáticamente MongoDB en un replica set.

Separar los manifiestos

El archivo inicial k8s/01-db-api.yaml también contenía la API. Después de migrar MongoDB:

  1. Renombrar el archivo antiguo para no aplicarlo accidentalmente.
  2. Crear k8s/01-api.yaml copiando únicamente el Deployment y el Service de la API.
  3. Mantener el Service db, el Service db-headless y el StatefulSet en k8s/05-db-statefulset.yaml.

Una estructura final recomendada es:

k8s/
├── 01-api.yaml
├── 02-web.yaml
├── 03-ingress.yaml
├── 04-db-pvc.yaml
└── 05-db-statefulset.yaml

No volver a aplicar el manifiesto antiguo de Deployment de MongoDB.

Pruebas a realizar

  1. Comparar los recursos que gestionan MongoDB antes y después de la
    migración:

    kubectl get deployment,statefulset,pods,services,pvc -n mern
    
  2. Describir el StatefulSet y comprobar que utiliza el Service headless:

    kubectl describe statefulset db -n mern
    kubectl get service db-headless -n mern -o yaml
    
  3. Resolver desde un Pod temporal el Service normal y el nombre estable del
    Pod:

    kubectl run debug-dns -n mern --rm -it --restart=Never \
      --image=busybox:1.36 -- sh
    

    Dentro del Pod:

    nslookup db
    nslookup db-headless
    nslookup db-0.db-headless.mern.svc.cluster.local
    exit
    
  4. Eliminar db-0 y observar que el StatefulSet crea otro Pod con el mismo
    nombre y el mismo PVC:

    kubectl delete pod db-0 -n mern
    kubectl get pods,pvc -n mern -w
    
  5. Comprobar que los datos siguen disponibles después de la recreación del
    Pod y revisar los endpoints de ambos Services:

    kubectl get endpointslice -n mern \
      -l kubernetes.io/service-name=db -o wide
    kubectl get endpointslice -n mern \
      -l kubernetes.io/service-name=db-headless -o wide
    
  6. Revisar que no exista todavía un Deployment de MongoDB activo:

    kubectl get deployment db -n mern
    

    El resultado esperado es que no se encuentre ese Deployment; MongoDB debe
    estar gestionado por el StatefulSet.

Aprendizajes del despliegue