Como executar um job

Nesta página, explicamos como executar jobs no Kubernetes Engine.

Visão geral

No GKE, um Job é um objeto controlador que representa uma tarefa finita. Os jobs são diferentes dos outros objetos do controlador porque eles gerenciam a tarefa durante a execução até a conclusão, em vez de gerenciar um estado desejado contínuo (como o número total de pods em execução).

Os jobs são úteis para grandes tarefas de computação e baseadas em lote. Eles podem ser usados para dar suporte à execução paralela de pods. Você pode usar um job para execução em paralelo de itens de trabalho que sejam independentes, mas relacionados: envio de e-mails, renderização de frames, transcodificação de arquivos, verificação de chaves do banco de dados etc. Porém, os jobs não foram projetados para processos paralelos de comunicação estreita, como fluxos contínuos de processos em segundo plano.

No GKE, existem dois tipos de jobs:

  • Job não paralelo: um job que cria apenas um pod (que será recriado se o pod se encerrar com falha) e é concluído quando o pod se encerra com sucesso.
  • Jobs paralelos com contagem de conclusão: um job que é concluído quando um determinado número de pods é encerrado com sucesso. Especifique o número desejado de conclusões no campo completions.

Os jobs são representados por objetos de job do Kubernetes. Quando um job é criado, o controlador dele cria um ou mais pods e garante que eles sejam terminados com êxito. À medida que o pods são terminados, um job rastreia quantos pods concluíram as tarefas com sucesso. Quando o número pretendido de conclusões bem-sucedidas é atingido, o job é concluído.

Semelhante a outros controladores, um controlador de job criará um novo pod se um dos pods falhar ou for excluído.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

Defina as configurações padrão da gcloud usando um dos métodos a seguir:

  • Use gcloud init se quiser orientações para definir os padrões.
  • Use gcloud config para definir individualmente a região, a zona e o ID do projeto.

Como usar o gcloud init

Se você receber o erro One of [--zone, --region] must be supplied: Please specify location, preencha esta seção.

  1. Execute gcloud init e siga as instruções:

    gcloud init

    Se você estiver usando SSH em um servidor remoto, utilize a sinalização --console-only para impedir que o comando inicie um navegador:

    gcloud init --console-only
  2. Siga as instruções para autorizar a gcloud a usar sua conta do Google Cloud.
  3. Crie uma nova configuração ou selecione uma atual.
  4. Escolha um projeto do Google Cloud.
  5. Escolha uma zona padrão do Compute Engine.

Como usar o gcloud config

  • Defina o ID do projeto padrão:
    gcloud config set project project-id
  • Se você estiver trabalhando com clusters zonais, defina a zona do Compute padrão:
    gcloud config set compute/zone compute-zone
  • Se você estiver trabalhando com clusters regionais, defina a região do Compute padrão:
    gcloud config set compute/region compute-region
  • Atualize gcloud para a versão mais recente:
    gcloud components update

Como criar um job

É possível criar um job usando o kubectl apply (em inglês) com um arquivo de manifesto.

O exemplo a seguir mostra um manifesto de job:

apiVersion: batch/v1
kind: Job
metadata:
  # Unique key of the Job instance
  name: example-job
spec:
  template:
    metadata:
      name: example-job
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl"]
        args: ["-Mbignum=bpi", "-wle", "print bpi(2000)"]
      # Do not restart containers after they exit
      restartPolicy: Never
  # of retries before marking as failed.
  backoffLimit: 4

Copie o manifesto para um arquivo chamado config.yaml e crie o Job:

kubectl apply -f config.yaml

Esse job computa o pi até 2.000 casas e, em seguida, o imprime.

O único requisito para um objeto de job é que o campo template do pod é obrigatório.

Contagem de conclusões de job

Um job é concluído quando um número específico de pods termina com sucesso. Por padrão, um job não paralelo com um único pod é concluído assim que o pod se encerra com sucesso.

Se você tiver um job paralelo, defina uma contagem de conclusões usando o campo opcional completions. Esse campo especifica quantos pods devem se encerrar com sucesso antes da conclusão do job. O campo completionscompletions aceita um valor positivo diferente de zero.

Se você omitir o campo completions ou especificar o valor como zero, o êxito de um pod sinalizará o mesmo para todos os outros.

Copie config.yaml do exemplo anterior para um arquivo chamado config-2.yaml. Em config-2.yaml, altere name para example-job-2 e adicione completions: 8 ao campo spec do Job. Isso especifica que é preciso haver oito conclusões bem-sucedidas:

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job-2
spec:
  completions: 8
  template:
    metadata:
      name: example-job-2
    spec:
      ...

Crie o job:

kubectl apply -f config-2.yaml

O valor padrão de completions é 1. Quando completions é definido, o campo parallelism é definido como 1 por padrão, a menos que seja definido de outra forma. Se nenhum dos campos estiverem configurados, os valores padrão serão 1.

Como gerenciar o paralelismo

Por padrão, os pods dos jobs não são executados em paralelo. O campo opcional parallelism especifica o número máximo desejado de pods que um job deve executar simultaneamente em qualquer momento.

O número real de pods em execução em um estado estável poderá ser inferior ao valor de parallelism se o trabalho restante for menor que o valor do parallelism. Se completions também tiver sido definido, o número real de pods em execução em paralelo não excede o número de conclusões restantes. Um job pode acelerar a criação de pods em resposta a falhas excessivas nesse processo.

Copie config.yaml do exemplo anterior para um arquivo chamado config-3.yaml. Em config-3.yaml, altere name para example-job-3 e adicione parallelism: 5 ao campo spec do Job. Isso especifica que é preciso haver cinco pods simultaneamente em execução:

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job-3
spec:
  parallelism: 5
  template:
    metadata:
      name: example-job-3
    spec:
      ...

