You are viewing documentation for Kubernetes version: v1.20
Kubernetes v1.20 documentation non maintenue. Vous consultez une version statique. Pour une documentation à jour, veuillez consulter: dernière version.
Init Containers
Cette page fournit une vue d'ensemble des conteneurs d'initialisation (init containers) : des conteneurs spécialisés qui s'exécutent avant les conteneurs d'application dans un Pod. Les init containers peuvent contenir des utilitaires ou des scripts d'installation qui ne sont pas présents dans une image d'application.
Vous pouvez spécifier des init containers dans la spécification du Pod à côté du tableau containers
(qui décrit les conteneurs d'application)
Comprendre les init containers
Un Pod peut avoir plusieurs conteneurs exécutant des applications mais peut aussi avoir un ou plusieurs init containers, qui sont exécutés avant que les conteneurs d'application ne démarrent.
Les init containers se comportent comme les conteneurs réguliers, avec quelques différences :
- Les init containers s'exécutent toujours jusqu'à la complétion.
- Chaque init container doit se terminer avec succès avant que le prochain ne démarre.
Si le init container d'un Pod échoue, Kubernetes redémarre le Pod à répétition jusqu'à ce que le init container se termine avec succès.
Cependant, si le Pod a une restartPolicy
à "Never", Kubernetes ne redémarre pas le Pod.
Afin de spécifier un init container pour un Pod, il faut ajouter le champ initContainers
dans la spécification du Pod, comme un
tableau d'objets de type Container, au même niveau que le tableau d'applications containers
.
Le statut des init containers est retourné dans le champ .status.initContainerStatuses
comme un tableau des statuts du conteneur (comparable au champ .status.containerStatuses
).
Différences avec les conteneurs réguliers
Les init containers supportent tous les champs et fonctionnalités des conteneurs d'application incluant les limites de ressources, les volumes et les paramètres de sécurité. Cependant, les demandes de ressources pour un init container sont gérées différemment des limites de ressources, tel que documenté dans Ressources.
De plus, les init containers ne supportent pas les readiness probes parce que ces conteneurs s'exécutent jusqu'au bout avant que le Pod soit prêt.
Si l'on spécifie plusieurs init containers pour un Pod, Kubelet exécute chaque init container de manière séquentielle. Chaque init container doit se terminer avec succès avant que le prochain ne puisse s'exécuter. Lorsque tous les init containers se sont exécutés jusqu'au bout, Kubelet initialise les conteneurs d'application pour le Pod et les exécute comme d'habitude.
Utiliser les init containers
Puisque les init containers ont des images séparées des conteneurs d'application, ils apportent certains avantages pour du code de mise en route :
- Les init containers peuvent contenir des utilitaires ou du code de configuration personnalisé
qui ne sont pas présents dans une image d'application.
Par exemple, il n'y a pas besoin de faire hériter une image d'une autre (
FROM
) seulement pour utiliser un outil commesed
,awk
,python
, oudig
pendant l'installation. - Les init containers peuvent exécuter en toute sécurité des utilitaires qui rendraient moins sécurisée une image de conteneur d'application.
- Les rôles "builder" et "deployer" d'une image d'application peuvent travailler indépendamment sans qu'il n'y ait besoin de créer conjointement une seule image d'application.
- Les init containers peuvent s'exécuter avec une vue du système de fichiers différente de celle des conteneurs d'application dans le même Pod. Par conséquent, on peut leur donner accès aux Secrets, auxquels les conteneurs d'application n'ont pas accès.
- Puisque les init containers s'exécutent jusqu'à la complétion avant qu'un conteneur d'application ne démarre, les init containers offrent un mécanisme pour bloquer ou retarder le démarrage d'un conteneur d'application tant qu'un ensemble de préconditions n'est pas respecté. Une fois que les préconditions sont respectées, tous les conteneurs d'application dans un Pod peuvent démarrer en parallèle.
Exemples
Voici plusieurs idées pour utiliser les init containers :
Attendre qu'un Service soit créé, en utilisant une commande shell d'une ligne telle que :
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
Enregistrer ce Pod à un serveur distant depuis l'API downward avec une commande telle que :
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
Attendre un certain temps avant de démarrer le conteneur d'application avec une commande telle que :
sleep 60
Cloner un dépôt Git dans un Volume
Placer des valeurs dans un fichier de configuration et exécuter un outil de templating pour générer dynamiquement un fichier de configuration pour le conteneur d'application principal. Par exemple, placer la valeur
POD_IP
dans une configuration et générer le fichier de configuration de l'application principale en utilisant Jinja.
Les init containers en utilisation
Cet exemple définit un simple Pod possédant deux init containers.
Le premier attend myservice
et le second attend mydb
. Une fois que les deux
init containers terminent leur exécution, le Pod exécute le conteneur d'application décrit dans sa section spec
.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo "L''app s''exécute!" && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo en attente de myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo en attente de mydb; sleep 2; done"]
Les fichiers YAML suivants résument les services mydb
et myservice
:
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
Vous pouvez démarrer ce Pod en exécutant :
kubectl apply -f myapp.yaml
pod/myapp-pod created
Et vérifier son statut avec :
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
ou pour plus de détails :
kubectl describe -f myapp.yaml
Name: myapp-pod
Namespace: default
[...]
Labels: app=myapp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
Pour voir les logs des init containers dans ce Pod, exécuter :
kubectl logs myapp-pod -c init-myservice # Inspecter le premier init container
kubectl logs myapp-pod -c init-mydb # Inspecter le second init container
À ce stade, ces init containers attendent de découvrir les services nommés
mydb
et myservice
.
Voici une configuration que vous pouvez utiliser pour faire apparaître ces Services :
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
Pour créer les services mydb
et myservice
:
kubectl apply -f services.yaml
service/myservice created
service/mydb created
Vous verrez ensuite que ces init containers se terminent et que le Pod myapp-pod
évolue vers l'état "Running" (en exécution) :
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
Cet exemple simple devrait suffire à vous inspirer pour créer vos propres init containers. A suivre contient un lien vers un exemple plus détaillé.
Comportement détaillé
Pendant le démarrage d'un Pod, chaque init container démarre en ordre, après que le réseau
et les volumes ont été initialisés. Chaque conteneur doit se terminer avec succès avant que le prochain
ne démarre. Si un conteneur n'arrive pas à démarrer à cause d'un problème d'exécution ou
se termine avec un échec, il est redémarré selon la restartPolicy
du Pod.
Toutefois, si la restartPolicy
du Pod est configurée à "Always", les init containers utilisent la restartPolicy
"OnFailure".
Un Pod ne peut pas être Ready
tant que tous les init containers ne se sont pas exécutés avec succès.
Les ports d'un init container ne sont pas agrégés sous un Service. Un Pod qui s'initialise
est dans l'état Pending
mais devrait avoir une condition Initialized
configurée à "true".
Si le Pod redémarre ou est redémarré, tous les init containers doivent s'exécuter à nouveau.
Les changements aux spec d'un init containers sont limités au champ image du conteneur. Changer le champ image d'un init container équivaut à redémarrer le Pod.
Puisque les init containers peuvent être redémarrés, réessayés ou ré-exécutés,
leur code doit être idempotent. En particulier, le code qui écrit dans des fichiers sur EmptyDirs
devrait être préparé à la possibilité qu'un fichier de sortie existe déjà.
Les init containers ont tous les champs d'un conteneur d'application.
Cependant, Kubernetes interdit l'utilisation de readinessProbe
parce que les init containers
ne peuvent pas définir une "readiness" distincte de la complétion. Ceci est appliqué lors de la validation.
L'utilisation de activeDeadlineSeconds
sur le Pod et livenessProbe
sur le conteneur
permet d'empêcher les init containers d'échouer tout le temps.
La deadline active inclut les init containers.
Le nom de chaque application et init container dans un Pod doit être unique; une erreur de validation est générée pour tout conteneur partageant un nom avec un autre.
Ressources
Étant donné l'ordonnancement et l'exécution des init containers, les règles suivantes s'appliquent pour l'utilisation des ressources :
- La plus haute requête ou limite particulière de ressource définie pour tous les init containers est la limite/requête d'initialisation effective
- La limite/requête effective d'un Pod pour une ressource est la plus haute parmis :
- la somme de toutes les requêtes/limites des conteneurs d'application pour une ressource
- la limite/requête d'initialisation effective pour une ressource
- Le Scheduling est effectué sur la base des requêtes/limites effectives, ce qui signifie que les init containers peuvent réserver des ressources pour l'initialisation qui ne sont pas utilisées durant le cycle de vie du Pod.
- La QoS (qualité de service) tierce de la QoS tierce effective d'un Pod est la QoS tierce aussi bien pour les init containers que pour les conteneurs d'application.
Les quotas et limites sont appliqués sur la base de la requête/limite effective d'un Pod.
Les groupes de contrôle au niveau du Pod (cgroups) sont basés sur la requête/limite effective de Pod, la même que celle du scheduler.
Raisons du redémarrage d'un Pod
Un Pod peut redémarrer, ce qui cause la ré-exécution des init containers, pour les raisons suivantes :
- Un utilisateur met à jour les spécifications du Pod, ce qui cause le changement de l'image de l'init container. Tout changement à l'image du init container redémarre le Pod. Les changements au conteneur d'application entraînent seulement le redémarrage du conteneur d'application.
- Le conteneur d'infrastructure Pod est redémarré. Ceci est peu commun et serait effectué par une personne ayant un accès root aux nœuds.
- Tous les conteneurs dans un Pod sont terminés tandis que
restartPolicy
est configurée à "Always", ce qui force le redémarrage, et l'enregistrement de complétion du init container a été perdu à cause d'une opération de garbage collection (récupération de mémoire).
A suivre
- Lire à propos de la création d'un Pod ayant un init container
- Apprendre à debugger les init containers