Otros worklods

1. Deployments

  • Propósito: Los Deployments se utilizan para desplegar y gestionar aplicaciones sin estado (stateless). Esto significa que los pods asociados a un Deployment no guardan ningún tipo de información o estado entre sesiones. Son ideales para aplicaciones que no dependen de la persistencia de datos, como aplicaciones web front-end.
  • Características:
    • Permite definir el número de réplicas de un pod y Kubernetes se encarga de mantener ese número funcionando.
    • Si uno de los pods falla, Kubernetes crea uno nuevo automáticamente.
    • Se puede actualizar una aplicación sin downtime, ya que el Deployment realiza una actualización gradual (rolling update).
  • Uso típico: Aplicaciones web, APIs, servicios que no requieren mantener datos entre reinicios.

2. ReplicaSet

  • Propósito: El ReplicaSet es responsable de asegurarse de que un número especificado de réplicas de un pod esté en ejecución en todo momento.
  • Características:
    • Es la base de los Deployments. Normalmente no se usa directamente, ya que los Deployments lo manejan automáticamente.
    • Mantiene el estado deseado en términos de réplicas de pods, pero no gestiona actualizaciones de versiones como los Deployments.
  • Uso típico: Cuando se necesita garantizar que siempre haya un número específico de instancias de un pod en ejecución, pero no se necesitan actualizaciones complejas o estrategias de despliegue.

3. StatefulSet

  • Propósito: Los StatefulSets se utilizan para aplicaciones con estado (stateful), es decir, aquellas que requieren mantener datos o una identidad estable entre reinicios y actualizaciones.
  • Características:
    • A diferencia de los Deployments, los StatefulSets garantizan que los pods se desplieguen de manera ordenada y que tengan nombres fijos.
    • Los pods creados por un StatefulSet tienen un identificador único y persistente, lo que es crucial para ciertas aplicaciones como bases de datos o sistemas distribuidos.
    • Los volúmenes persistentes (persistent volumes) pueden asociarse con cada pod, lo que garantiza que los datos no se pierdan cuando el pod se reinicia o migra.
  • Uso típico: Bases de datos como PostgreSQL, MongoDB, y sistemas distribuidos como Kafka, que requieren que cada instancia mantenga su propio almacenamiento y configuración.

4. DaemonSet

  • Propósito: Un DaemonSet asegura que un pod específico se ejecute en cada nodo de tu clúster.
  • Características:
    • Se utiliza comúnmente para tareas que requieren que cada nodo en el clúster ejecute un pod idéntico. Por ejemplo, para recopilar logs o para monitorear el sistema.
    • Los pods de un DaemonSet se inician automáticamente cuando un nuevo nodo se une al clúster, y se eliminan si un nodo sale.
    • Se usa típicamente en nodos de infraestructura para tareas de mantenimiento o monitoreo.
  • Uso típico: Agentes de monitoreo como Prometheus Node Exporter, o herramientas de logging como Fluentd, o para configurar firewalls a nivel de nodo.

5. Job y CronJob

  • Job:
    • Propósito: Un Job se usa para ejecutar tareas puntuales. Un Job crea uno o más pods y asegura que esas tareas se completen. Si un pod falla, Kubernetes lo reintentará hasta que la tarea finalice correctamente (si está configurado para hacerlo).
    • Características:
      • Ideal para trabajos de procesamiento que no necesitan ejecutarse continuamente, como tareas de procesamiento de datos, cálculos o migraciones de bases de datos.
      • Al finalizar la tarea, los pods se destruyen, a menos que se configure de otro modo.
    • Uso típico: Migraciones de base de datos, procesamiento de archivos, tareas que se ejecutan una sola vez.
  • CronJob:
    • Propósito: Los CronJobs permiten la programación de trabajos (Jobs) de manera recurrente, utilizando un formato similar al cron de Unix/Linux.
    • Características:
      • Permiten definir una periodicidad para la ejecución de tareas, como backups regulares, tareas de mantenimiento o informes programados.
      • Si un cronjob falla o se detiene, Kubernetes puede configurarse para reintentar el trabajo según la política establecida.
    • Uso típico: Realización de backups diarios, generación de informes periódicos, sincronización de datos cada hora.

6. Custom Resource (Recursos Personalizados)

  • Propósito: Un Custom Resource (CR) permite a los usuarios de Kubernetes extender su funcionalidad, creando sus propios tipos de recursos personalizados.
  • Características:
    • Kubernetes ofrece una API rica para gestionar recursos como pods, servicios, volúmenes, etc., pero los Custom Resources permiten crear nuevos tipos de recursos que no están definidos por defecto en Kubernetes.
    • A menudo, los Custom Resources se usan junto con Custom Controllers para gestionar el estado de estos recursos personalizados.
    • Esto es muy útil para implementar operadores, que son controladores que automatizan la gestión de aplicaciones complejas, como bases de datos distribuidas.
  • Uso típico: Usar o crear operadores personalizados que automaticen la gestión de aplicaciones, como Operadores para MongoDB, Kafka, o ElasticSearch.

Conclusión:

