Pods Kubernetes

Comprendre les Pods

Un Pod est le bloc de construction de base de Kubernetes--l'unité la plus petite et la plus simple dans le modèle d'objets de Kubernetes--que vous créez ou déployez. Un Pod représente un process en cours d'exécution dans votre cluster.

Un Pod encapsule un conteneur applicatif (ou, dans certains cas, plusieurs conteneurs), des ressources de stockage, une IP réseau unique, et des options qui contrôlent comment le ou les conteneurs doivent s'exécuter. Un Pod représente une unité de déploiement : une instance unique d'une application dans Kubernetes, qui peut consister soit en un unique conteneur soit en un petit nombre de conteneurs qui sont étroitement liés et qui partagent des ressources.

Docker est le runtime de conteneurs le plus courant utilisé dans un Pod Kubernetes, mais les Pods prennent également en charge d'autres runtimes de conteneurs.

Les Pods dans un cluster Kubernetes peuvent être utilisés de deux manières différentes :

  • les Pods exécutant un conteneur unique. Le modèle "un-conteneur-par-Pod" est le cas d'utilisation Kubernetes le plus courant ; dans ce cas, vous pouvez voir un Pod comme un wrapper autour d'un conteneur unique, et Kubernetes gère les Pods plutôt que directement les conteneurs.
  • les Pods exécutant plusieurs conteneurs devant travailler ensemble. Un Pod peut encapsuler une application composée de plusieurs conteneurs co-localisés qui sont étroitement liés et qui doivent partager des ressources. Ces conteneurs co-localisés pourraient former une unique unité de service cohérente--un conteneur servant des fichiers d'un volume partagé au public, alors qu'un conteneur "sidecar" séparé rafraîchit ou met à jour ces fichiers. Le Pod enveloppe ensemble ces conteneurs et ressources de stockage en une entité maniable de base.

Le Blog Kubernetes contient quelques informations supplémentaires sur les cas d'utilisation des Pods. Pour plus d'informations, voir :

Chaque Pod est destiné à exécuter une instance unique d'une application donnée. Si vous désirez mettre à l'échelle votre application horizontalement, (par ex., exécuter plusieurs instances), vous devez utiliser plusieurs Pods, un pour chaque instance. Dans Kubernetes, on parle généralement de réplication. Des Pods répliqués sont en général créés et gérés comme un groupe par une abstraction appelée Controller. Voir Pods et Controllers pour plus d'informations.

Les Pods gérant plusieurs conteneurs

Les Pods sont conçus pour supporter plusieurs processus coopérants (sous forme de conteneurs) qui forment une unité de service cohérente. Les conteneurs d'un même Pod sont automatiquement co-localisés et co-programmés sur la même machine physique ou virtuelle dans le cluster. Ces conteneurs peuvent partager des ressources et dépendances, communiquer entre eux, et coordonner le moment et la manière de leur arrêt.

Notez que grouper plusieurs conteneurs co-localisés et co-gérés dans un Pod unique est un cas d'utilisation relativement avancé. Vous devriez utiliser ce "pattern" seulement dans des instances spécifiques dans lesquelles vos conteneurs sont étroitement liés. Par exemple, vous pourriez avoir un conteneur qui agit comme un serveur web pour des fichiers contenus dans un volume partagé, et un conteneur "sidecar" séparé qui met à jour ces fichiers depuis une source externe, comme dans le diagramme suivant :

Pod Kubernetes
Figure 11 : Pod Kubernetes

On trouvera des explications sur ces patterns composites dans la présentation The Distributed System ToolKit: Patterns for Composite Containers.

Un exemple de ce pattern "sidecar" se trouve dans le repo Git https://github.com/kubernetes/git-sync/tree/master/demo avec l'application Git-Sync.

Ressources partagées par les Pods

Les Pods fournissent deux types de ressources partagées pour leurs conteneurs : réseau et stockage.

Réseau

