1 - Exécuter une application stateless avec un Déploiement

Cette page montre comment exécuter une application en utilisant une resource Deployment (déploiement) dans Kubernetes.

Objectifs

  • Créer un déploiement nginx.
  • Utiliser kubectl pour afficher des informations sur le déploiement.
  • Mettre à jour le déploiement.

Pré-requis

Vous devez disposer d'un cluster Kubernetes et l'outil de ligne de commande kubectl doit être configuré pour communiquer avec votre cluster. Si vous ne possédez pas déjà de cluster, vous pouvez en créer un en utilisant Minikube, ou vous pouvez utiliser l'un de ces environnements Kubernetes:

Votre serveur Kubernetes doit être au moins à la version v1.9. Pour consulter la version, entrez kubectl version.

Création et exploration d'un déploiement nginx

Vous pouvez exécuter une application en créant un objet déploiement Kubernetes, et vous pouvez décrire un déploiement dans un fichier YAML. Par exemple, ce fichier YAML décrit un déploiement qui exécute l'image Docker nginx:1.14.2 :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
  1. Créez un déploiement basé sur ce fichier YAML:

    kubectl apply -f https://k8s.io/examples/application/deployment.yaml
    
  2. Affichez les informations du déploiement:

    kubectl describe deployment nginx-deployment
    

    Le résultat sera similaire à ceci :

    Name:     nginx-deployment
    Namespace:    default
    CreationTimestamp:  Tue, 30 Aug 2016 18:11:37 -0700
    Labels:     app=nginx
    Annotations:    deployment.kubernetes.io/revision=1
    Selector:   app=nginx
    Replicas:   2 desired | 2 updated | 2 total | 2 available | 0 unavailable
    StrategyType:   RollingUpdate
    MinReadySeconds:  0
    RollingUpdateStrategy:  1 max unavailable, 1 max surge
    Pod Template:
      Labels:       app=nginx
      Containers:
        nginx:
        Image:              nginx:1.14.2
        Port:               80/TCP
        Environment:        <none>
        Mounts:             <none>
      Volumes:              <none>
    Conditions:
      Type          Status  Reason
      ----          ------  ------
      Available     True    MinimumReplicasAvailable
      Progressing   True    NewReplicaSetAvailable
    OldReplicaSets:   <none>
    NewReplicaSet:    nginx-deployment-1771418926 (2/2 replicas created)
    No events.
    
  3. Affichez les Pods créés par le déploiement :

    kubectl get pods -l app=nginx
    

    Le résultat sera similaire à ceci :

    NAME                                READY     STATUS    RESTARTS   AGE
    nginx-deployment-1771418926-7o5ns   1/1       Running   0          16h
    nginx-deployment-1771418926-r18az   1/1       Running   0          16h
    
  4. Affichez les informations d'un Pod :

    kubectl describe pod <pod-name>
    

    est le nom d'un de vos Pods.

Mise à jour du déploiement

Vous pouvez mettre à jour le déploiement en appliquant un nouveau fichier YAML. Ce fichier YAML indique que le déploiement doit être mis à jour pour utiliser nginx 1.16.1.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # Update the version of nginx from 1.14.2 to 1.16.1
        ports:
        - containerPort: 80
  1. Appliquez le nouveau fichier YAML :

    kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
    
  2. Regardez le déploiement créer de nouveaux pods et supprimer les anciens :

    kubectl get pods -l app=nginx
    

Mise à l'échelle de l'application en augmentant le nombre de réplicas