Cada tipo de workload en Kubernetes está diseñado para manejar diferentes necesidades de aplicaciones. Los Deployments y ReplicaSets son más adecuados para aplicaciones sin estado, mientras que los StatefulSets son cruciales para aplicaciones que requieren persistencia de datos. Los DaemonSets aseguran que tareas críticas se ejecuten en cada nodo del clúster, y los Jobs/CronJobs gestionan la ejecución de tareas únicas o programadas. Finalmente, los Custom Resources permiten a los usuarios extender Kubernetes para adaptarlo a necesidades específicas.

StatefulSets vs Deployments

Aunque tanto un StatefulSet como un Deployment pueden usar PersistentVolumes (PV) para almacenar datos de manera persistente, no son lo mismo y tienen diferencias clave en su comportamiento, especialmente en cómo gestionan la identidad y el estado de los pods. Aquí te detallo las diferencias principales entre ambos, incluso cuando se usan con almacenamiento persistente:

Diferencias entre StatefulSet y Deployment:

  1. Identidad de los Pods:

    • StatefulSet: Cada pod tiene una identidad única y estable a lo largo del tiempo. Esto significa que los pods tienen nombres predecibles (por ejemplo, myapp-0, myapp-1, etc.), y esos nombres no cambian aunque los pods se reinicien o migren a otros nodos. Además, los pods en un StatefulSet se crean y eliminan de manera ordenada, lo que es crucial para aplicaciones distribuidas que dependen del orden y la persistencia.
    • Deployment: Los pods gestionados por un Deployment no tienen identidad persistente. Si un pod falla o se reinicia, Kubernetes lo reemplaza con otro pod sin preocuparse de que mantenga el mismo nombre o identidad. Para aplicaciones sin estado, esto es perfectamente adecuado, pero para aplicaciones que necesitan una relación estable entre nodos (como bases de datos distribuidas), no es suficiente.
  2. Orden de creación y destrucción:

    • StatefulSet: Los pods se crean y destruyen de forma ordenada. Esto significa que el pod myapp-0 siempre se creará primero, seguido por myapp-1, y así sucesivamente. De la misma manera, cuando se eliminan, lo hacen en orden inverso. Esto es crucial para ciertas aplicaciones, como bases de datos distribuidas o clusters de servicios, donde la secuencia importa.
    • Deployment: Los pods se crean y destruyen de manera aleatoria, no hay garantía de que un pod nuevo mantenga el orden o la relación con otros pods anteriores. Esto es adecuado para aplicaciones que no dependen del orden de ejecución o del estado entre instancias.
  3. Persistencia de datos:

    • StatefulSet: Está diseñado específicamente para aplicaciones con estado. Aunque ambos (StatefulSet y Deployment) pueden usar PersistentVolumes para persistir datos, en el caso de los StatefulSets, cada pod puede tener su propio PersistentVolume asociado individualmente. El pod myapp-0 siempre se conectará a su volumen myapp-0-volume, incluso si se reinicia o migra a otro nodo. Esto garantiza que el estado específico de cada pod se mantenga.
    • Deployment: Los pods de un Deployment también pueden usar volúmenes persistentes, pero como los pods no tienen identidad única y pueden ser recreados sin tener en cuenta cuál era el pod original, no existe la misma asociación directa y predecible entre un pod y su volumen. Esto podría causar problemas en aplicaciones donde cada pod necesita datos específicos.
  4. Casos de uso:

    • StatefulSet: Se usa para aplicaciones con estado que necesitan persistencia, como bases de datos (MySQL, PostgreSQL), sistemas distribuidos (Cassandra, Kafka, Zookeeper), o cualquier sistema que requiera que los nodos (pods) mantengan su identidad y estado a través de reinicios o cambios en la topología del clúster.
    • Deployment: Es ideal para aplicaciones sin estado donde cada instancia del pod es intercambiable, como servidores web, servicios REST, microservicios, etc.

¿Por qué un StatefulSet es diferente de un Deployment aunque ambos usen PV?

Un StatefulSet ofrece capacidades adicionales para manejar el estado y la identidad de los pods, que son vitales para ciertas aplicaciones. Incluso si ambos requieren PersistentVolumes para almacenar datos, la forma en que gestionan los pods y sus volúmenes es distinta:

  • En un StatefulSet, cada pod tiene una asociación única y estable con su volumen persistente, lo que asegura que el estado del pod se mantenga incluso a través de reinicios.
  • En un Deployment, los pods no tienen una asociación estable con sus volúmenes. Si un pod se elimina, el nuevo pod puede no conectarse al mismo volumen, lo que podría hacer que pierda su estado específico, dependiendo de la configuración.

Resumen:

Aunque tanto un StatefulSet como un Deployment pueden usar PersistentVolumes para la persistencia de datos, un StatefulSet gestiona los pods de manera que mantengan una identidad única y estable, lo que es crucial para aplicaciones que dependen del estado y del orden. En cambio, un Deployment es más adecuado para aplicaciones sin estado, donde los pods son intercambiables y no necesitan mantener ningún tipo de identidad entre reinicios.

Bases de datos con statefulSet

Los pods de tipo statefulSet no comparten datos. Cada uno de ellos maneja su propio volumen persistente.

statefull db

El POD-0 es el master y tienen permisos de lectura y escritura mientras que los slave solo lectura.

El resto se replica desde el master

Kubernetes solo se encarga de clonar los pods, pero de la sincronización se encarga la db que esta dentro de los pods.