Chaque Pod se voit assigner une adresse IP unique. Tous les conteneurs d'un Pod partagent le même "namespace" réseau, y compris l'adresse IP et les ports réseau. Les conteneurs à l'intérieur d'un Pod peuvent communiquer entre eux en utilisant localhost. Lorsque les conteneurs dans un Pod communiquent avec des entités en dehors du Pod, ils doivent coordonner la manière dont ils utilisent les ressources réseau partagées (comme les ports).

Stockage

Un Pod peut spécifier un ensemble de volumes de stockage partagés. Tous les conteneurs dans le Pod peuvent accéder aux volumes partagés, permettant à ces conteneurs de partager des données. Les volumes permettent aussi les données persistantes d'un Pod de survivre au cas où un des conteneurs doit être redémarré. Voir Volumes pour plus d'informations sur la façon dont Kubernetes implémente le stockage partagé dans un Pod.

Travailler avec des Pods

Vous aurez rarement à créer directement des Pods individuels dans Kubernetes--même des Pods à un seul conteneur. Ceci est dû au fait que les Pods sont conçus comme des entités relativement éphémères et jetables. Lorsqu'un Pod est créé (directement par vous ou indirectement par un Controller), il est programmé pour s'exécuter sur un Nœud dans votre cluster. Le Pod reste sur ce Nœud jusqu'à ce que le process se termine, l'objet pod soit supprimé, le pod soit expulsé par manque de ressources, ou le Nœud soit en échec.

Redémarrer un conteneur dans un Pod ne doit pas être confondu avec redémarrer le Pod. Le Pod lui-même ne s'exécute pas, il est un environnement dans lequel les conteneurs s'exécutent, et persiste jusqu'à ce qu'il soit supprimé.

Les Pods ne se guérissent pas par eux-mêmes. Si un Pod est programmé sur un Nœud qui échoue, ou si l'opération de programmation elle-même échoue, le Pod est supprimé ; de plus, un Pod ne survivra pas à une expulsion due à un manque de ressources ou une mise en maintenance du Nœud. Kubernetes utilise une abstraction de plus haut niveau, appelée un Controller, qui s'occupe de gérer les instances de Pods (éphémères). Ainsi, même s'il est possible d'utiliser des Pods directement, il est beaucoup plus courant dans Kubernetes de gérer vos Pods en utilisant un Controller. On developpera plus loin la façon dont Kubernetes utilise des Controllers pour implémenter la mise à l'échelle et la guérison des Pods.

Pods et Controllers

Un Controller peut créer et gérer plusieurs Pods pour vous, s'occupant de la réplication et du déploiement et fournissant des capacités d'auto-guérison au niveau du cluster. Par exemple, si un Nœud échoue, le Controller peut automatiquement remplacer le Pod en programmant un remplaçant identique sur un Nœud différent.

Quelques exemples de Controllers qui contiennent un ou plusieurs pods :

En général, les Controllers utilisent des Templates de Pod que vous lui fournissez pour créer les Pods dont il est responsable.

Templates de Pod

Les Templates de Pod sont des spécifications de pod qui sont inclus dans d'autres objets, comme les Replication Controllers, Jobs, et DaemonSets. Les Controllers utilisent les Templates de Pod pour créer réellement les pods.

L'exemple ci-dessous est un manifeste simple pour un Pod d'un conteneur affichant un message.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

Plutôt que de spécifier tous les états désirés courants de tous les réplicas, les templates de pod sont comme des emporte-pièces. Une fois qu'une pièce a été coupée, la pièce n'a plus de relation avec l'outil. Il n'y a pas de lien qui persiste dans le temps entre le template et le pod. Un changement à venir dans le template ou même le changement pour un nouveau template n'a pas d'effet direct sur les pods déjà créés. De manière similaire, les pods créés par un replication controller peuvent par la suite être modifiés directement. C'est en contraste délibéré avec les pods, qui spécifient l'état désiré courant de tous les conteneurs appartenant au pod. Cette approche simplifie radicalement la sémantique système et augmente la flexibilité de la primitive.