Vous pouvez augmenter le nombre de pods dans votre déploiement en appliquant un nouveau fichier YAML. Ce fichier YAML définit replicas à 4, ce qui spécifie que le déploiement devrait avoir quatre pods :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 4 # Update the replicas from 2 to 4
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1
        ports:
        - containerPort: 80
  1. Appliquez le nouveau fichier YAML :

    kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml
    
  2. Vérifiez que le déploiement a quatre pods:

    kubectl get pods -l app=nginx
    

    Le résultat sera similaire à ceci :

    NAME                               READY     STATUS    RESTARTS   AGE
    nginx-deployment-148880595-4zdqq   1/1       Running   0          25s
    nginx-deployment-148880595-6zgi1   1/1       Running   0          25s
    nginx-deployment-148880595-fxcez   1/1       Running   0          2m
    nginx-deployment-148880595-rwovn   1/1       Running   0          2m
    

Suppression d'un déploiement

Supprimez le déploiement avec son nom :

kubectl delete deployment nginx-deployment

ReplicationControllers -- méthode obsolète

La méthode préférée pour créer une application répliquée consiste à utiliser un déploiement, qui utilise à son tour un ReplicaSet. Avant que le déploiement et le ReplicaSet ne soient ajoutés à Kubernetes, les applications répliquées étaient configurées à l'aide d'un ReplicationController.

A suivre

2 - Exécutez une application stateful mono-instance

Cette page montre comment exécuter une application mono-instance, avec gestion d'état (stateful) dans Kubernetes en utilisant un PersistentVolume et un Deployment. L'application utilisée est MySQL.

Objectifs

  • Créer un PersistentVolume en référençant un disque dans votre environnement.
  • Créer un déploiement MySQL.
  • Exposer MySQL à d'autres pods dans le cluster sous un nom DNS connu.

Pré-requis

  • Vous devez disposer d'un cluster Kubernetes et l'outil de ligne de commande kubectl doit être configuré pour communiquer avec votre cluster. Si vous ne possédez pas déjà de cluster, vous pouvez en créer un en utilisant Minikube, ou vous pouvez utiliser l'un de ces environnements Kubernetes:

    Pour consulter la version, entrez kubectl version.

  • Vous devez disposer soit d'un fournisseur PersistentVolume dynamique avec une valeur par défaut StorageClass, soit préparer un PersistentVolumes statique pour satisfaire les PersistentVolumeClaims utilisés ici.

Déployer MySQL

Vous pouvez exécuter une application stateful en créant un Deployment Kubernetes et en le connectant à un PersistentVolume existant à l'aide d'un PersistentVolumeClaim. Par exemple, ce fichier YAML décrit un Deployment qui exécute MySQL et référence le PersistentVolumeClaim. Le fichier définit un point de montage pour /var/lib/mysql, puis crée un PersistentVolumeClaim qui réclame un volume de 20G. Cette demande est satisfaite par n'importe quel volume existant qui répond aux exigences, ou par un provisionneur dynamique.