Los PV se crean a partir de un StorageClass de de un volumeClaimTemplate, de esa manera son unicos para cada pod.

Este concepto que mencionas es muy importante cuando se usan StatefulSets en Kubernetes para aplicaciones que requieren almacenamiento persistente único por cada pod. Vamos a desglosarlo paso a paso:

1. Persistent Volume (PV)

Un Persistent Volume (PV) es un recurso de almacenamiento en Kubernetes que se abstrae de los detalles del almacenamiento físico. Los PVs pueden representar un volumen físico como un disco en la nube, un sistema de archivos en red, o cualquier otro tipo de almacenamiento. Son gestionados por el administrador del clúster.

2. StorageClass

Un StorageClass en Kubernetes define la manera en que se debe aprovisionar un volumen persistente. Es un modelo de “almacenamiento bajo demanda”. Describe el tipo de almacenamiento y sus características (por ejemplo, el tipo de disco, el rendimiento, etc.). Kubernetes puede utilizar el StorageClass para aprovisionar dinámicamente un Persistent Volume cuando sea necesario.

  • StorageClass define el “perfil” del almacenamiento. Ejemplos incluyen gp2 en AWS (discos EBS de rendimiento general), ssd en GCP, etc.

3. volumeClaimTemplate

Cuando usas un StatefulSet en Kubernetes, normalmente quieres que cada pod tenga su propio volumen persistente, es decir, que cada pod tenga su propio PersistentVolumeClaim (PVC) asociado. Aquí es donde el concepto de volumeClaimTemplate entra en juego.

Un volumeClaimTemplate es básicamente una plantilla que Kubernetes utiliza para generar un PersistentVolumeClaim (PVC) único para cada pod que se crea a partir del StatefulSet. Esto asegura que cada pod en el StatefulSet tenga su propio almacenamiento persistente, en lugar de compartir uno.

4. Cómo funciona en conjunto:

  • StorageClass: Define el tipo de almacenamiento que quieres usar para tus volúmenes.
  • PersistentVolumeClaim (PVC): Solicita el almacenamiento persistente basado en un StorageClass.
  • volumeClaimTemplate: En un StatefulSet, cada vez que un nuevo pod es creado, Kubernetes usará el volumeClaimTemplate para generar un nuevo PersistentVolumeClaim (PVC) para ese pod.

El PVC generado solicitará un volumen de almacenamiento que será creado dinámicamente usando el StorageClass especificado.

Flujo de trabajo:

  1. StorageClass define las características del almacenamiento (por ejemplo, un disco SSD en la nube).
  2. El volumeClaimTemplate en el StatefulSet asegura que cada pod tenga su propio PVC.
  3. Kubernetes crea automáticamente un Persistent Volume (PV) basado en el StorageClass cuando el pod lo necesita.
  4. Cada pod en el StatefulSet tiene su propio Persistent Volume asignado, lo que asegura que cada pod tenga su propio espacio de almacenamiento único.

Beneficios:

  • Aislamiento: Cada pod tiene su propio volumen persistente único.
  • Persistencia: Si un pod específico se borra y se recrea, siempre obtendrá su propio volumen persistente original.
  • Automatización: Kubernetes maneja la creación y asignación de los volúmenes dinámicamente mediante el StorageClass.

En resumen, la combinación de PV creado a partir de un StorageClass y un volumeClaimTemplate garantiza que cada pod en un StatefulSet tenga un almacenamiento persistente único y adecuado a sus necesidades.

Ejemplo con MongoDb

Creando StorageClass y sevicio

  1. Creamos un servidor nfs como hicimos en capitulos anteriores.

Es importante que en cada nodo, los cuales cada uno contendran una replica de la DB tienen que tener instalado el cliente de nfs

sudo apt update
sudo apt install nfs-common -y
  1. Instalamos el backend de NFS CLIENT PROVISIONER en el control-plane. Lo haremos con helm esto creara los pods,StorageClass,serviceAccounts y permisos, necesarios para crear pvc de manera dimamica.
curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
sudo apt-get install apt-transport-https --yes
echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner

helm install nfs-subdir-external-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=<IP-SERVER-NFS> \
--set nfs.path=<PATH-NFS-SERVER> \
--set storageClass.onDelete=true

Vemos los servicios creados:

kubectl get pods
kubectl get sc
kubectl get sa
kubectl get deployments
  1. Cremos el servicio para mongo
apiVersion: v1
kind: Service
metadata:
  name: mongodb-svc
  labels:
    app: db
    name: mongodb
spec:
  ports:
  - port: 27017
  clusterIP: None 
  selector:
    app: db
    name: mongodb 
kubectl get svc

NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
kubernetes    ClusterIP   10.96.0.1    <none>        443/TCP     32m
mongodb-svc   ClusterIP   None         <none>        27017/TCP   6s

Al crear un StatefulSet en Kubernetes, la configuración del Service debe tener clusterIP: None si lo que deseas es un servicio de tipo Headless Service. Este tipo de servicio es necesario para que cada pod del StatefulSet tenga su propio nombre DNS único y accesible dentro del clúster.

¿Por qué clusterIP: None?