Créer un Pod qui fait fonctionner deux conteneurs

Dans cet exercice, vous créez un pod qui exécute deux conteneurs. Les deux conteneurs partagent un Volume qu'ils peuvent utiliser pour communiquer. Voici le fichier de configuration du Pod :

Fichier pods/two-container-pod.yaml.

apiVersion: v1
kind: Pod
metadata:
  name: two-containers
spec:

  restartPolicy: Never

  volumes:
  - name: shared-data
    emptyDir: {}

  containers:

  - name: nginx-container
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html

  - name: debian-container
    image: debian
    volumeMounts:
    - name: shared-data
      mountPath: /pod-data
    command: ["/bin/sh"]
    args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]

Dans le fichier de configuration, vous pouvez voir que le Pod a un Volume nommé shared-data.

Le premier conteneur répertorié dans le fichier de configuration exécute un serveur nginx. Le chemin de montage pour le volume partagé est /usr/share/nginx/html.

Le second conteneur est basé sur l'image debian, et a un chemin de montage /pod-data. Le deuxième conteneur exécute la commande suivante, puis se termine.

echo Hello from the debian container > /pod-data/index.html

Notez que le deuxième conteneur écrit le fichier index.html à la racine du serveur nginx.

Créez le pod et les deux conteneurs :

kubectl apply -f https://k8s.io/examples/pods/two-container-pod.yaml

Observez les informations sur le Pod et les conteneurs :

kubectl get pod two-containers --output=yaml

Voici une partie de la sortie :

apiVersion: v1
kind: Pod
metadata:
  ...
  name: two-containers
  namespace: default
  ...
spec:
  ...
  containerStatuses:

  - containerID: docker://c1d8abd1 ...
    image: debian
    ...
    lastState:
      terminated:
        ...
    name: debian-container
    ...

  - containerID: docker://96c1ff2c5bb ...
    image: nginx
    ...
    name: nginx-container
    ...
    state:
      running:
    ...

Vous pouvez voir que le conteneur debian s'est terminé et que le conteneur nginx est toujours en cours d'exécution.

Lancez un shell dans le conteneur Nginx :

kubectl exec -it two-containers -c nginx-container -- /bin/bash

Dans la console, veuillez vérifier que nginx fonctionne :

root@two-containers:/# apt-get update
root@two-containers:/# apt-get install curl procps
root@two-containers:/# ps aux

Vous devriez obtenir une sortie semblable à celle-ci :

USER       PID  ...  STAT START   TIME COMMAND
root         1  ...  Ss   21:12   0:00 nginx: master process nginx -g daemon off;

Le conteneur Debian a créé un fichier index.html dans le dossier principal de nginx. On peut envoyerune requête GET HTTP au serveur ngnix :

root@two-containers:/# curl localhost

La sortie nous montre bien qu'une page Web a été écrite par le conteneur Debian. The output shows that nginx serves a web page written by the debian container:

Hello from the debian container

La principale raison pour laquelle les Pods peuvent avoir à gérer plusieurs conteneurs est le support d'applications qui assistent une application primaire. Des exemples typiques sont :

  • Les "data pullers"
  • Les "data pushers"
  • Les proxies

Les applications secondaires et les applications primaires ont souvent besoin de communiquer entre elles. Cela se fait par le biais d'un système de fichiers partagés, comme le montre cet exercice, ou via l'interface réseau loopback, localhost. Un exemple de ce modèle est un ainsi qu'un programme d'aide qui interroge un dépôt Git pour les nouvelles mises à jour.

Le volume de cet exercice permet aux conteneurs de communiquer entre eux durant la vie du Pod. Si le Pod est supprimé et recréé, toutes les données stockées dans le volume partagé est perdu.

Sources