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 - Découverte de l'HorizontalPodAutoscaler

Un HorizontalPodAutoscaler (raccourci en HPA) met à jour automatiquement une ressource de charge de travail (comme un Deployment ou un StatefulSet), dans le but de faire évoluer automatiquement la charge de travail en fonction de la demande.

L'évolutivité horizontale signifie que la réponse à une augmentation de la charge est de déployer plus de Pods. Cela diffère de l'évolutivité verticale, qui pour Kubernetes signifierait attribuer plus de ressources (par exemple : mémoire ou CPU) aux Pods qui sont déjà en cours d'exécution pour la charge de travail.

Si la charge diminue et que le nombre de Pods est supérieur au minimum configuré, le HorizontalPodAutoscaler indique à la ressource de charge de travail (le Deployment, le StatefulSet ou une autre ressource similaire) de réduire son échelle (nombre de réplicas).

Ce document vous guide à travers un exemple d'activation de HorizontalPodAutoscaler pour gérer automatiquement l'échelle d'une application web. Cette charge de travail d'exemple est Apache httpd exécutant du code PHP.

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 1.23. Pour consulter la version, entrez kubectl version. Si vous utilisez une version plus ancienne de Kubernetes, consultez la version de la documentation correspondante (voir versions de documentation disponibles).

Pour suivre ce guide, vous devez également utiliser un cluster qui dispose d'un Metrics Server déployé et configuré.

Le Metrics Server Kubernetes collecte les métriques des ressources des kubelets de votre cluster et expose ces métriques via l'API Kubernetes, en utilisant un APIService pour ajouter de nouveaux types de ressources représentant les lectures de métriques.

Pour apprendre comment déployer le Metrics Server, consultez la documentation de metrics-server.

Exécutez et exposez le serveur php-apache

Pour démontrer un HorizontalPodAutoscaler, vous commencerez par démarrer un Deployment qui exécute un conteneur utilisant l'image hpa-example et l'expose en tant que Service en utilisant le manifeste suivant:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache

Pour créer les ressources, exécutez la commande suivante:

kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache created
service/php-apache created

Créer le HorizontalPodAutoscaler

Maintenant que le serveur est en cours d'exécution, créez l'autoscaler à l'aide de kubectl. Il existe une sous-commande kubectl autoscale, faisant partie de kubectl, qui vous aide à le faire.

Vous allez bientôt exécuter une commande qui crée un HorizontalPodAutoscaler qui maintient entre 1 et 10 réplicas des Pods contrôlés par le déploiement php-apache que vous avez créé lors de la première étape.

En parlant simplement, le HPA (contrôleur) augmentera ou diminuera le nombre de réplicas (en mettant à jour le déploiement) pour maintenir une utilisation CPU moyenne de 50% sur l'ensemble des Pods.

Ensuite, le déploiement met à jour le ReplicaSet - cela fait partie du fonctionnement de tous les déploiements dans Kubernetes - puis le ReplicaSet ajoute ou supprime des Pods en fonction des modifications apportées à son champ .spec.

Étant donné que chaque pod demande 200 milli-cores via kubectl run, cela signifie une utilisation CPU moyenne de 100 milli-cores. Consultez les détails de l'algorithme pour plus d'informations sur celui-ci.

Créez le HorizontalPodAutoscaler :

kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled

Vous pouvez visualiser le statut actuel du nouvel HorizontalPodAutoscaler avec la commande:

# Vous pouvez utiliser "hpa" ou "horizontalpodautoscaler"; les deux appelations fonctionnent.
kubectl get hpa

Le résultat sera similaire à celui-ci:

NAME         REFERENCE                     TARGET    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   0% / 50%  1         10        1          18s