Cuando defines clusterIP: None, el Headless Service permite que Kubernetes no asigne una IP virtual única al servicio, sino que en su lugar se asignen nombres DNS individuales para cada pod. Esto es útil en los StatefulSets, ya que los pods mantienen una identidad estable y única dentro del clúster.

Con esta configuración, Kubernetes generará automáticamente un nombre DNS para cada pod del StatefulSet. Por ejemplo, si tienes un StatefulSet llamado mongodb con tres réplicas, los nombres DNS para los pods serán:

  • mongodb-0.mongodb-svc.default.svc.cluster.local
  • mongodb-1.mongodb-svc.default.svc.cluster.local
  • mongodb-2.mongodb-svc.default.svc.cluster.local

Cada pod puede acceder a los otros pods a través de estos nombres, lo cual es esencial para aplicaciones que requieren replicación o coordinación, como MongoDB en un clúster.

Ejemplo de tu Service:

Este servicio permitirá que los pods del StatefulSet de MongoDB tengan su propio nombre DNS y se comuniquen entre sí de manera efectiva.

¿Cuándo no usar clusterIP: None?

Si quisieras exponer el servicio MongoDB como un servicio único con una sola IP (por ejemplo, si no estás usando un StatefulSet y solo tienes un Deployment), entonces podrías omitir clusterIP: None y dejar que Kubernetes gestione una única dirección IP para el servicio. Pero en el caso de un StatefulSet, el clusterIP: None es necesario.

7.Creamos el servicio stateful (mongo-stateful.yml)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
spec:
  selector:
    matchLabels:
      app: db
      name: mongodb
  serviceName: mongodb-svc #Servicio headless
  replicas: 3
  template:
    metadata:
      labels:
        app: db
        name: mongodb    
    spec:
      terminationGracePeriodSeconds: 10  
      containers:
      - name: mongo
        image: mongo:3.6        
        command: 
          - mongod
        args: 
          - --bind_ip=0.0.0.0
          - --replSet=rs0 #Nombre del replica set. Todos los miembros dle cluster usan este nombre
          - --dbpath=/data/db          
        livenessProbe:
            exec:
              command:
                - mongo
                - --eval
                - "db.adminCommand('ping')"
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongo-storage
          mountPath: /data/db    
  volumeClaimTemplates:
    - metadata:
        name: mongo-storage      
      spec:
        storageClassName: nfs-client
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi
kubectl apply -f mongo-stateful.yml

Si ahora hacemos :

kubectl get pv

Deberiamos ver que se genero automaticamente el pv

kubectl get pvc

Veremos algo asi :

NAME                    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
mongo-storage-mongo-0   Bound    pvc-695244da-0d2c-41e2-b77a-0b96807d777e   1Gi        RWO            nfs-client     <unset>                 18m
mongo-storage-mongo-1   Bound    pvc-f56ab2fd-c9d2-49d8-937b-faef0d5045ca   1Gi        RWO            nfs-client     <unset>                 18m
mongo-storage-mongo-2   Bound    pvc-269a7bf7-4d5b-4587-b2d6-769942c81ff7   1Gi        RWO            nfs-client     <unset>                 17m
kubectl get pods
NAME                                              READY   STATUS    RESTARTS   AGE
mongo-0                                           1/1     Running   0          19m
mongo-1                                           1/1     Running   0          18m
mongo-2                                           1/1     Running   0          18m
nfs-subdir-external-provisioner-6fbcf8944-g9z8w   1/1     Running   0          24m

Arrancando la replica

El parámetro --replSet=rs0 en la configuración de MongoDB que aparece en la imagen establece el nombre del Replica Set. Un Replica Set es un grupo de instancias de MongoDB que mantienen el mismo conjunto de datos. Las réplicas proporcionan alta disponibilidad y redundancia de datos.

Cuando configuras un Replica Set con —replSet=rs0, indicas que el nodo de MongoDB que estás iniciando formará parte de un conjunto de réplicas llamado rs0. Esto permite que varios nodos de MongoDB se sincronicen entre ellos, manteniendo una copia idéntica de los datos en varios servidores. En un Replica Set típico, hay un nodo primario que recibe todas las operaciones de escritura y varios nodos secundarios que replican los datos del primario.

Beneficios de un Replica Set en MongoDB:

Alta disponibilidad: Si el nodo primario falla, uno de los nodos secundarios puede ser elegido automáticamente como nuevo primario. Redundancia: Los datos están replicados en múltiples servidores, lo que previene la pérdida de datos en caso de fallos. Escalabilidad de lectura: Las aplicaciones pueden leer desde los nodos secundarios (en modo lectura).

Para iniciar un Replica Set en MongoDB, además de configurar los nodos con la opción --replSet, debes seguir algunos pasos adicionales para inicializar y configurar el conjunto de réplicas una vez que los nodos estén en ejecución.

Pasos para iniciar un Replica Set en MongoDB:

1. Asegúrate de que todos los nodos están configurados con --replSet:

En tu archivo de configuración (como el StatefulSet que mostraste), todos los nodos de MongoDB deben tener la opción --replSet=rs0 en los argumentos al iniciar. En tu ejemplo, ya has configurado esto correctamente.

2. Inicia los nodos de MongoDB:

Una vez que los nodos de MongoDB se están ejecutando, el siguiente paso es inicializar el Replica Set.

