Jobs en Kubernetes

En más de un cliente he visto que una de las razones por la que usan Kubernetes es para la ejecución de tareas de forma escalable y programable. Ya sean trabajos de Spark, transcodificación de video, proyectos de machine learning, etcétera. Hoy vamos a ver cómo funcionan los jobs en Kubernetes.

Qué es un job

Por si no estás familiarizado/a con el concepto, un job o trabajo, también conocido como tareas, es la ejecución de un programa que tiene un principio y un fin. Es decir, no es una aplicación que está continuamente ejecutándose, como puede ser un sitio web o un proceso en segundo plano como veíamos en el artículo anterior.

Su estructura en YAML es la siguiente:

#job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: countdown
spec:
  template:
    metadata:
      name: countdown
    spec:
      containers:
      - name: counter
        image: ubuntu
        command:
         - "bin/bash"
         - "-c"
         - "for i in {0..15} ; do echo $i ; sleep 1; done"
      restartPolicy: Never

Para este ejemplo, voy a lanzar un job que, utilizando como imagen ubuntu, simplemente cuenta desde cero hasta 15. Puedes crearlo como el resto de recursos a través del siguiente comando:

kubectl apply -f job.yaml

Los jobs de tu clúster puedes recuperarlos así:

kubectl get jobs

Estos trabajos se apoyan en pods, que son los que van a realizar las tareas. Sin embargo, una vez que finalice permanecerá con el estado Completed entre tus pods.

kubectl get pods

Esto es así para que puedas revisar los logs incluso después de haber finalizado.

kubectl logs countdown-8vgl5
kubectl logs countdown-8vgl5

Como el resto de recursos vistos hasta ahora, también tienen su sección en el dashboard de Kubernetes:

Jobs en el dashboard de Kubernetes

Para volver a ejecutar un trabajo deberás eliminarlo y volver a crearlo o bien utilizar CronJobs, que veremos después.

Tipos de tareas

Podríamos decir que es posible configurar tres tipos de tareas:

Tareas simples

Se tratan de aquellas que solamente se ejecutan una vez, que es el ejemplo que hemos visto, con un único pod.

Tareas secuenciales

Tareas por lotes que se ejecutan de manera secuencial, es decir una detrás de otra. Modificando nuestro ejemplo quedaría de la siguiente manera:

apiVersion: batch/v1
kind: Job
metadata:
  name: sequential-countdown
spec:
  completions: 3
  template:
    metadata:
      name: countdown
    spec:
      containers:
      - name: sequential-counter
        image: ubuntu
        command:
         - "bin/bash"
         - "-c"
         - "for i in {0..15} ; do echo $i ; sleep 1; done"
      restartPolicy: Never

Simplemente añadiendo la propiedad completions y el número de veces que queremos que se ejecute se lanzará la tarea N veces de manera secuencial.

Tareas en paralelo

Por último, también tenemos la posibilidad de crear tareas que se lancen en paralelo:

apiVersion: batch/v1
kind: Job
metadata:
  name: parallel-countdown
spec:
  completions: 10
  parallelism: 3
  template:
    metadata:
      name: countdown
    spec:
      containers:
      - name: parallel-counter
        image: ubuntu
        command:
         - "bin/bash"
         - "-c"
         - "for i in {0..15} ; do echo $i ; sleep 1; done"
      restartPolicy: Never

Junto con la propiedad completions, si añadimos la propiedad parallelism conseguimos que el número de tareas elegido se pueda paralelizar hasta el número especificado en esta propiedad.

Paralelizando jobs con parallelism

Programar tareas con CronJob

Otro de los escenarios frecuentes es que sea necesario programar ciertas tareas. Para ello, existe otro recurso llamado CronJob que funciona de la misma manera que un cron de Linux. Siguiendo el ejemplo anterior, podemos modificarlo para que el mismo se ejecute cada minuto:

#cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: countdown
spec:
    #min hour day-of-month month day-of-week
  schedule: "*/1 * * * *" #every minute
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: countdown
            image: ubuntu
            args:
            - /bin/sh
            - -c
            - "for i in {0..15} ; do echo $i ; sleep 1; done"
          restartPolicy: OnFailure

Como puedes ver, el formato es bastante similar solo que utilizamos la típica expresión de cron en la propiedad schedule para indicar cada cuánto queremos que se ejecute esta tarea. Crea el cronjob:

kubectl apply -f cronjob.yaml

Y comprobarás que el mismo se lanza cada minuto.

kubectl get cronjobs

En el dashboard podrás ver más información, como cuántos pods se han lanzado, hace cuánto, los eventos relacionados, etcétera:

Cron Jobs en el dashboard de Kubernetes

¡Saludos!