Remarque: le mot de passe MySQL est défini dans le fichier de configuration YAML, ce qui n'est pas sécurisé. Voir les secrets Kubernetes pour une approche sécurisée.

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
  clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

  1. Déployez le PV et le PVC du fichier YAML:

    kubectl apply -f https://k8s.io/examples/application/mysql/mysql-pv.yaml
    
  2. Déployez les resources du fichier YAML:

    kubectl apply -f https://k8s.io/examples/application/mysql/mysql-deployment.yaml
    
  3. Affichez les informations liées au Deployment:

    kubectl describe deployment mysql
    

    Le résultat sera similaire à ceci:

    Name:                 mysql
    Namespace:            default
    CreationTimestamp:    Tue, 01 Nov 2016 11:18:45 -0700
    Labels:               app=mysql
    Annotations:          deployment.kubernetes.io/revision=1
    Selector:             app=mysql
    Replicas:             1 desired | 1 updated | 1 total | 0 available | 1 unavailable
    StrategyType:         Recreate
    MinReadySeconds:      0
    Pod Template:
      Labels:       app=mysql
      Containers:
        mysql:
        Image:      mysql:5.6
        Port:       3306/TCP
        Environment:
          MYSQL_ROOT_PASSWORD:      password
        Mounts:
          /var/lib/mysql from mysql-persistent-storage (rw)
      Volumes:
        mysql-persistent-storage:
        Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
        ClaimName:  mysql-pv-claim
        ReadOnly:   false
    Conditions:
      Type          Status  Reason
      ----          ------  ------
      Available     False   MinimumReplicasUnavailable
      Progressing   True    ReplicaSetUpdated
    OldReplicaSets:       <none>
    NewReplicaSet:        mysql-63082529 (1/1 replicas created)
    Events:
      FirstSeen    LastSeen    Count    From                SubobjectPath    Type        Reason            Message
      ---------    --------    -----    ----                -------------    --------    ------            -------
      33s          33s         1        {deployment-controller }             Normal      ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
    
  4. Listez les Pods créés par le Deployment:

    kubectl get pods -l app=mysql
    

    Le résultat sera similaire à ceci:

    NAME                   READY     STATUS    RESTARTS   AGE
    mysql-63082529-2z3ki   1/1       Running   0          3m
    
  5. Inspectez le PersistentVolumeClaim:

    kubectl describe pvc mysql-pv-claim
    

    Le résultat sera similaire à ceci:

    Name:         mysql-pv-claim
    Namespace:    default
    StorageClass:
    Status:       Bound
    Volume:       mysql-pv-volume
    Labels:       <none>
    Annotations:    pv.kubernetes.io/bind-completed=yes
                    pv.kubernetes.io/bound-by-controller=yes
    Capacity:     20Gi
    Access Modes: RWO
    Events:       <none>
    

Accès à l'instance MySQL

Le fichier YAML précédent crée un service qui permet à d'autres pods dans le cluster d'accéder à la base de données. L'option clusterIP: None du service permet à son nom DNS de résoudre directement l'adresse IP du pod. C'est optimal lorsque vous n'avez qu'un seul pod derrière un service et que vous n'avez pas l'intention d'augmenter le nombre de pods.

Exécutez un client MySQL pour vous connecter au serveur :

kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword

Cette commande crée un nouveau pod dans le cluster exécutant un client MySQL et le connecte au serveur via le Service. Si la connexion réussit, cela signifie que votre base de données MySQL est opérationnelle.

Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.

mysql>

Mises à jour

L'image ou toute autre partie du Deployment peut être mise à jour comme d'habitude avec la commande kubectl apply. Voici quelques précautions spécifiques aux applications stateful :

  • Ne pas mettre à l'échelle l'application. Cette configuration est conçue pour des applications à une seule instance seulement. Le PersistentVolume sous-jacent ne peut être monté que sur un Pod. Pour les applications stateful clusterisées, consultez la documentation sur les StatefulSets.
  • Utilisez strategy: type: Recreate dans le fichier de configuration YAML du Deployment. Cela indique à Kubernetes de ne pas utiliser des mises à jour continues. Les mises à jour en roulement ne fonctionneront pas, car vous ne pouvez pas avoir plus d'un Pod en cours d'exécution à la fois. La stratégie Recreate arrêtera le premier pod avant d'en créer un nouveau avec la configuration mise à jour.

Suppression d'un déploiement

Supprimez les ressources déployées avec leur noms:

kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv-volume

Si vous avez provisionné manuellement un PersistentVolume, vous devrez également le supprimer manuellement, ainsi que libérer la ressource sous-jacente. Si vous avez utilisé un provisionneur dynamique, il supprimera automatiquement le PersistentVolume lorsqu'il verra que vous avez supprimé le PersistentVolumeClaim. Certains provisionneurs dynamiques (comme ceux pour EBS et PD) libèrent également la ressource sous-jacente lors de la suppression du PersistentVolume.

A suivre

3 - Accéder à l'API de Kubernetes depuis un Pod

Ce guide explique comment accéder à l'API de Kubernetes depuis un Pod.

Pré-requis