3. Conéctate al nodo primario:

Accede a uno de los nodos de MongoDB (el que desees que sea el primario inicialmente). Puedes hacerlo utilizando el siguiente comando de kubectl o directamente si estás en una máquina local:

kubectl exec -it <nombre-del-pod-mongodb> -- mongo

O, si estás en una terminal directamente conectada al nodo MongoDB:

mongo

4. Inicializa el Replica Set:

Una vez dentro de la consola de MongoDB, debes inicializar el Replica Set usando el siguiente comando:

rs.initiate()

Esto iniciará el Replica Set en el nodo actual. Si no has definido una configuración específica para el Replica Set, MongoDB lo hará automáticamente, asignando el nodo actual como primario.

5. Verifica el estado del Replica Set:

Después de iniciar el Replica Set, puedes verificar su estado utilizando el siguiente comando:

rs.status()

Esto te mostrará información sobre el Replica Set, incluyendo qué nodos están conectados y cuál es el nodo primario.

6. Agregar nodos secundarios (opcional):

Si estás configurando un Replica Set con varios nodos (lo que es lo más común), puedes agregar nodos secundarios utilizando el comando rs.add(). Por ejemplo:

rs.add("<nombre-del-segundo-nodo>:<puerto>")

Ejemplo:

rs.add("mongo-1.mongodb-svc:27017")
rs.add("mongodb-2.mongodb-svc:27017")

Este comando agregará otros nodos al Replica Set. Debes usar los nombres de los servicios de Kubernetes o las direcciones IP de los otros nodos MongoDB.

7. Verifica nuevamente el estado:

Después de agregar los nodos secundarios, puedes verificar el estado nuevamente con:

rs.status()

Asegúrate de que los nodos secundarios estén sincronizando correctamente con el nodo primario.

Resumen:

  1. Configura todos los nodos con --replSet=rs0.
  2. Inicia los nodos de MongoDB.
  3. Conéctate a uno de los nodos y ejecuta rs.initiate() para iniciar el Replica Set.
  4. Verifica el estado con rs.status().
  5. Agrega nodos secundarios (opcional) con rs.add().
  6. Verifica nuevamente el estado.

Siguiendo estos pasos, tendrás un Replica Set de MongoDB en funcionamiento en tu clúster de Kubernetes. Si tienes alguna duda o encuentras algún problema, estaré aquí para ayudarte.

Mongo express

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-express
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo-express
  template:
    metadata:
      labels:
        app: mongo-express
    spec:
      containers:
      - name: mongo-express
        image: mongo-express:latest
        ports:
        - containerPort: 8081
        env:
        - name: ME_CONFIG_MONGODB_SERVER
          value: "mongo-0.mongodb-svc" 
        - name : ME_CONFIG_MONGODB_URL
          value: mongodb://mongo-0.mongodb-svc:27017


---
apiVersion: v1
kind: Service
metadata:
  name: mongo-express-svc
spec:
  type: NodePort  
  selector:
    app: mongo-express
  ports:
  - protocol: TCP
    port: 80        
    targetPort: 8081

Ahora hacemos kubectl get svc vemos el puerto y en el navegador ponemos http://IP-NODE:PORT-SVC deberiamso poder ver la web de mongo express.

Probando la replica

Creamos mediante la interfaz una db cualquira y una colleccion y agregamos un registro.

Ahora entramos a cualquiera de los pods de mongo.

kubectl exec -it mongo-0 -- sh 
mongo 
show dbs;

Deberiamos poder ver la DB que creamos a traves de mongo-express.

Si vamos a otro pod.

kubectl exec -it mongo-1 -- sh 
rs.secondaryOk();
show dbs;

En MongoDB, cuando estás conectado a un nodo secundario (SECONDARY) de un conjunto replicado, las operaciones de lectura están restringidas de forma predeterminada para proteger la consistencia y evitar que se lean datos incompletos o inestables. MongoDB impone esta restricción porque los nodos secundarios suelen estar dedicados a replicar datos del nodo PRIMARY y no siempre reflejan los datos más recientes.

¿Qué hace rs.secondaryOk()?

La función rs.secondaryOk() indica a MongoDB que permita operaciones de lectura en un nodo SECONDARY. Esto puede ser útil en situaciones donde necesitas:

  1. Consultar datos para propósitos de prueba o monitoreo sin cargar el nodo PRIMARY.
  2. Distribuir la carga de lectura en aplicaciones de solo lectura o donde la consistencia absoluta no es crítica.
  3. Inspeccionar la base de datos sin interrumpir las operaciones de escritura en el nodo PRIMARY.

Ejemplo de Uso:

Si intentas ver las bases de datos en un nodo secundario sin ejecutar rs.secondaryOk(), MongoDB te impedirá hacerlo. Para habilitar la lectura, ejecuta:

rs.secondaryOk()
show dbs

Esto permitirá que el nodo SECONDARY acepte consultas de lectura, aunque debes ser consciente de que los datos pueden no estar actualizados si la replicación está retrasada.

¿Pueden los clientes leer desde un nodo secundario si el PRIMARY se cae y nunca ejecuté rs.secondaryOk()?