(Si vous voyez d'autres HorizontalPodAutoscalers avec des noms différents, cela signifie qu'ils existaient déjà et ce n'est généralement pas un problème).

Veuillez noter que la consommation actuelle de CPU est de 0 % car il n'y a pas de clients envoyant des requêtes au serveur (la colonne TARGET montre la moyenne de tous les Pods contrôlés par le déploiement correspondant).

Augmenter la charge

Ensuite, voyons comment l'autoscaler réagit à une augmentation de la charge.

Pour cela, vous allez démarrer un autre Pod pour agir en tant que client. Le conteneur à l'intérieur du Pod client s'exécute dans une boucle infinie, envoyant des requêtes au service php-apache.

# Exécutez ceci dans un terminal séparé
# pour que la montée en charge s'applique pendant que vous continuez les étapes suivantes
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

Maintenant exécutez:

# Entrez Ctrl+C pour terminer lorsque c'est ok
kubectl get hpa php-apache --watch

Après environ une minute, vous devriez constater une augmentation de la charge CPU, comme ceci:

NAME         REFERENCE                     TARGET      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   305% / 50%  1         10        1          3m

en réponse, une augmentation du nombre de réplicas, comme ceci:

NAME         REFERENCE                     TARGET      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   305% / 50%  1         10        7          3m

Dans ce cas, la consommation CPU a atteint 305% de ce qui était demandé. Ainsi, le nombre de réplicas du Deployment a été augmenté à 7:

kubectl get deployment php-apache

Vous devriez voir le nombre de réplicas être égal à la valeur du HorizontalPodAutoscaler:

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   7/7      7           7           19m

Arrêt de la charge

Pour finir cet exemple, nous allons arrêter d'envoyer des requètes.

Dans le terminal utilisé pour créer le Pod qui exécute une image busybox, arrêtez la charge en entrant <Ctrl> +C.

Puis vérifiez le résultat après un temps d'attente:

# entrez Ctrl+C pour arrêter une fois la charge arretée
kubectl get hpa php-apache --watch

Le résultat sera similaire à:

NAME         REFERENCE                     TARGET       MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   0% / 50%     1         10        1          11m

et le nombre de réplicas du Deployment sera redescendu:

kubectl get deployment php-apache
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   1/1     1            1           27m

Une fois que la consommation CPU atteindra 0, le HPA ajustera automatiquement le nombre de réplicas à 1.

Cette étape peut prendre quelques minutes.

L'auto-ajustement basé sur des métriques multiples ou personnalisées

Vous pouvez ajouter de nouvelles métriques à utiliser pour l'auto-ajustement du Deployment php-apache en utilisant l'api autoscaling/v2.

Pour commencer, récupérez le YAML de votre HorizontalPodAutoscaler en format autoscaling/v2:

kubectl get hpa php-apache -o yaml > /tmp/hpa-v2.yaml

Ouvrez le fichier /tmp/hpa-v2.yaml avec votre éditeur, le YAML devrait ressembler à ceci:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
      current:
        averageUtilization: 0
        averageValue: 0

Veuillez noter que le champ targetCPUUtilizationPercentage a été remplacé par un tableau appelé metrics. La métrique d'utilisation du CPU est une métrique de ressource, car elle est représentée en pourcentage d'une ressource spécifiée sur les conteneurs de pod. Notez que vous pouvez spécifier d'autres métriques de ressource en plus du CPU. Par défaut, la seule autre métrique de ressource prise en charge est la mémoire. Ces ressources ne changent pas de nom d'un cluster à l'autre et devraient toujours être disponibles tant que l'API metrics.k8s.io est disponible.

Vous pouvez également spécifier des métriques de ressource en termes de valeurs directes, au lieu de pourcentages de la valeur demandée, en utilisant un target.type de AverageValue au lieu de Utilization, et en définissant le champ correspondant target.averageValue au lieu de target.averageUtilization.

Il existe deux autres types de métriques, tous deux considérés comme des métriques personnalisées: les métriques de pod et les métriques d'objet. Ces métriques peuvent avoir des noms spécifiques au cluster et nécessitent une configuration de la surveillance du cluster plus avancée.

Le premier de ces types de métriques alternatives est les métriques de pod. Ces métriques décrivent les pods et sont regroupées en moyenne sur l'ensemble des pods, puis comparées à une valeur cible pour déterminer le nombre de réplicas. Elles fonctionnent de manière similaire aux métriques de ressource, à la différence qu'elles prennent en charge seulement le type de target AverageValue.

Les métriques de pod sont spécifiées à l'aide d'une définition metric comme ceci:

type: Pods
pods:
  metric:
    name: packets-per-second
  target:
    type: AverageValue
    averageValue: 1k

Le deuxième type de métrique alternative est les métriques d'objet. Ces métriques décrivent un objet différent dans le même namespace, au lieu de décrire des Pods. Les métriques ne sont pas nécessairement récupérées à partir de l'objet mais le décrivent. Les métriques d'objet prennent en charge les types de target suivants: Value et AverageValue. Avec Value, la cible est comparée directement à la métrique renvoyée par l'API. Avec AverageValue, la valeur renvoyée par l'API de métriques personnalisées est divisée par le nombre de Pods avant d'être comparée à la cible. L'exemple suivant est la représentation YAML de la métrique requests-per-second.

type: Object
object:
  metric:
    name: requests-per-second
  describedObject:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k

Si vous fournissez plusieurs définitions de métriques similaires, le HorizontalPodAutoscaler examinera chaque métrique à tour de rôle. Il calculera les nombres de réplicas proposés pour chaque métrique, puis choisira celle avec le nombre de réplicas le plus élevé. Par exemple, si votre système de surveillance collecte des métriques sur le trafic réseau, vous pouvez mettre à jour la définition ci-dessus en utilisant kubectl edit pour qu'elle ressemble à ceci :

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      target:
        type: AverageValue
        averageValue: 1k
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1
        kind: Ingress
        name: main-route
      target:
        type: Value
        value: 10k
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
    current:
      averageUtilization: 0
      averageValue: 0
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1
        kind: Ingress
        name: main-route
      current:
        value: 10k

Ensuite, votre HorizontalPodAutoscaler tentera de s'assurer que chaque pod consomme environ 50% de sa CPU demandée, en traitant 1000 paquets par seconde, et que tous les pods derrière l'Ingress main-route servent un total de 10000 requêtes par seconde.

Auto-ajustement sur des métriques plus spécifiques

De nombreuses chaines de métriques vous permettent de décrire les métriques soit par leur nom, soit par un ensemble de descripteurs supplémentaires appelés labels. Pour tous les types de métriques autres que les ressources (pod, objet et externe, décrits ci-dessous), vous pouvez spécifier un sélecteur de label supplémentaire qui est transmis à votre chaine de métriques. Par exemple, si vous collectez une métrique http_requests avec le label verb, vous pouvez spécifier la définition de métrique suivante pour ne faire varier l'échelle que sur les requêtes de type GET:

type: Object
object:
  metric:
    name: http_requests
    selector: {matchLabels: {verb: GET}}

Ce sélecteur utilise la même syntaxe que les sélecteurs d'étiquettes complets de Kubernetes. La chaine de surveillance détermine comment regrouper plusieurs séries en une seule valeur, si le nom et le sélecteur correspondent à plusieurs séries. Le sélecteur est additif et ne peut pas sélectionner des métriques qui décrivent des objets qui ne sont pas l'objet cible (les pods cibles dans le cas du type Pods, et l'objet décrit dans le cas du type Object).

Auto-ajustement sur des métriques non liées aux objets Kubernetes

Les applications s'exécutant sur Kubernetes peuvent avoir besoin de s'auto-adapter en fonction de métriques qui n'ont pas de relation évidente avec un objet dans le cluster Kubernetes, telles que des métriques décrivant un service hébergé sans corrélation directe avec les namespace Kubernetes. À partir de Kubernetes 1.10, vous pouvez répondre à ce cas d'utilisation avec des métriques externes.

L'utilisation de métriques externes nécessite une connaissance de votre système de surveillance ; la configuration est similaire à celle requise lors de l'utilisation de métriques personnalisées. Les métriques externes vous permettent de mettre à l'échelle automatiquement votre cluster en fonction de n'importe quelle métrique disponible dans votre système de surveillance. Créez un bloc metric avec un name et un selector, comme ci-dessus, et utilisez le type de métrique External au lieu de Object. Si plusieurs séries temporelles correspondent au metricSelector, la somme de leurs valeurs sera utilisée par le HorizontalPodAutoscaler. Les métriques externes prennent en charge les types de cible Value et AverageValue, qui fonctionnent exactement de la même manière que lorsque vous utilisez le type Object.

Par exemple, si votre application traite des tâches à partir d'un service de file de messages hébergé, vous pouvez ajouter la section suivante à votre déclaration de HorizontalPodAutoscaler pour spécifier que vous avez besoin d'un travailleur par tranche de 30 tâches en attente.

- type: External
  external:
    metric:
      name: queue_messages_ready
      selector:
        matchLabels:
          queue: "worker_tasks"
    target:
      type: AverageValue
      averageValue: 30

Lorsque possible, il est préférable d'utiliser les types de cible métrique personnalisés plutôt que des métriques externes, car cela facilite la sécurisation de l'API des métriques personnalisées pour les administrateurs de cluster. L'API des métriques externes permet potentiellement l'accès à n'importe quelle métrique, il est donc nécessaire que les administrateurs de cluster fassent attention lors de son exposition.

Annexe : Conditions d'état du Horizontal Pod Autoscaler

Lorsque vous utilisez la forme autoscaling/v2 du HorizontalPodAutoscaler, vous pourrez voir les conditions d'état définies par Kubernetes sur celui-ci. Ces conditions d'état indiquent s'il est capable de se mettre à l'échelle et s'il est actuellement restreint de quelque manière que ce soit. Les conditions apparaissent dans le champ status.conditions.

Pour voir les conditions affectant un HorizontalPodAutoscaler, nous pouvons utiliser la commande kubectl describe hpa.

kubectl describe hpa cm-test
Name:                           cm-test
Namespace:                      prom
Labels:                         <none>
Annotations:                    <none>
CreationTimestamp:              Fri, 16 Jun 2017 18:09:22 +0000
Reference:                      ReplicationController/cm-test
Metrics:                        ( current / target )
  "http_requests" on pods:      66m / 500m
Min replicas:                   1
Max replicas:                   4
ReplicationController pods:     1 current / 1 desired
Conditions:
  Type                  Status  Reason                  Message
  ----                  ------  ------                  -------
  AbleToScale           True    ReadyForNewScale        the last scale time was sufficiently old as to warrant a new scale
  ScalingActive         True    ValidMetricFound        the HPA was able to successfully calculate a replica count from pods metric http_requests
  ScalingLimited        False   DesiredWithinRange      the desired replica count is within the acceptable range
Events:

Pour ce HorizontalPodAutoscaler, vous pouvez voir plusieurs conditions dans un état sain. La première, AbleToScale, indique si le HPA est capable de récupérer et de mettre à jour les échelles, ainsi que si des conditions liées aux limitations sont susceptibles d'empêcher le redimensionnement. La deuxième, ScalingActive, indique si le HPA est activé (c'est-à-dire que le nombre de réplicas de la cible n'est pas nul) et est capable de calculer les échelles souhaitées. Lorsqu'il est False, cela indique généralement des problèmes de récupération des métriques. Enfin, la dernière condition, ScalingLimited, indique que l'échelle souhaitée a été limitée par le maximum ou le minimum du HorizontalPodAutoscaler. Cela indique que vous souhaiteriez peut-être augmenter ou diminuer les contraintes de nombre de réplicas minimum ou maximum de votre HorizontalPodAutoscaler.

Quantités

Toutes les métriques dans le HorizontalPodAutoscaler et les API de métriques sont spécifiées à l'aide d'une notation spéciale en nombres entiers connue dans Kubernetes sous le nom de quantité. Par exemple, la quantité 10500m serait écrite comme 10.5 en notation décimale. Les API de métriques renvoient des nombres entiers sans suffixe lorsque cela est possible, et renvoient généralement des quantités en milli-unités sinon. Cela signifie que vous pouvez voir la valeur de votre métrique fluctuer entre 1 et 1500m, ou 1 et 1.5 lorsqu'elle est écrite en notation décimale.

Autres scénarios possibles

Création de l'autoscaler de manière déclarative

Au lieu d'utiliser la commande kubectl autoscale pour créer un HorizontalPodAutoscaler de manière impérative, nous pouvons utiliser le manifeste suivant pour le créer de manière déclarative :

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

Ensuite, créez l'autoscaler en exécutant la commande suivante :

kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created

4 - 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"
    }
  ]
}