Adicionar Init Containers

KubernetesBeginner
Pratique Agora

Introdução

Um init container é executado antes dos containers de aplicação principais em um Pod. Cada init container deve ser concluído com sucesso antes que o Kubernetes inicie o próximo init container ou qualquer container regular. Isso torna os init containers úteis para preparar arquivos, verificar dependências ou realizar pequenas tarefas de configuração que não precisam permanecer em execução junto com a aplicação.

Neste laboratório, você adicionará um init container que grava um arquivo de inicialização em um volume emptyDir compartilhado, confirmará que o container da aplicação consegue ler o arquivo, inspecionará o status de conclusão e os logs do init container e, em seguida, usará o mesmo padrão em um template de Deployment.

Preparar um Namespace para Init Containers

Nesta etapa, você preparará um namespace limpo para praticar com init containers.

Comece em /home/labex/project. Você escreverá os manifestos de Pod e Deployment neste diretório.

mkdir -p /home/labex/project
cd /home/labex/project

Verifique se o servidor da API do Kubernetes está acessível. Se a VM acabou de iniciar e o nó ainda não está pronto, aguarde alguns segundos e execute o comando novamente.

kubectl get nodes --request-timeout=5s

A saída esperada inclui:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

Os init containers são executados dentro de Pods, portanto, aguarde até que o Pod de rede do cluster esteja pronto (Ready) antes de criar as cargas de trabalho.

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

Saída esperada:

pod/calico-node-... condition met

Crie um namespace chamado ckad-prep-init:

kubectl create namespace ckad-prep-init

Defina este namespace como o namespace do contexto atual:

kubectl config set-context --current --namespace=ckad-prep-init

Confirme o namespace atual:

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

Saída esperada:

ckad-prep-init

Preparar Dados Compartilhados Antes da Inicialização da Aplicação

Nesta etapa, você criará um Pod onde um init container prepara um arquivo antes que o container da aplicação seja iniciado.

O volume emptyDir é criado quando o Pod é atribuído a um nó e é compartilhado pelos containers no mesmo Pod. Tanto o init container quanto o container da aplicação montam este volume em /work. O init container grava em /work/startup.txt e, em seguida, encerra. Somente após a conclusão bem-sucedida, o Kubernetes inicia o container da aplicação.

Crie o arquivo init-file-pod.yaml:

cat > init-file-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: init-file-demo
  labels:
    app: init-file-demo
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: shared-work
    emptyDir: {}
  initContainers:
  - name: prepare-startup-file
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo init-started; echo prepared-by-init > /work/startup.txt; echo init-finished'
    volumeMounts:
    - name: shared-work
      mountPath: /work
  containers:
  - name: app
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo app-started; cat /work/startup.txt; sleep 3600'
    volumeMounts:
    - name: shared-work
      mountPath: /work
EOF

Aplique o manifesto:

kubectl apply -f init-file-pod.yaml

Saída esperada:

pod/init-file-demo created

Aguarde até que o Pod esteja pronto (Ready):

kubectl wait --for=condition=Ready pod/init-file-demo --timeout=120s

Saída esperada:

pod/init-file-demo condition met

Leia o arquivo de dentro do container da aplicação. Isso prova que o init container preparou os dados no volume compartilhado antes que a aplicação fosse iniciada.

kubectl exec init-file-demo -c app -- cat /work/startup.txt

Saída esperada:

prepared-by-init

Inspecionar o Status e os Logs do Init Container

Nesta etapa, você inspecionará as evidências de que o init container foi concluído antes que o container da aplicação continuasse em execução.

Os init containers aparecem em .status.initContainerStatuses, enquanto os containers regulares aparecem em .status.containerStatuses. O init container deve ter um motivo (reason) Completed porque foi encerrado com sucesso.

kubectl get pod init-file-demo -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'

Saída esperada:

prepare-startup-file Completed

Agora, inspecione o status do container da aplicação regular. Ele deve estar pronto e em execução.

kubectl get pod init-file-demo -o 'jsonpath={.status.containerStatuses[0].name}{" "}{.status.containerStatuses[0].ready}{" "}{.status.containerStatuses[0].state.running.startedAt}{"\n"}'

A saída esperada inclui:

app true ...

Leia os logs do init container. Mesmo que o init container tenha terminado, seus logs permanecem disponíveis através do comando kubectl logs -c.

kubectl logs init-file-demo -c prepare-startup-file

Saída esperada:

init-started
init-finished

Leia os logs do container da aplicação. A aplicação inicia após o init container gravar o arquivo, portanto, seus logs incluem o valor preparado.

kubectl logs init-file-demo -c app

A saída esperada inclui:

app-started
prepared-by-init

Adicionar um Init Container a um Deployment

Nesta etapa, você usará o mesmo padrão de init container dentro de um template de Deployment.

Para cargas de trabalho de aplicação, você geralmente coloca init containers no template de Pod de um controlador, em vez de criar Pods isolados. Quando o Deployment cria um Pod, o Kubernetes executa o init container primeiro para cada Pod criado a partir desse template.

Crie o arquivo init-deployment.yaml:

cat > init-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: init-web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: init-web
  template:
    metadata:
      labels:
        app: init-web
    spec:
      terminationGracePeriodSeconds: 0
      volumes:
      - name: web-content
        emptyDir: {}
      initContainers:
      - name: render-index
        image: busybox:1.36
        command:
        - /bin/sh
        - -c
        - 'echo deployment-init > /site/index.txt'
        volumeMounts:
        - name: web-content
          mountPath: /site
      containers:
      - name: web
        image: busybox:1.36
        command:
        - /bin/sh
        - -c
        - 'cat /site/index.txt; sleep 3600'
        volumeMounts:
        - name: web-content
          mountPath: /site
EOF

Aplique o Deployment:

kubectl apply -f init-deployment.yaml

Saída esperada:

deployment.apps/init-web created

Aguarde até que o Deployment esteja disponível:

kubectl wait --for=condition=Available deployment/init-web --timeout=120s

Saída esperada:

deployment.apps/init-web condition met

Encontre o Pod criado pelo Deployment:

web_pod="$(kubectl get pods -l app=init-web -o 'jsonpath={.items[0].metadata.name}')"
echo "$web_pod"

A saída esperada mostra um nome de Pod gerado:

init-web-...

Leia os logs do container da aplicação a partir desse Pod:

kubectl logs "$web_pod" -c web

Saída esperada:

deployment-init

Inspecione o status de conclusão do init container dentro do Pod criado pelo Deployment:

kubectl get pod "$web_pod" -o 'jsonpath={.status.initContainerStatuses[0].name}{" "}{.status.initContainerStatuses[0].state.terminated.reason}{"\n"}'

Saída esperada:

render-index Completed

Resumo

Você adicionou init containers a um Pod e a um template de Deployment. Você usou um volume emptyDir para compartilhar arquivos preparados com o container da aplicação, inspecionou o status de conclusão do init container, leu os logs do init e da aplicação e confirmou que o mesmo padrão funciona para Pods de aplicação gerenciados por controladores.