Esta es una pregunta frecuente cuando se configuran conjuntos replicados en MongoDB. La capacidad de los clientes para leer desde un nodo SECONDARY después de la caída de un PRIMARY depende de varios factores de configuración y de la capacidad de MongoDB para manejar elecciones de nuevos PRIMARY. Aquí están los puntos clave a considerar:

  1. Elección automática de un nuevo PRIMARY:

    • Si el conjunto replicado está correctamente configurado, los nodos SECONDARY pueden iniciar una elección automática para designar un nuevo PRIMARY.
    • Si se elige un nuevo PRIMARY, los clientes pueden continuar las operaciones sin problemas, accediendo al nuevo nodo PRIMARY para lecturas y escrituras. No se necesita ejecutar rs.secondaryOk().
  2. Preferencias de lectura configuradas en los clientes:

    • Si el conjunto replicado no puede elegir un nuevo PRIMARY (por ejemplo, debido a falta de quórum), todos los nodos permanecerán en estado SECONDARY.
    • En este caso, los clientes podrán leer de los nodos SECONDARY si sus preferencias de lectura están configuradas en "secondaryPreferred" o una configuración similar. Esto permite que las lecturas se dirijan a los nodos secundarios cuando el PRIMARY no está disponible, sin requerir rs.secondaryOk() en el shell.
  3. Usar rs.secondaryOk() manualmente en el shell:

    • rs.secondaryOk() es útil cuando se trabaja directamente en el shell de MongoDB y se necesita habilitar las lecturas en un SECONDARY.
    • Sin embargo, esto no es necesario para los clientes de aplicaciones, siempre y cuando estén configurados para permitir lecturas en nodos SECONDARY.

En resumen, si el PRIMARY se cae y no se elige un nuevo PRIMARY, los clientes podrán leer desde los nodos secundarios siempre que se configuren adecuadamente. Para uso en el shell, rs.secondaryOk() habilita la lectura manualmente en los nodos SECONDARY.

Escalar PODS

kuebctl scale statefulset mongo --replicas=4

Veremos con kubectl get pods como se crean las replicas en base a la ultima, por ejemplo mongo-4 ser replicara de mongo-3 si mongo-3 no esta funcionando correctamente mongo-4 no se creara.

Demon sets

En Kubernetes, un DaemonSet es un tipo de recurso que asegura que una copia de un pod específico se ejecute en cada nodo de un clúster. Esto es particularmente útil para aplicaciones o servicios que deben ejecutarse en todos los nodos, como herramientas de monitoreo, almacenamiento distribuido o proxies de red.

¿Cómo Funciona un DaemonSet?

  1. Despliegue en Todos los Nodos: Cuando se crea un DaemonSet, Kubernetes programa automáticamente un pod en cada nodo del clúster. Si se añade un nodo nuevo al clúster, Kubernetes también programará un nuevo pod del DaemonSet en este nodo.

  2. Manejo de Eliminación: Si un nodo es eliminado o no está disponible, Kubernetes eliminará los pods correspondientes del DaemonSet en ese nodo. Si el nodo vuelve a unirse al clúster, Kubernetes automáticamente volverá a desplegar el pod en ese nodo.

  3. Actualizaciones de DaemonSets: Kubernetes permite actualizar los DaemonSets de manera controlada. Al actualizar la definición del DaemonSet, Kubernetes aplicará las actualizaciones a los pods en todos los nodos según la estrategia configurada, como RollingUpdate, para que los pods se actualicen de uno en uno o de forma paralela.

Usos Comunes de un DaemonSet

  • Monitoreo y Registro: Herramientas como Prometheus Node Exporter o Fluentd, que recogen métricas o logs de cada nodo, suelen ejecutarse mediante un DaemonSet para asegurar que el monitoreo esté cubierto en todos los nodos.
  • Networking: Proxies de red o configuraciones de red avanzadas (como Calico o Weave) suelen necesitar un DaemonSet para ejecutar pods en cada nodo y permitir la configuración o el enrutamiento adecuado.
  • Almacenamiento Distribuido: Servicios de almacenamiento como Ceph o GlusterFS pueden usar DaemonSets para asegurar que cada nodo participe en el sistema de almacenamiento.

Ejemplo de DaemonSet en YAML

Aquí tienes un ejemplo básico de cómo se configura un DaemonSet:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-daemonset
spec:
  selector:
    matchLabels:
      name: log 
  template:
    metadata:
      labels:
        name: log
    spec:
      containers:
      - name: log
        image: logstash:8.4.1

En este ejemplo, Kubernetes desplegará un pod con el contenedor log en cada nodo del clúster, asegurando que el contenedor esté presente y en ejecución.

Diferencia entre DaemonSet y Deployment

  • DaemonSet asegura que haya un pod en cada nodo.
  • Deployment escala los pods en función de la cantidad deseada, sin garantizar que se ejecute en cada nodo.

Un DaemonSet es ideal cuando una aplicación debe ejecutarse en cada nodo del clúster para realizar una tarea crítica de manera local.

Jobs

En Kubernetes, un Job es un recurso que se utiliza para ejecutar tareas de corta duración, que se ejecutan una sola vez o en un número específico de repeticiones. A diferencia de otros recursos como los Deployments o DaemonSets, que están diseñados para ejecutar aplicaciones continuamente, un Job se encarga de tareas que tienen un principio y un fin definidos.

