Jobs e CronJobs no Kubernetes

1. Introdução a Workloads Temporários no Kubernetes

No ecossistema Kubernetes, a maioria dos workloads são serviços contínuos — aplicações web, APIs, microserviços — que rodam indefinididamente. No entanto, uma parcela significativa das tarefas em ambientes de produção são temporárias: backups de banco de dados, processamento batch de arquivos, limpeza de logs antigos, envio de relatórios periódicos. Para esses cenários, o Kubernetes oferece dois recursos especializados: Job e CronJob.

1.1. Diferença entre Pods efêmeros e workloads batch

Pods comuns são efêmeros por natureza, mas sua finalidade principal é manter processos contínuos. Quando um container termina sua execução (exit code 0), o Pod é reiniciado pela política restartPolicy: Always. Já os workloads batch (Job e CronJob) são projetados para executar uma tarefa até a conclusão e depois parar. Eles gerenciam o ciclo de vida completo: criação de Pods, monitoramento de conclusão e limpeza.

1.2. Casos de uso

  • Backups: dump de banco de dados PostgreSQL/MySQL armazenado em um volume persistente ou bucket S3
  • Processamento de dados: transformação de arquivos CSV, geração de relatórios, ETL
  • Tarefas agendadas: limpeza de diretórios temporários, rotação de logs, renovação de certificados SSL
  • Migrações: execução de scripts de migração de banco de dados antes de um deployment

1.3. Visão geral dos recursos

  • Job: executa um ou mais Pods até que um número específico de conclusões bem-sucedidas seja alcançado
  • CronJob: cria Jobs em intervalos de tempo definidos por expressão cron, similar ao cron do Linux

2. Job: Execução Única e Garantida

2.1. Definição de um Job

Um Job básico define um template de Pod com restartPolicy: Never ou OnFailure. O campo backoffLimit controla quantas vezes o Job tentará reiniciar um Pod com falha antes de marcar o Job como falho.

apiVersion: batch/v1
kind: Job
metadata:
  name: job-exemplo
spec:
  template:
    spec:
      containers:
      - name: worker
        image: busybox:1.36
        command: ["sh", "-c", "echo 'Tarefa executada'; sleep 5"]
      restartPolicy: Never
  backoffLimit: 4

2.2. Tipos de completude

  • Non-parallel jobs: apenas um Pod é criado. Quando termina com sucesso, o Job é concluído
  • Parallel jobs with fixed completion count: completions define quantos Pods bem-sucedidos são necessários; parallelism define quantos Pods rodam simultaneamente
  • Work queue jobs: o Job cria Pods até que um número suficiente de itens da fila seja processado (sem completions fixo)
apiVersion: batch/v1
kind: Job
metadata:
  name: job-paralelo
spec:
  completions: 6
  parallelism: 2
  template:
    spec:
      containers:
      - name: worker
        image: busybox:1.36
        command: ["sh", "-c", "echo 'Processando...'; sleep 10"]
      restartPolicy: Never

2.3. Monitoramento

Comandos essenciais para acompanhar Jobs:

# Listar Jobs
kubectl get jobs

# Ver detalhes completos
kubectl describe job job-exemplo

# Ver logs do Pod gerado pelo Job
kubectl logs job/job-exemplo

# Acompanhar em tempo real
kubectl get pods --watch -l job-name=job-exemplo

O status de um Job exibe campos como completions, active (Pods rodando) e failed (Pods que falharam).

3. Configuração Avançada de Jobs

3.1. Controle de paralelismo

Os campos parallelism e completions permitem ajustar o throughput:

  • parallelism: 3 e completions: 9: 3 Pods rodam simultaneamente até que 9 tenham sucesso
  • parallelism: 0: pausa a execução (útil para suspender temporariamente)

3.2. Timeout e retentativas

apiVersion: batch/v1
kind: Job
metadata:
  name: job-com-timeout
spec:
  activeDeadlineSeconds: 120       # Job falha se exceder 2 minutos
  backoffLimit: 3                  # Máximo de 3 tentativas por Pod
  ttlSecondsAfterFinished: 3600    # Remove o Job 1 hora após conclusão
  template:
    spec:
      containers:
      - name: worker
        image: busybox:1.36
        command: ["sh", "-c", "exit 1"]   # Simula falha
      restartPolicy: Never
  • activeDeadlineSeconds: tempo máximo total do Job (incluindo retentativas)
  • backoffLimit: número de tentativas antes de marcar como falho
  • ttlSecondsAfterFinished: limpeza automática após conclusão

3.3. Indexed Jobs

Para processamento de filas ou lotes numerados, use completionMode: Indexed:

apiVersion: batch/v1
kind: Job
metadata:
  name: job-indexado
spec:
  completions: 5
  parallelism: 2
  completionMode: Indexed
  template:
    spec:
      containers:
      - name: worker
        image: busybox:1.36
        command: ["sh", "-c", "echo 'Processando item $JOB_COMPLETION_INDEX'"]
      restartPolicy: Never

Cada Pod recebe a variável de ambiente JOB_COMPLETION_INDEX com um valor de 0 a 4.

4. CronJob: Agendamento de Jobs no Tempo