Vous devez disposer d'un cluster Kubernetes et l'outil de ligne de commande kubectl doit être configuré pour communiquer avec votre cluster. Si vous ne possédez pas déjà de cluster, vous pouvez en créer un en utilisant Minikube, ou vous pouvez utiliser l'un de ces environnements Kubernetes:

Accéder à l'API depuis un Pod

Lorsque l'on veut accéder à l'API depuis un Pod, localiser et s'authentifier auprès du serveur API se passe différement que dans le cas d'un client externe.

Le moyen le plus simple pour interagir avec l'API Kubernetes depuis un Pod est d'utiliser l'une des librairies clientes officielles. Ces bibliothèques peuvent automatiquement découvrir le serveur API et s'authentifier.

Utilisation des clients officiels

Depuis un Pod, les moyens recommandés pour se connecter à l'API Kubernetes sont:

  • Pour un client Go, utilisez la bibliothèque client officielle Go. La fonction rest.InClusterConfig() gère automatiquement la découverte de l'hôte API et l'authentification. Voir un exemple ici.

  • Pour un client Python, utilisez la bibliothèque client officielle Python. La fonction config.load_incluster_config() gère automatiquement la découverte de l'hôte API et l'authentification. Voir un exemple ici.

  • Il existe d'autres bibliothèques disponibles, vous pouvez vous référer à la page Bibliothèques clientes.

Dans tous les cas, les informations d'identification du compte de service du Pod seront utilisées pour communiquer avec le serveur API.

Accès direct à l'API REST

En s'exécutant dans un Pod, votre conteneur peut créer une URL HTTPS pour le serveur API Kubernetes en récupérant les variables d'environnement KUBERNETES_SERVICE_HOST et KUBERNETES_SERVICE_PORT_HTTPS. L'adresse du serveur API dans le cluster est également publiée dans un Service nommé kubernetes dans le namespace default afin que les pods puissent référencer kubernetes.default.svc comme nom DNS pour le serveur API.

La manière recommandée pour s'authentifier auprès du serveur API est d'utiliser les identifiants d'un compte de service. Par défaut, un Pod est associé à un compte de service, et un identifiant pour ce compte de service est placé dans le système de fichiers de chaque conteneur dans ce Pod, dans /var/run/secrets/kubernetes.io/serviceaccount/token.

Si disponible, un lot de certificats est placé dans le système de fichiers de chaque conteneur dans /var/run/secrets/kubernetes.io/serviceaccount/ca.crt et doit être utilisé pour vérifier le certificat du serveur API.

Enfin, le namespace courant dans lequel est déployé le Pod est placé dans un fichier /var/run/secrets/kubernetes.io/serviceaccount/namespace dans chaque container.

Avec utilisation du proxy kubectl

Si vous souhaitez interroger l'API sans utiliser de bibliothèque client officielle, vous pouvez exécuter kubectl proxy en tant que commande d'un nouveau conteneur sidecar dans le Pod. De cette manière, kubectl proxy s'authentifiera auprès de l'API et l'exposera sur l'interface localhost du Pod, de sorte que les autres conteneurs dans le Pod puissent l'utiliser directement.

Sans utiliser de proxy

Il est possible d'éviter l'utilisation du proxy kubectl en passant directement les informations d'authentification au serveur API. Le certificat interne sécurise la connexion.

# Pointe vers le nom d'hôte interne du serveur API.
APISERVER=https://kubernetes.default.svc

# Chemin du token pour le compte de service
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount

# Lire le namespace du Pod
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)

# Lire le token du compte de service
TOKEN=$(cat ${SERVICEACCOUNT}/token)

# Référence l'authorité de certificat interne 
CACERT=${SERVICEACCOUNT}/ca.crt

# Accéder à l'API avec le token
curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api

Le résultat sera similaire à:

{
  "kind": "APIVersions",
  "versions": ["v1"],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.1.149:443"
    }
  ]
}