La CLI de Kubernetes propose une commande parfois bien pratique qui permet d’attendre des évènements sur son cluster : la commande kubectl wait
.
Celle ci permet de surveiller deux choses :
- Qu’une ressource soit supprimée
- Que la condition d’une ressource rencontre un certain état
Attente de suppression d’une ressource : kubectl wait --for=delete
On utilisera l’option --for=delete
de la manière suivante, par exemple sur un pod :
$ kubectl wait pod/rabbitmq-7575b7f589-dsdhl --for=delete --timeout=-1s
pod/rabbitmq-7575b7f589-dsdhl condition met
Cette option s’utilise sur tout type de ressources Kubernetes.
A noter : par défaut le timeout est définit à 30s, on utilise ici la valeur “-1s” qui équivaut au timeout maximum de 1 semaine (il n’est pas possible de désactiver le timeout).
Attente d’une condition : kubectl wait --for=condition
Les conditions sont rattachées à certains types de ressources. En voici la liste pour la version 1.14 de Kubernetes :
- nodes
- persistentvolumeclaims
- pods
- replicationcontrollers
- customresourcedefinitions
- apiservices
- daemonsets
- deployments
- replicasets
- statefulsets
- jobs
- daemonsets
- deployments
- replicasets
- nodes
- pods
Chacune de ces ressources possède ensuite un certain nombre de conditions. Par exemple, les pods ont les conditions Initialized, Ready, ContainersReady, PodScheduled et Unschedulable alors que les deployments ont seulement la condition Available.
L’exemple suivant liste l’état des conditions actuelles pour un pod :
$ kubectl get pod/rabbitmq-7575b7f589-dsdhl -o "go-template={{range .status.conditions}}{{printf \"%s = %s\n\" .type .status}}{{end}}"
Initialized = True
Ready = True
ContainersReady = True
PodScheduled = True
Attendre qu’un pod soit ready : kubectl wait --for=condition=Ready
Pour attendre que notre pod Kubernetes soit prêt, on utilisera la commande kubectl wait suivante :
$ kubectl -n nxs-r1-prod wait pod/rabbitmq-7575b7f589-dsdhl --for=condition=Ready --timeout=-1s
pod/rabbitmq-7575b7f589-dsdhl condition met
Le cas des services
Comme vous pouvez le constater dans le listing plus haut, les services ne possèdent malheureusement pas de condition. Cela pourrait pourtant être très pratique pour vérifier qu’au moins un endpoint existe pour le service en question (et donc qu’au moins un pod soit prêt à servir les requêtes des utilisateurs grace aux health checks).
Il est possible de surveiller les pods associés (ou mieux, les deployments) mais une race condition existe entre le moment où le pod est déclaré prêt à l’emploit et celui où l'Endpoints Controller du Controller Manager créé effectivement l'endpoint associé.
Une solution à ce problème consiste à poller de manière active l’API de Kubernetes pour surveiller la création d’un endpoint en utilisant le one-liner bash suivant :
until [[ $(kubectl get endpoints/rabbitmq -o=jsonpath='{.subsets[*].addresses[*].ip}') ]]; do sleep 5; done
Une solution alternative consisterait à poller de la même manière le service cible directement et à attendre que celui-ci soit disponible, la commande à employer dépendra dans ce cas du service utilisé.
Ordonnancer avec les initContainers
Les pods Kubernetes peuvent exécuter un certain nombre d'initContainers. Ceux-ci sont exécutés de manière “synchrone” et dans l’ordre de leur définition dans la spécification du pod et ce, avant l’exécution des containers “classiques”. Cela permet par exemple d’initialiser une base de données, de préparer un volume, de rendre des templates de configuration (voir Konfplate, un de nos projets sur Github).
Associés à des initContainers, la commande wait permet de bloquer l’exécution de certains pods en attendant que certaines conditions soit rencontrées (par exemple, l’achèvement d’un Job) et donc d’ordonnancer basiquement l’exécution des ressources sur son cluster Kubernetes.
Ne ratez pas nos prochains articles DevOps et Cloud Native! Suivez Enix sur Twitter!