[Kubernetes] Empêcher l'arrêt d'un Pod pendant l'upgrade
Quand nous réalisons une mise à jours d’un composant sur kubernetes
(deployment
, statefulset
, etc.) le contrôleur de pod va supprimer au
fur et à mesure nos anciens pod pour en créer de nouveau avec notre
nouvelle configuration. La stratégie de déploiement par défaut de k8s
est pensé pour réduire les temps d’indisponibilité et toujours laisser
un maximum de pod en ligne. Ainsi par exemple la stratégie de
déploiement par défaut d’un deployment
est RollingUpdate
1
ce qui se traduit, lors de l’upgrade, par un arrêt et une suppression
d’une partie des pods, et en parallèle la recréation de ceux-ci dans la
nouvelle version. Ces actions se répètent jusqu'à ce que tout les pod soit
à jours. Les autres contrôleurs de pod ont leurs propres stratégies aussi.
Comment prendre en compte l'état fonctionnel du pod?
Si le modèle évoqué ci-dessus fonctionne bien il n’en reste pas moins
assez basique. En effet que se passe-t-il quand vous avez un traitement
long (conversion vidéo, consommation d’un flux live, etc.) en cours de
fonctionnement? La réponse n’est malheureusement pas celle que nous
attendons: Kubernetes
va, par défaut, arrêter le pod
, peut être même de
manière violente (SIGKILL).
Fonctionnement de l’arrêt d’un pod
L’arrêt d’un pod par kubernetes
se découpe en plusieurs étapes:
- Exécution du
hook
:preStop
- Envoi d’un signal
SIGTERM
. - Si le pod n’est pas à l’arrêt après un certain temps envoi d’un signal
SIGKILL
.
La première étape de tout arrêt de pod par k8s
est d’exécuter la
commande de preStop
. Celle-ci est exécutée avant l’envoi du signal
d’arrêt et est bloquante. Ceci signifie que nous allons pouvoir nous en
servir pour dire à kubernetes
que nous souhaitons attendre avant
l’arrêt du pod. Il est tout de même à noter un point important: Ce hook
de preStop
est exécuté aussi bien sur les arrêts voulus (mise à jours
d’un deployment
) que sur les arrêts de type erreur (livenessProbe,
contention de ressources, etc.)2.
Quand kubernetes
exécute ce hook
il passe l'état du pod à
Terminating
.
Kubernetes
applique une protection sur ces scripts de preStop
et il
n’est pas possible de le faire attendre indéfiniment avant qu’il n’envoie
un signal d’arrêt. C’est le rôle de la directive de configuration
terminationGracePeriodSeconds
que de fixer la durée maximale d’exécution
de ce script. La valeur par défaut est de 30 secondes et sa
configuration est globale au pod (donc à tous les containers). 3
Une fois ce hook
exécuté, kubernetes
va envoyer un signal SIGTERM
à tous les processus qui ont le pid 1 de chaque container pour leur
demander de s’arrêter. De la même manière qu’avec le hook
précédent il
est possible de catcher ce signal dans le code de l’application pour
bloquer l’arrêt. La valeur de la directive
terminationGracePeriodSeconds
est là aussi respecté et le temps de
blocage de l’arrêt ne peut pas excéder cette valeur.
Si après la période de temps définit par terminationGracePeriodSeconds
les processus du pod ne sont toujours pas à l’arrêt, kubernetes
enverra
un signal SIGTERM
mettant fin à ceux-ci.
Note: La durée définit par terminationGracePeriodSeconds
s’entend
globalement que ce soit pour le hook
pour le SIGTERM
. Par exemple
pour une valeur de terminationGracePeriodSeconds
à 10minutes, si le hook
prend 5 minutes pour s’exécuter il ne restera que 5 minutes au container
pour exécuter son code lié à l'évènement SIGTERM
.
Configuration
La configuration de ces éléments est assez simple au niveau des spec
de nos pods
.
apiVersion: apps/v1
kind: Deployment
...
spec:
...
template:
...
spec:
containers:
- name: test
image: test:latest
lifecycle:
preStop:
exec:
command:
- /bin/ash
- /usr/local/bin/can-stop.sh
terminationGracePeriodSeconds: 600
...
Il existe plusieurs handler pour les hook
de preStop comme pour les
probes
4. À savoir:
- exec
- httpGet
- tcpSocket
Conclusion
Au final il existe deux méthodes pour réaliser une mise en pause du processus d’arrêt de kubernetes : les hook ou l’interception du signal SIGTERM. Le hook on l’avantage d'être plus simple à mettre en place pour un admin qui n’a pas accès au code source de l’application (un simple script bash suffit) mais l’interception du signal SIGTERM n’est pas à mettre de côté tout de même. Celui-ci laisse la liberté aux développeurs de gérer au mieux l’arrêt de leur application (pour par exemple fermer des connexions, sauvegarder un état, etc …).
-
https://kubernetes.io/fr/docs/concepts/workloads/controllers/deployment/#strat%C3%A9gie ↩︎
-
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks ↩︎
-
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution ↩︎
-
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#handler-v1-core ↩︎