Añadir Init Containers

KubernetesBeginner
Practicar Ahora

Introducción

Un init container se ejecuta antes que los contenedores de aplicación principales en un Pod. Cada init container debe finalizar correctamente antes de que Kubernetes inicie el siguiente init container o cualquier contenedor regular. Esto hace que los init containers sean útiles para preparar archivos, verificar dependencias o realizar pequeñas tareas de configuración que no necesitan permanecer en ejecución junto a la aplicación.

En este laboratorio, añadirás un init container que escribe un archivo de inicio en un volumen compartido emptyDir, confirmarás que el contenedor de la aplicación puede leer el archivo, inspeccionarás el estado de finalización y los registros del init container, y luego utilizarás el mismo patrón en una plantilla de Deployment.

Preparar un Namespace para Init Containers

En este paso, prepararás un namespace limpio para practicar con init containers.

Comienza en /home/labex/project. Escribirás los manifiestos de Pod y Deployment en este directorio.

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

Verifica que el servidor de la API de Kubernetes sea accesible. Si la máquina virtual acaba de iniciarse y el nodo aún no está listo, espera unos segundos y vuelve a ejecutar el comando.

kubectl get nodes --request-timeout=5s

La salida esperada incluye:

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

Los init containers se ejecutan dentro de los Pods, así que espera hasta que el Pod de red del clúster esté listo (Ready) antes de crear cargas de trabajo.

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

Salida esperada:

pod/calico-node-... condition met

Crea un namespace llamado ckad-prep-init:

kubectl create namespace ckad-prep-init

Establece este namespace como el namespace del contexto actual:

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

Confirma el namespace actual:

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

Salida esperada:

ckad-prep-init

Preparar datos compartidos antes de iniciar la aplicación

En este paso, crearás un Pod donde un init container prepara un archivo antes de que se inicie el contenedor de la aplicación.

El volumen emptyDir se crea cuando el Pod se asigna a un nodo y es compartido por los contenedores dentro del mismo Pod. Tanto el init container como el contenedor de la aplicación montan este volumen en /work. El init container escribe /work/startup.txt y luego termina. Solo después de que finaliza con éxito, Kubernetes inicia el contenedor de la aplicación.

Crea 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

Aplica el manifiesto:

kubectl apply -f init-file-pod.yaml

Salida esperada:

pod/init-file-demo created

Espera hasta que el Pod esté listo:

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

Salida esperada:

pod/init-file-demo condition met

Lee el archivo desde dentro del contenedor de la aplicación. Esto demuestra que el init container preparó los datos en el volumen compartido antes de que la aplicación comenzara.

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

Salida esperada:

prepared-by-init

Inspeccionar el estado y los registros del Init Container

En este paso, inspeccionarás la evidencia de que el init container se completó antes de que el contenedor de la aplicación comenzara a ejecutarse.

Los init containers aparecen bajo .status.initContainerStatuses, mientras que los contenedores regulares aparecen bajo .status.containerStatuses. El init container debería tener un motivo (reason) de Completed porque terminó con éxito.

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

Salida esperada:

prepare-startup-file Completed

Ahora inspecciona el estado del contenedor de aplicación regular. Debería estar listo y en ejecución.

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

La salida esperada incluye:

app true ...

Lee los registros del init container. Aunque el init container haya terminado, sus registros permanecen disponibles a través de kubectl logs -c.

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

Salida esperada:

init-started
init-finished

Lee los registros del contenedor de la aplicación. La aplicación comienza después de que el init container escribe el archivo, por lo que sus registros incluyen el valor preparado.

kubectl logs init-file-demo -c app

La salida esperada incluye:

app-started
prepared-by-init

Añadir un Init Container a un Deployment

En este paso, utilizarás el mismo patrón de init container dentro de una plantilla de Deployment.

Para cargas de trabajo de aplicación, normalmente colocas los init containers en la plantilla de Pod de un controlador en lugar de crear Pods independientes. Cuando el Deployment crea un Pod, Kubernetes ejecuta el init container primero para cada Pod creado a partir de esa plantilla.

Crea 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

Aplica el Deployment:

kubectl apply -f init-deployment.yaml

Salida esperada:

deployment.apps/init-web created

Espera hasta que el Deployment esté disponible:

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

Salida esperada:

deployment.apps/init-web condition met

Encuentra el Pod creado por el Deployment:

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

La salida esperada muestra un nombre de Pod generado:

init-web-...

Lee los registros del contenedor de la aplicación desde ese Pod:

kubectl logs "$web_pod" -c web

Salida esperada:

deployment-init

Inspecciona el estado de finalización del init container dentro del Pod creado por el Deployment:

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

Salida esperada:

render-index Completed

Resumen

Has añadido init containers a un Pod y a una plantilla de Deployment. Utilizaste un volumen emptyDir para compartir archivos preparados con el contenedor de la aplicación, inspeccionaste el estado de finalización del init container, leíste los registros tanto del init container como de la aplicación, y confirmaste que el mismo patrón funciona para Pods de aplicación gestionados por controladores.