Ajouter des conteneurs d'initialisation (Init Containers)

KubernetesBeginner
Pratiquer maintenant

Introduction

Un conteneur d'initialisation (init container) s'exécute avant les conteneurs d'application principaux dans un Pod. Chaque conteneur d'initialisation doit se terminer avec succès avant que Kubernetes ne démarre le conteneur d'initialisation suivant ou tout conteneur régulier. Cela rend les conteneurs d'initialisation utiles pour préparer des fichiers, vérifier des dépendances ou effectuer de petites tâches de configuration qui n'ont pas besoin de rester actives parallèlement à l'application.

Dans ce laboratoire, vous allez ajouter un conteneur d'initialisation qui écrit un fichier de démarrage dans un volume partagé emptyDir, confirmer que le conteneur d'application peut lire ce fichier, inspecter le statut et les journaux du conteneur d'initialisation, puis appliquer ce même modèle dans un modèle de déploiement (Deployment).

Préparer un espace de noms pour les conteneurs d'initialisation

Dans cette étape, vous allez préparer un espace de noms (namespace) propre pour pratiquer les conteneurs d'initialisation.

Commencez dans /home/labex/project. Vous rédigerez les manifestes de Pod et de Deployment dans ce répertoire.

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

Vérifiez que le serveur API Kubernetes est accessible. Si la machine virtuelle vient de démarrer et que le nœud n'est pas encore prêt, attendez quelques secondes et relancez la commande.

kubectl get nodes --request-timeout=5s

La sortie attendue inclut :

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

Les conteneurs d'initialisation s'exécutent à l'intérieur des Pods ; attendez donc que le Pod réseau du cluster soit prêt avant de créer des charges de travail.

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

Sortie attendue :

pod/calico-node-... condition met

Créez un espace de noms nommé ckad-prep-init :

kubectl create namespace ckad-prep-init

Définissez cet espace de noms comme contexte actuel :

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

Confirmez l'espace de noms actuel :

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

Sortie attendue :

ckad-prep-init

Préparer des données partagées avant le démarrage de l'application

Dans cette étape, vous allez créer un Pod où un conteneur d'initialisation prépare un fichier avant le démarrage du conteneur d'application.

Le volume emptyDir est créé lorsque le Pod est assigné à un nœud et est partagé par les conteneurs au sein du même Pod. Le conteneur d'initialisation et le conteneur d'application montent tous deux ce volume sur /work. Le conteneur d'initialisation écrit /work/startup.txt, puis se termine. Ce n'est qu'après sa réussite que Kubernetes démarre le conteneur d'application.

Créez 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

Appliquez le manifeste :

kubectl apply -f init-file-pod.yaml

Sortie attendue :

pod/init-file-demo created

Attendez que le Pod soit prêt :

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

Sortie attendue :

pod/init-file-demo condition met

Lisez le fichier depuis l'intérieur du conteneur d'application. Cela prouve que le conteneur d'initialisation a bien préparé les données sur le volume partagé avant le démarrage de l'application.

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

Sortie attendue :

prepared-by-init

Inspecter le statut et les journaux du conteneur d'initialisation

Dans cette étape, vous allez vérifier que le conteneur d'initialisation s'est bien terminé avant que le conteneur d'application ne continue de s'exécuter.

Les conteneurs d'initialisation apparaissent sous .status.initContainerStatuses, tandis que les conteneurs réguliers apparaissent sous .status.containerStatuses. Le conteneur d'initialisation doit avoir une raison Completed car il s'est terminé avec succès.

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

Sortie attendue :

prepare-startup-file Completed

Inspectez maintenant le statut du conteneur d'application régulier. Il doit être prêt et en cours d'exécution.

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

La sortie attendue inclut :

app true ...

Lisez les journaux du conteneur d'initialisation. Même si le conteneur d'initialisation est terminé, ses journaux restent disponibles via kubectl logs -c.

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

Sortie attendue :

init-started
init-finished

Lisez les journaux du conteneur d'application. L'application démarre après que le conteneur d'initialisation a écrit le fichier, ses journaux incluent donc la valeur préparée.

kubectl logs init-file-demo -c app

La sortie attendue inclut :

app-started
prepared-by-init

Ajouter un conteneur d'initialisation à un Deployment

Dans cette étape, vous allez utiliser le même modèle de conteneur d'initialisation au sein d'un modèle de déploiement (Deployment).

Pour les charges de travail applicatives, vous placez généralement les conteneurs d'initialisation dans le modèle de Pod d'un contrôleur plutôt que de créer des Pods isolés. Lorsque le Deployment crée un Pod, Kubernetes exécute d'abord le conteneur d'initialisation pour chaque Pod créé à partir de ce modèle.

Créez 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

Appliquez le Deployment :

kubectl apply -f init-deployment.yaml

Sortie attendue :

deployment.apps/init-web created

Attendez que le Deployment soit disponible :

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

Sortie attendue :

deployment.apps/init-web condition met

Trouvez le Pod créé par le Deployment :

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

La sortie attendue affiche un nom de Pod généré :

init-web-...

Lisez les journaux du conteneur d'application depuis ce Pod :

kubectl logs "$web_pod" -c web

Sortie attendue :

deployment-init

Inspectez le statut de fin du conteneur d'initialisation à l'intérieur du Pod créé par le Deployment :

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

Sortie attendue :

render-index Completed

Résumé

Vous avez ajouté des conteneurs d'initialisation à un Pod et à un modèle de déploiement. Vous avez utilisé un volume emptyDir pour partager des fichiers préparés avec le conteneur d'application, inspecté le statut des conteneurs d'initialisation terminés, lu les journaux d'initialisation et d'application, et confirmé que ce même modèle fonctionne pour les Pods d'application gérés par un contrôleur.