Aller au contenu

Déboguer avec les Ephemeral Containers#

Note

La fonctionnalité est marquée stable à partir de la version 1.25 de Kubernetes. Cependant, elle est déjà disponible pour les versions antérieures.

Cas d'usage#

Lorsqu'il faut "entrer dans un container", la méthode habituelle est :

kubectl -n <namespace> exec -it <pod> -c <container> -- sh

Il est possible d'utiliser bash s'il est disponible dans le container.

Cependant, certaines images ne contiennent que le binaire à exécuter et la méthode ci-dessus ne fonctionne pas, faute de shell à lancer.

C'est dans ce cas que l'on peut utiliser un Ephemeral Container.

Fonctionnement#

IMAGE=alpine:latest  # ou busybox:latest ou ce que vous voulez, avec un shell
NAMESPACE=xxx
POD=xxx
TARGETCONTAINER=xxx

kubectl -n "${NAMESPACE}" debug -it --image="${IMAGE}" --profile=general --target="${TARGETCONTAINER}" "${POD}" -- sh

La commande ci-dessus ajoute un Ephemeral Container dans le pod ciblé :

  • il faut indiquer le nom du pod cible ${POD} et son namespace ${NAMESPACE} ;
  • le container éphémère aura accès au container ${TARGETCONTAINER} en particulier pour les commande ps, ls / ...
  • l'image utilisée dans le container éphémère est ${IMAGE}. Elle devrait donc être légère (par exemple, busybox:latest) mais éventuellement aussi outillée (dans ce cas, alpine:latest permet d'ajouter facilement de l'outillage avec apk add).

Cette commande donne accès à un shell. Dans cet environnement, il faut connaître certaines particularités :

  • la racine du container est celle de l'image ${IMAGE} choisie ci-dessus ;
  • la racine du container cible est accessible (cf ci-dessous) ;
  • le namespace (au sens Linux du terme) des process est commun aux deux containers, ce qui donne accès aux process du container cible.
    ps -ef
    
    Cette commande liste donc les process des deux containers.

Accès au filesystem du container cible#

Pour accéder au filesystem du container cible, on utilise cette astuce : le lien /proc/<pid>/root pointe vers la racine du filesystem d'un process. En prenant le PID d'un process du container cible, on a ainsi accès à son filesystem.

Voici comment faire :

ps -ef

En général, le PID 1 est celui du process du container cible. Sinon vous changerez le 1 par le PID adéquat ci-dessous.

cd /proc/1/root
ls

Cela affiche la racine du filesystem du container cible.

Note

il est possible de se déplacer dans l'arborescence du filesystem du container cible. Les volumes sont montés dans leurs points de montage comme attendu. Il n'y a pas lieu de les remonter par ailleurs.

Quitter une session de debug#

En quittant le shell, on quitte la session de debug.

Cela a pour impact de terminer le container éphémère. Il ne sera donc pas possible d'y revenir ultérieurement. Une nouvelle session de debug avec kubectl debug créera un nouveau container éphémère.

Supprimer un container éphémère#

Comme tout container, il n'est pas possible de supprimer un container éphémère.

La seule façon de se débarasser des containers éphémères est de supprimer le pod (kubectl delete pod).

Lister les containers éphémères#

Certains outils n'affichent pas les containers éphémères (en particulier kubectl describe pod ne les affiche pas).

Pour lister les containers éphémères, il faut lancer kubectl get pod -o yaml.

Créer un container éphémère avec un volume monté#

Il n'est pas possible de monter un volume avec kubectl debug. Il faut patcher le pod pour ajouter le container éphémère avec le volume monté.

Nous utilisons la méthode de kubectl proxy / curl :

kubectl proxy

IMAGE=alpine:latest  # ou busybox:latest ou ce que vous voulez, avec un shell
NAMESPACE=xxx
POD=xxx
TARGETCONTAINER=xxx
CONTAINERNAME=debug1 # à changer si ce container éphémère existe déjà

curl "http://localhost:8001/api/v1/namespaces/${NAMESPACE}/pods/${POD}/ephemeralcontainers" \
  -X PATCH \
  -H 'Content-Type: application/strategic-merge-patch+json' \
  -d '
{
    "spec":
    {
        "ephemeralContainers":
        [
            {
                "name": "'"${CONTAINERNAME}"'",
                "command": ["sh"],
                "image": "'"${IMAGE}"'",
                "targetContainerName": "'"${TARGETCONTAINER}"'",
                "stdin": true,
                "tty": true,
                "volumeMounts": [{
                    "mountPath": "<mount path>",
                    "name": "<name>"
                }]
            }
        ]
    }
}'

Puis on se connecte au container :

kubectl attach "${POD}" -c "${CONTAINERNAME}" -ti

La suite des opération est similaire à celle de kubectl debug.