Crie o job:

kubectl apply -f config-3.yaml

O valor padrão de parallelism será 1 se o campo for omitido ou se for definido de outra forma. Se o valor for definido como 0, o job será pausado até o valor ser aumentado.

Como especificar novas tentativas

Por padrão, um job é executado sem interrupções, a menos que haja uma falha. Nesse ponto, o job é transferido para backoffLimit. O campo backoffLimit especifica o número de novas tentativas antes de marcar o job como falha. O valor padrão é 6. O número de novas tentativas é aplicado por pod, não globalmente. Isso significa que, se vários pods falharem (quando parallelism for maior que 1), o job continuará sendo executado até que um único pod falhe backoffLimit vezes. Quando o backoffLimit for alcançado, o job será marcado como com falha e todos os pods em execução serão encerrados.

Por exemplo, no nosso job de exemplo, definimos o número de novas tentativas como 4:

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job
spec:
  template:
    metadata:
      name: example-job
    spec:
      containers:
      ...
  backoffLimit: 4

Substituição de pods

O job recria os pods para honrar o backoffLimit quando o pod atual é considerado com falha em cenários como estes:

  • O contêiner do pod é encerrado com um código de erro diferente de zero.
  • Quando um nó é reinicializado, o kubelet pode marcar o pod como Failed após a reinicialização.

Em determinados cenários, um job que não foi concluído substitui o pod sem considerar o backoffLimit, como:

  • Encerrar um pod manualmente não definiria a fase do pod como Failed. O pod substituto pode ser criado mesmo antes da conclusão do período de carência do término do pod atual.
  • Quando um nó é drenado (manualmente ou durante o upgrade automático), o pod é encerrado para honrar um período de carência de dreno e é substituído.
  • Quando um nó é excluído, o pod é coletado como lixo (marcado como excluído) e substituído.

Como especificar um prazo

Por padrão, um job sempre criará novos pods se eles falharem continuamente. Se preferir que o job não realize tentativas infinitas, especifique um prazo usando o campo opcional activeDeadlineSeconds.

Um prazo dá a um job uma quantidade específica de tempo, em segundos, para concluir as tarefas antes de se encerrar.

Para especificar um prazo, adicione o valor de activeDeadlineSeconds ao campo spec do Job no arquivo de manifesto. Por exemplo, a configuração a seguir especifica que o job tem 100 segundos para ser concluído:

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job
spec:
  activeDeadlineSeconds: 100
  template:
    metadata:
      name: example-job
    spec:
      ...

Se um job não for concluído com sucesso antes do prazo, ele se encerrará com o status DeadlineExceeded. Isso faz com que a criação de pods pare e que eles sejam excluídos.

Como especificar um seletor de pod

Se você quiser atualizar o modelo de pod, mas quiser que os pods sejam executados no job atualizado, será útil especificar um seletor manualmente.

Um job é instanciado com um campo selector. O selector gera um identificador exclusivo para os pods do job. O código gerado não se sobrepõe a outros jobs. Geralmente, não é recomendável que você mesmo defina esse campo: definir um valor de selector que se sobrepõe a outro job pode causar problemas com pods nesse outro job. Para definir o campo você mesmo, especifique manualSelector: True no campo spec do Job.

Por exemplo, execute kubectl get job my-job --output=yaml para ver a especificação do job, que contém o seletor gerado para seus pods:

kind: Job
metadata:
  name: my-job
...
spec:
  completions: 1
  parallelism: 1
  selector:
    matchLabels:
      controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...

Ao criar um novo Job, você pode definir o valor manualSelector como True e, em seguida, definir o selector valor job-uid do campo, como no exemplo a seguir:

kind: Job
metadata:
  name: my-new-job
  ...
spec:
  manualSelector: true
  selector:
    matchLabels:
      job-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
  ...

Os pods criados por my-new-job usam o UID do pod anterior.

Como inspecionar um job

kubectl

Para verificar o status de um job, execute o seguinte comando:

kubectl describe job my-job

Para visualizar todos os recursos do pod em seu cluster, incluindo pods criados pelo job que foi concluído, execute:

kubectl get pods -a

A sinalização -a define que todos os recursos do tipo especificado (neste caso, pods) serão exibidos.

Console

Para inspecionar um job depois de criá-lo com o kubectl, siga estas etapas:

  1. Acesse o menu "Cargas de trabalho" do Google Kubernetes Engine no Console do Cloud.

    Acessar o menu “Cargas de trabalho”

  2. Selecione a carga de trabalho desejada no menu.

Você pode inspecionar o job das seguintes maneiras:

  • Para ver a configuração ativa do Job, clique em YAML.
  • Para ver todos os eventos relacionados ao job, clique em Eventos.
  • Para ver o histórico de revisões do job, clique em Histórico de revisões.

Como excluir um job

Quando um job é concluído, ele deixa de criar pods. O objeto da job API não é removido quando é concluído, o que permite que você veja o status dele. Os pods criados pelo job não são excluídos, mas são encerrados. A retenção dos pods permite que você veja os registros e interaja com eles.

kubectl

Para excluir um job, execute o seguinte comando:

kubectl delete job my-job

Quando você exclui um job, todos os pods dele também são excluídos.

Para excluir um job, mas manter seus pods, especifique o sinalizador --cascade false:

kubectl delete jobs my-job --cascade false

Console

Para excluir um job, siga estas etapas:

  1. Acesse o menu "Cargas de trabalho" do Google Kubernetes Engine no Console do Cloud.

    Acessar o menu “Cargas de trabalho”

  2. No menu, selecione a carga de trabalho pretendida.

  3. Clique em Excluir.

  4. No menu da caixa de diálogo de confirmação, clique em Excluir.

A seguir