Características Principales de un Job

  1. Ejecución Única o Repetida:

    • Un Job puede configurarse para ejecutarse una única vez o para ejecutarse varias veces hasta que se complete exitosamente.
    • Puedes definir cuántas veces intentará ejecutarse si falla (reintentos), lo cual es útil en tareas donde pueden ocurrir errores intermitentes.
  2. Finalización y Éxito:

    • El Job considera su tarea completada cuando todos los pods que ha lanzado finalizan con éxito.
    • Una vez que el Job se completa exitosamente, Kubernetes no lo ejecutará de nuevo a menos que se recree.
  3. Resiliencia ante Fallos:

    • Si un Job falla durante su ejecución, Kubernetes puede reiniciarlo según la configuración, asegurando que la tarea se complete.
    • Si un nodo falla, Kubernetes programa el Job en otro nodo disponible para asegurar su finalización.

Tipos de Jobs

  • Job Único: Ejecuta una tarea una sola vez y se completa al terminar exitosamente.
  • Job de Paralelismo: Ejecuta varias instancias del mismo Job en paralelo, lo cual es útil para tareas que pueden dividirse en subprocesos.
  • CronJob: Una extensión de los Jobs, que permite programar tareas recurrentes en un intervalo de tiempo específico, similar a un cron en sistemas Unix.

Ejemplo de un Job en YAML

Este es un ejemplo básico de un Job que imprime un mensaje y se completa:

apiVersion: batch/v1
kind: Job
metadata:
  name: job1
spec:
  template:
    spec:
      containers:
      - name: job1
        image: alpine   
        command: ["sh","-c"]
        args: ["echo Estas en la maquina con el nombre $(uname -n)"]
      restartPolicy: Never

En este ejemplo:

  • Ejecuta el comando echo Estas en la maquina con el nombre $(uname -n).
  • $(uname -n) devuelve el nombre del host (en este caso, el nombre del pod).
  • Kubernetes completará el Job y detendrá el pod una vez que el comando termine exitosamente.

Diferencia entre Job y Deployment

  • Job: Ideal para tareas de corta duración que deben completarse y no necesitan ejecutarse de forma continua.
  • Deployment: Ideal para aplicaciones o servicios que necesitan estar siempre en ejecución y manejan automáticamente el escalado y la actualización.

Casos de Uso Comunes

  • Procesamiento de Datos: Ejecutar scripts de procesamiento que analicen datos y se detengan al finalizar.
  • Migraciones de Base de Datos: Ejecutar scripts de migración en bases de datos que solo se necesitan una vez.
  • Tareas de Limpieza: Ejecutar tareas de mantenimiento que se necesitan realizar una sola vez o en intervalos específicos (usando CronJobs).

En resumen, los Jobs son útiles para cualquier tarea de corta duración que necesita completarse exitosamente y luego finalizar.

Entonces si hacemos kubectl get pod y luego tomamos el nombre del pod y vemos los logs kubectl logs nombre-del-pod-job veremos el mensaje “estas en la maquina con nombre ---”

Solo podemos crear un job , si queremos modificar el fichero que lo lanza, tenemos que hacer un delete kubectl delete job1 y volverlo a lanzar con kubectl apply -f job.yml

Jobs con varias replicas

De manera secuencial

apiVersion: batch/v1
kind: Job
metadata:
  name: job2
spec:
  completions: 3
  template:
    spec:
      containers:
      - name: job2
        image: alpine   
        command: ["sh","-c"]
        args: ["echo Estas en la maquina con el nombre $(uname -n)"]
      restartPolicy: Never

De manera paralela

apiVersion: batch/v1
kind: Job
metadata:
  name: job3
spec:
  completions: 3
  paralelism: 3
  template:
    spec:
      containers:
      - name: job3
        image: alpine   
        command: ["sh","-c"]
        args: ["echo Estas en la maquina con el nombre $(uname -n)"]
      restartPolicy: Never

activeDeadlineSeconds y backoffLimit

En un Job de Kubernetes, las propiedades activeDeadlineSeconds y backoffLimit controlan la duración máxima y los intentos de reintento para completar el Job, respectivamente. Vamos a ver cómo funcionan estos parámetros en el contexto de tu ejemplo:

YAML de Ejemplo del Job con activeDeadlineSeconds y backoffLimit
apiVersion: batch/v1
kind: Job
metadata:
  name: job3
spec:
  activeDeadlineSeconds: 60  # El Job tiene un límite de 60 segundos para completarse
  backoffLimit: 4            # Intentará reiniciar hasta 4 veces en caso de fallos
  template:
    spec:
      containers:
      - name: job3
        image: alpine   
        command: ["sh", "-c"]
        args: ["echo Estas en la maquina con el nombre $(uname -n)"]
      restartPolicy: Never
Explicación de los Parámetros
activeDeadlineSeconds
  • Definición: Especifica el tiempo máximo, en segundos, que Kubernetes permitirá que el Job esté activo.

  • Cómo funciona:

    • En este ejemplo, activeDeadlineSeconds: 60 significa que el Job debe completarse en 60 segundos desde el momento en que se inicia.
    • Si el Job no se completa en ese tiempo (por ejemplo, porque el contenedor está tardando demasiado o se queda bloqueado), Kubernetes cancelará el Job y lo marcará como fallido.
  • Uso típico: Este parámetro es útil para evitar que un Job quede colgado indefinidamente si hay algún problema en su ejecución.