4.1. Estrutura de um CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: backup-diario
spec:
  schedule: "0 2 * * *"            # Todos os dias às 02:00
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: mysql:8.0
            command: ["mysqldump", "-h", "mysql-service", "-u", "root", "--all-databases"]
          restartPolicy: Never
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1

O schedule segue o formato cron padrão: minuto hora dia mês dia-da-semana.

4.2. Políticas de concorrência

  • Allow (padrão): permite que múltiplos Jobs do mesmo CronJob rodem simultaneamente
  • Forbid: não cria novo Job se o anterior ainda estiver ativo
  • Replace: cancela o Job anterior e cria um novo

4.3. Controle de histórico

  • successfulJobsHistoryLimit: quantos Jobs bem-sucedidos manter no histórico (padrão 3)
  • failedJobsHistoryLimit: quantos Jobs falhos manter (padrão 1)

Jobs antigos são removidos automaticamente pelo controlador.

5. Boas Práticas para Jobs e CronJobs

5.1. Imagens idempotentes e stateless

Todo Job deve ser seguro para executar múltiplas vezes sem efeitos colaterais. Por exemplo, um backup deve sobrescrever o arquivo anterior ou usar timestamps. Um script de limpeza deve verificar se o arquivo já foi removido antes de tentar deletá-lo.

5.2. Gerenciamento de dependências

Use Jobs como pré-requisitos via initContainers ou orquestre sequências com ferramentas como Argo Workflows. Para dependências simples, um Job pode verificar a existência de um recurso antes de prosseguir.

5.3. Cleanup automático

Sempre defina ttlSecondsAfterFinished em Jobs e successfulJobsHistoryLimit/failedJobsHistoryLimit em CronJobs para evitar acúmulo de recursos no cluster.

6. Monitoramento e Observabilidade

6.1. Métricas nativas

O Kubernetes expõe métricas via /metrics do kube-controller-manager. Utilize Prometheus para coletar:

  • kube_job_status_succeeded: Jobs concluídos com sucesso
  • kube_job_status_failed: Jobs que falharam
  • kube_job_status_active: Jobs em execução
  • kube_cronjob_status_last_schedule_time: última execução do CronJob

6.2. Logs centralizados

Configure um agregador de logs (Loki, Elasticsearch, CloudWatch) para coletar logs de Jobs. Use labels como job-name e cronjob-name para filtragem.

6.3. Alertas

Alertas comuns usando Prometheus + Alertmanager:

# Falha recorrente: mais de 3 falhas em 10 minutos
- alert: JobFalhando
  expr: rate(kube_job_status_failed[10m]) > 0.3
  for: 5m

# Job travado: ativo por mais de 30 minutos
- alert: JobStuck
  expr: kube_job_status_active > 0 and (time() - kube_job_start_time) > 1800

7. Exemplos Práticos e Integração com o Ecossistema

7.1. Job para backup de banco de dados (MySQL dump)

apiVersion: batch/v1
kind: Job
metadata:
  name: backup-mysql
spec:
  ttlSecondsAfterFinished: 86400
  template:
    spec:
      containers:
      - name: mysqldump
        image: mysql:8.0
        env:
        - name: MYSQL_PWD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        command:
        - sh
        - -c
        - |
          mysqldump -h mysql-service -u root --all-databases > /backup/backup-$(date +%Y%m%d).sql
          echo "Backup concluído: backup-$(date +%Y%m%d).sql"
        volumeMounts:
        - name: backup-storage
          mountPath: /backup
      volumes:
      - name: backup-storage
        persistentVolumeClaim:
          claimName: backup-pvc
      restartPolicy: Never

7.2. CronJob para limpeza de logs antigos

apiVersion: batch/v1
kind: CronJob
metadata:
  name: limpeza-logs
spec:
  schedule: "0 4 * * 0"            # Todo domingo às 04:00
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cleaner
            image: busybox:1.36
            command:
            - sh
            - -c
            - |
              find /var/log/app -name "*.log" -mtime +30 -delete
              echo "Logs com mais de 30 dias removidos"
            volumeMounts:
            - name: log-volume
              mountPath: /var/log/app
          volumes:
          - name: log-volume
            persistentVolumeClaim:
              claimName: logs-pvc
          restartPolicy: Never
      backoffLimit: 2
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 1

7.3. Integração com Helm

Em charts Helm, Jobs e CronJobs são definidos como templates. Exemplo de templates/cronjob.yaml:

{{- if .Values.cronjob.enabled }}
apiVersion: batch/v1
kind: CronJob
metadata:
  name: {{ .Release.Name }}-cronjob
spec:
  schedule: "{{ .Values.cronjob.schedule }}"
  concurrencyPolicy: {{ .Values.cronjob.concurrencyPolicy }}
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: {{ .Chart.Name }}
            image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
            command: {{ .Values.cronjob.command }}
          restartPolicy: Never
  successfulJobsHistoryLimit: {{ .Values.cronjob.successfulJobsHistoryLimit }}
  failedJobsHistoryLimit: {{ .Values.cronjob.failedJobsHistoryLimit }}
{{- end }}

Com values.yaml correspondente:

cronjob:
  enabled: true
  schedule: "0 */6 * * *"
  concurrencyPolicy: Forbid
  command: ["/bin/sh", "-c", "python /app/process.py"]
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1

Referências