Aplicaciones Stateful en Kubernetes – Statefulset

Statefulset en Kubernetes

Statefulset en Kubernetes


En esta entrada vamos a tratar sobre aplicaciones Stateful en Kubernetes – Statefulset, el cual es un tipo de recurso que nos ofrece Kubernetes. Statefulset es un recurso que controla y gestiona en kubernetes uno o más Pods, pero entonces por qué no usar un Deployment te estarás preguntando?, entonces antes de continuar es mejor que veas las diferencias entre Stateful y Stateless en una arquitectura.

Diferencia entre Statefulset y Deployment en Kubernetes

Para entender por qué aplicar un objeto de tipo Statefulset en lugar de Deployment, antes de nada necesitamos conocer las diferencias básicas entre Stateless y Stateful.

Una aplicación stateless es aquella que no tiene estado, a la que no le importa la red en la que se esta ejecutando, o que no necesita un almacenamiento permanente, su información puede ser efímera y estar contenida en su Pod. Un ejemplo de esto puede ser un Tomcat, o un Apache o un Nginx. Este tipo es el más usado dentro de Kubernetes.

Por otro lado, tenemos todas aquellas aplicaciones stateful, que son las que tienen estado, que nos importa conocer la red o la instancia en la que se ejecuta o se está ejecutando, por lo general este tipo de aplicaciones suelen corresponder a Bases de Datos. Algún ejemplo son PostgreSql, MongoDB, Elasticsearch, kafka, etc… .

Vamos a intentar explicar una aplicación Stateful con un ejemplo con PostgreSQL funcionando en alta disponibilidad (HA). Imágina que tenemos ejecutando un único master (escritura) con una o más replicas (lecturas). Como cada nodo que desplegamos tienen que estar identificados para saber quién es master y cuál es réplica y conocer su estado. De esta manera sabemos que nodo escribe y cuál lee además si el master se cae tenemos que elegir su sucesor. Por lo que, necesitamos que se desplieguen de manera Stateful, por lo que utilizaremos un StatefulSet para el despliegue.

Por lo que el motivo para elegir un StatefulSet, en general, en lugar de un deployment, suele ser que necesitamos conocer el Pod, al cual se le asigna una identidad única, y con un Deployment pueden ser intercambiables, y además poder otorgar persistencia a la aplicación.

¿Cómo funciona un Statefulset en Kubernetes?

Cuando decidimos hacer uso del tipo de objeto Statefulset en kubernetes es debido, por lo general, a que los pods que desplegemos tienen que ser únicos y estar identificados. Por lo que cuando creamos este tipo de objeto de manera automática se crearán Pods que se encontrarán identificados.

Cuando trabajamos con Kubernetes se suele crear un servicio, que podríamos definirlo como una capa de abstración para nuestros Pods, se llama o se realiza una petición al servicio y este redirecciona a cualquier Pod. Pero cuando trabajamos con un tipo de Objeto Statefulset el Pod al que se redirija la llamada es importante, por lo que este hecho implica a Headless Service. El cuál no tiene un clúster de IP’s asignadas a unos Pod’s, sino que tiene varios endpoints con unos registros de DNS, y cada uno a un Pod diferentes.

Por lo que detrás de un objeto Statefulset de Kubernetes, la capa servicio que tiene asociada, tendrá una serie de endpoints para atacar directamente al Pod que se requiera.

Cómo desplegar una aplicación Stateful en Kubernetes con un objeto Statefulset?

A continuación vamos a hacer la definición de un objeto Statefulset, para ello vamos a realizar el ejemplo con unas imágenes de cassandra.

Desplegar cassandra en HA en kubernetes

Cassandra en HA | Aplicaciones Stateful en Kubernetes - Statefulset
Cassandra en HA

Lo primero que vamos a hacer es definir un Headless Service, que tal y como hemos comentado antes no irá un clusterIp asociado:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: cassandra
  name: cassandra
spec:
  clusterIP: None
  ports:
  - port: 9042
  selector:
    app: cassandra

y una vez creado el fichero lo ejecutamos de la siguiente manera:

kubectl apply -f cassandra-service.yml

A continuación creamos el objeto Statefulset con el que vamos a crear 2 Pods de cassandra, ya que establecemos replicas 2.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 2
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      terminationGracePeriodSeconds: 1800
      containers:
      - name: cassandra
        image: gcr.io/google-samples/cassandra:v13
        imagePullPolicy: Always
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command: 
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "K8Demo"
          - name: CASSANDRA_DC
            value: "DC1-K8Demo"
          - name: CASSANDRA_RACK
            value: "Rack1-K8Demo"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5

        volumeMounts:
        - name: cassandra-data
          mountPath: /cassandra_data
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi

y a continuación vamos a crear el StorageClass. En esta caso vamos a específicar que tipo de almacenamiento necesitamos y nos proporciona nuestro cloud. Como en nuestro caso usamos minikube, se nos proporciona k8s.io/minikube-hostpath y el tip de parámetro añadimos pd-ssd aunque también puede ser standard.

Si quieres ver el tipo de StorageClass que tienes puedes ejecutar por línea de comando kubectl get sc.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
  type: pd-ssd

A continuación vamos a ver como se han asignado numéricamente los Pods mediante el comando describe:

Describe de cassandra

Podemos ver como se han asignado los pods con cassandra-0 y cassandra-1.

Una vez finalizado podemos realizar pruebas con Cassandra mediante una aplicación Spring Boot que explícamos en un artículo pasado.

Conclusión

En esta entrada Aplicaciones Stateful en Kubernetes – Statefulset, hemos visto como y por qué crear una aplicación statefulset en Kubernetes.

Vamos a hacer un pequeño resumen sobre lo visto en el artículo:

  • Un objeto StatefulSet es un tipo de objeto dentro de Kubernetes que se encarga de gestionar los Pods, pero que esta pensado para las aplicaciones stateful.
  • Las aplicaciones stateful en kubernetes requieren Pods con una identidad única.
  • Para poder trabajar y que nuestras aplicaciones stateful funcionen correctamente en Kubernetes, necesitamos un Headless Service. La cual expone varios endpoints.
  • Un objeto StatefulSet necesita almacenamiento, por lo que usaremos los objetos de kubernetes que nos lo proporcionan.

Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com y te ayudaremos encantados!


No te olvides de seguirnos en nuestras redes sociales Facebook o Twitter para estar actualizado.


1 pensamiento sobre “Aplicaciones Stateful en Kubernetes – Statefulset

Deja una respuesta

Tu dirección de correo electrónico no será publicada.