backoffLimit
  • Definición: Especifica el número máximo de intentos de reintento si el Job falla.

  • Cómo funciona:

    • En este ejemplo, backoffLimit: 4 significa que Kubernetes intentará reiniciar el Job hasta 4 veces si falla en completarse con éxito.
    • Si el Job falla 4 veces seguidas, Kubernetes dejará de intentarlo y marcará el Job como fallido.
  • Uso típico: Este parámetro es útil cuando deseas que el Job se reintente automáticamente si encuentra errores intermitentes o fallos transitorios, pero deseas limitar la cantidad de intentos para evitar un ciclo infinito de fallos y reintentos.

Ejemplo en Contexto

Supongamos que ejecutas este Job y que el comando echo falla (por ejemplo, porque el contenedor tiene un error). En este caso:

  1. Reintentos: Kubernetes intentará ejecutar el Job hasta 4 veces debido a backoffLimit: 4.
  2. Tiempo Límite: Si los intentos de reintento duran más de 60 segundos en total, activeDeadlineSeconds: 60 detendrá el Job por completo.
  3. Resultado Final: Si el Job falla en todos los reintentos o excede los 60 segundos, se marcará como fallido y no se intentará nuevamente.

Estos parámetros son importantes para controlar y limitar la ejecución de Jobs, evitando tanto ciclos infinitos de reintento como tiempos de ejecución excesivos.

CronJob

Aquí tienes el contenido de la imagen en texto:


Cron schedule syntax

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │                                  7 is also Sunday on some systems)
# │ │ │ │ │
# * * * * *
EntryDescriptionEquivalent to
@yearly (or @annually)Run once a year at midnight of 1 January0 0 1 1 *
@monthlyRun once a month at midnight of the first day of the month0 0 1 * *
@weeklyRun once a week at midnight on Sunday morning0 0 * * 0
@daily (or @midnight)Run once a day at midnight0 0 * * *
@hourlyRun once an hour at the beginning of the hour0 * * * *

Este formato de cron sirve para definir la frecuencia de tareas programadas en servidores y sistemas basados en Unix.

Ejemplo CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job1
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: job1
            image: alpine   
            command: ["sh","-c"]
            args: ["echo Me ejecuto en este momento -- $(date)"]
          restartPolicy: Never

Este YAML define un CronJob en Kubernetes llamado cron-job1 que ejecuta un comando específico en un intervalo de tiempo regular.

Explicación de Cada Parte

  • apiVersion: batch/v1
    Especifica la versión de la API para el recurso de Kubernetes, que en este caso es batch/v1 para trabajos en batch.

  • kind: CronJob
    Indica que el recurso es un CronJob, que permite ejecutar un Job a intervalos regulares, similar a cómo funciona un cron en sistemas UNIX.

  • metadata:

    • name: cron-job1
      Este es el nombre del CronJob en Kubernetes.
  • spec:
    Configuración específica del CronJob.

    • schedule: "* * * * *"
      Define la programación del CronJob usando el formato estándar de cron. En este caso, "* * * * *" significa que el CronJob se ejecutará una vez por minuto. El formato es:

      * * * * *
      │ │ │ │ │
      │ │ │ │ └── Días de la semana (0 - 7) (Domingo = 0 o 7)
      │ │ │ └──── Meses (1 - 12)
      │ │ └────── Días del mes (1 - 31)
      │ └──────── Horas (0 - 23)
      └────────── Minutos (0 - 59)
    • jobTemplate:
      Define la plantilla del Job que se ejecutará según la programación.

      • spec:
        Contiene las especificaciones del Job.

        • template:
          Define la configuración del pod que se creará con cada ejecución del Job.

          • containers:

            • name: job1
              Nombre del contenedor dentro del pod.

            • image: alpine
              Usa la imagen alpine, una imagen ligera de Linux, adecuada para comandos de línea de comandos.

            • command y args:

              • command: ["sh", "-c"]
                Ejecuta el intérprete de comandos sh con la opción -c para ejecutar un comando completo especificado en args.
              • args: ["echo Me ejecuto en este momento -- $(date)"]
                El comando echo imprime la frase “Me ejecuto en este momento” junto con la fecha y hora actuales (obtenidas por $(date)), mostrando así cuándo se ejecutó el Job.
          • restartPolicy: Never
            La política de reinicio se establece en Never, lo que significa que el pod no se reiniciará si falla.

¿Qué Hace Este CronJob?

Este CronJob está configurado para:

  1. Ejecutarse cada minuto gracias a la configuración de schedule: "* * * * *".

  2. Crear un Job cada vez que se ejecuta, el cual lanza un pod que ejecuta el comando:

    echo Me ejecuto en este momento -- $(date)
    
  3. Salida: Cada minuto, en los logs del pod, verás la salida con la frase y la marca de tiempo, como:

    Me ejecuto en este momento -- Sun Oct 29 18:42:00 UTC 2024

Este CronJob es útil para ejecutar tareas programadas en Kubernetes, como tareas de mantenimiento, monitoreo, o procesamiento de datos en intervalos regulares.