Kubernetes – Introduction

14 février 2021

1 – Qu’est ce que Kubernetes ( grec pour « timonier ») ?

À l’origine développé par Google, Kubernetes est un projet ‘open-source’ d’ orchestration de conteneurs conçue pour automatiser le déploiement, la mise à l’échelle ainsi que la gestion d’applications conteneurisées.  La version 1.0 de Kubernetes a été publiée en 2015.

Kubernetes s’est imposé comme le standard de facto pour l’orchestration de conteneurs et est le projet phare de la Cloud Native Computing Foundation (CNCF), soutenu par des acteurs clés tels que Google, AWS, Microsoft, IBM, Intel, Cisco et Red Hat.

En bref,

1.1 – Les avantages des outils d’orchestration de K8s

1.2 – Les particularités 

  1. Kubernetes permet un déploiement rapide des applications.
  2. Kubernetes propose une utilisation efficace des ressources (moins couteux en ressources que des VM).
  3. Kubernetes est fortement intégré aux services des fournisseurs de solutions en nuage; Amazon AWS, Linode, Microsoft Azure, Google Cloud Platform.
  4. Les fournisseurs de solutions en nuage proposent des solutions Kubernetes clé en main; Serveurs maitres, noeuds et répartiteurs de charges déjà installés.

1.3 – Les composantes de Kubernetes

  1. Le(s) serveur(s) maitre(s) (master node)
    1. L’API du serveur (API Server)
    2. L’ordonnanceur (Scheduler )
    3. Le gestionnaire de contrôle (controller manager)
    4. etcd (informations, paires clé/valeur, sur l’état du système)
  2. Les noeuds (ou noeuds ouvriers – worker node)
    • processus ‘kube-proxy’
      • Gestion du réseau IP
      • Équilibreur de tâches
    • processus ‘kubelet
      • gestion de l’état du noeud
      • démarrage, arrêt et maintenance des conteneurs (pods)
      • optimisation de la performance en concordance avec le plan de déploiement
    • Un conteneur ‘runtime‘.  Habituellement, docker runtime.
  3. Pod, la plus petite unité sous K8s, une abstraction de conteneur, dans le but de ne pas être lié à une technologie.  Par exemple, docker.
    • Règle générale, un service par Pod.  Mais il peut y en avoir plus.
    • Chaque Pod obtient une adresse IP à l’intérieur d’un réseau K8s.
    • Les Pods sont éphémères.  Lors de la mise hors service d’un Pod, un autre sera créé et une nouvelle adresse IP lui sera attribuée .
    • Dans le but d’assurer un accès IP prévisible, K8s propose l’objet de type ‘service’.
      • Les services sont de type: (Attention, ne pas confondre service et micro-service)
        • internes, par example, une base de données interne, ou
        • externes, par example, l’accès à une application web.
  4. Le Déploiement (objet YAML)
    1. À partir d’un manifeste descriptif du système donné.
      1. Déploiement d’images,
      2. Déploiement de services (accès réseaux),
  5. Le ‘ReplicatSet
  6. Le ‘DeamonSet
  7. L’espace de nom ‘NameSpace
    1. Pour regrouper (isoler) les Pods en sous-systèmes.
  8. Les étiquettes ‘Labels
  9. Les ‘statefulSets
    1. Utilisés pour le Déploiement de bases de données.
  10. Le CLI de K8s, kubectl

Voici un schéma présentant l’architecture de base de Kubernetes

Helm

Helm est un registre de gestion de packages d’applications pour K8s.

artifacthub.io


2 – Minikube et kubectl

Description

Minikube est un environnement local de testes de la technologie Kubernetes.

C’est un système qui est proposé à l’intérieure d’une VM et qui permet d’apprendre la plupart des aspects de K8s sans avoir à installer un(des) serveur(s) maitre(s) et des noeuds (ouvrier/worker).  La VM de Minikube est configuré avec un noeud ‘maitre/ouvrier’.

La commande ‘cli‘ standard de gestion de l’environnement K8s, kubectl, est disponible pour gérer le système Minikube.

Pré-requis

Action 2.1 – Démarrage de minikube: minikube start

Note: Par défaut,  le gestionnaire d’amas devrait démarrer en utilisant le pilote de VM de Docker.

 minikube start  
  minikube v1.16.0 sur Darwin 10.15.4
  minikube 1.17.1 est disponible ! Téléchargez-le ici : https://github.com/kubernetes/minikube/releases/tag/v1.17.1
  To disable this notice, run: 'minikube config set WantUpdateNotification false'

  Utilisation du pilote docker basé sur le profil existant
  Démarrage du noeud de plan de contrôle minikube dans le cluster minikube
  Pulling base image ...
  docker "minikube" container est manquant, il va être recréé.
  Creating docker container (CPUs=2, Memory=1988MB) ...
  Préparation de Kubernetes v1.20.0 sur Docker 20.10.0...
     Generating certificates and keys ...
     Booting up control plane ...
     Configuring RBAC rules ...
  Verifying Kubernetes components...
  Enabled addons: storage-provisioner, default-storageclass
  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

Action 2.1.1 – Afficher l’état du service:

$ minikube  status

minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
timeToStop: Nonexistent

Alternative de démarrage de minikube:

2.1b – Démarrer un amas (cluster) en utilisant le pilote VM de VirtualBox:

minikube start --driver=virtualbox

# NOTE: Suite à un problème de détection de la fonction BIOS VT-x dans les Lab D-139 et D-137,

il faut jouter l'option --no-vtx-check au démarrage de minikube sous pilote virtualbox.

Au besoin, la commande suivante, dans PowerShell admin, pourra aider:

bcdedit /set hypervisorlaunchtype off

---
# Démarrage avec Hyper-v
minikube start --driver=hyperv --force

2.1c – Renseigner virtualbox comme pilote VM par défaut:

minikube config set driver virtualbox

2.1d – Démarrer Minikube avec un contrôle des ressources:

minikube start \
# Driver=virtualbox, parallels, vmwarefusion, hyperkit, vmware, docker, podman (def to auto-detect)  
--driver=docker \        
--container-runtime=docker \
--cpus 4 \
--memory 8192

2.1e – Démarrer un amas multi-noeud

minikube start --nodes 2 -p demo-multinode

Référence:  Démarrage de minikube


Action 2.1.2 – Lister les modules (addons) de Minikube:

$ minikube addons list 
 
|-----------------------------|----------|--------------|
|         ADDON NAME          | PROFILE  |    STATUS    |
|-----------------------------|----------|--------------|
| ambassador                  | minikube | disabled     |
| csi-hostpath-driver         | minikube | disabled     |
| dashboard                   | minikube | enabled ✅   |
| default-storageclass        | minikube | enabled ✅   |
| efk                         | minikube | disabled     |
| freshpod                    | minikube | disabled     |
| gcp-auth                    | minikube | disabled     |
| gvisor                      | minikube | disabled     |
| helm-tiller                 | minikube | disabled     |
| ingress                     | minikube | enabled ✅   |
| ingress-dns                 | minikube | disabled     |
| istio                       | minikube | disabled     |
| istio-provisioner           | minikube | disabled     |
| kubevirt                    | minikube | disabled     |
| logviewer                   | minikube | disabled     |
| metallb                     | minikube | disabled     |
| metrics-server              | minikube | disabled     |
| nvidia-driver-installer     | minikube | disabled     |
| nvidia-gpu-device-plugin    | minikube | disabled     |
| olm                         | minikube | disabled     |
| pod-security-policy         | minikube | disabled     |
| registry                    | minikube | disabled     |
| registry-aliases            | minikube | disabled     |
| registry-creds              | minikube | disabled     |
| storage-provisioner         | minikube | enabled ✅   |
| storage-provisioner-gluster | minikube | disabled     |
| volumesnapshots             | minikube | disabled     |
|-----------------------------|----------|--------------|

2.1.3 – Utilisation de minikube avec le pilote ‘Docker
(si problème avec le pilote virtualbox)

Installer (ou configurer) Docker-Desktop avec wls2
    - Pas d'Hyper-V

Ajouter le support 'kubernetes' dans Docker-Desktop (voir l'image suivante)

## Au besoin, effacer ancienne VM Virtualbox 
$ minikube delete

## Démarrer avec pilote Docker
$ minikube start --driver=docker

---------------------------------
Pas besoin de renseigner la clé 'nodePort: 300xx' dans le service.

Activer un tunnel avec minikube pour l'accès aux services de type LoadBalancer
$ minikube tunnel

Tester dans le fureteur en utilisant l'adresse 'localhost:PortDuService'

Par exemple, http://localhost:8080

3.1.4 – Exemple d’un manifeste pour un service utilisant le pilote ‘Docker’ avec minikube:

# #################################################################
# Service pour NextCloud
# #################################################################
apiVersion: v1
kind: Service
metadata:
  name: service-nextcloud
spec:
  selector:
    app: nextcloud
  type: LoadBalancer
  ports:
    - name: http
      protocol: TCP
      port: 81
      targetPort: 80
      nodePort: 30081  # Pas requis avec le pilote 'Docker'



Action 2.2 –
Interaction avec l’amas (cluster) de noeuds (les serveurs), la commande kubectl

kubectl get nodes
NAME       STATUS   ROLES                  AGE    VERSION
minikube   Ready    control-plane,master   106s   v1.20.0

NOTE: Avec minikube, il n’y a qu’un seul noeud, le ‘master/worker‘ (serveur maître/ouvrier) qui est le gestionnaire de l’orchestration et aussi le noeud ouvrier.

Action 2.3 – Obtenir la liste des ‘pods‘ (le pod est une abstraction du conteneur)

kubectl get pod  
No resources found in default namespace.

Note: Vide, nous n’avons pas encore lancer de déploiement.

Action 2.4 – Obtenir la liste des ‘services

kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   7m15s

Note: Un seul service, par défaut, qui renseigne sur le réseau de l’amas.

Nous allons maintenant ajouter des pods à notre système.

Action 2.5 kubectl create -h,  afficher l’aide de la commande create

kubectl create -h 
  
Create a resource from a file or from stdin.

 JSON and YAML formats are accepted.

Examples:
  # Create a pod using the data in pod.json.
  kubectl create -f ./pod.json
  
  # Create a pod based on the JSON passed into stdin.
  cat pod.json | kubectl create -f -
  
  # Edit the data in docker-registry.yaml in JSON then create the resource using the edited data.
  kubectl create -f docker-registry.yaml --edit -o json

Available Commands:
  clusterrole         Create a ClusterRole.
  clusterrolebinding  Create a ClusterRoleBinding for a particular ClusterRole
  configmap           Create a configmap from a local file, directory or literal value
  cronjob             Create a cronjob with the specified name.
  deployment          Create a deployment with the specified name.
  job                 Create a job with the specified name.
...

NOTE: Avec Kubernetes, le ‘pod‘ est la plus petite unité possible.  Il n’est pas possible de le créer directement. Il faut plutôt créer un ‘deployment‘ pour déployer des ‘pods‘.  L’objet ‘deployment‘ est une couche d’abstraction sur les ‘pods‘.

Action 2.5.1 – Créer un pod

kubectl create deployment ma-alpine --image=alpine

deployment.apps/ma-alpine created
√ ~ % kubectl get pod
NAME                        READY   STATUS              RESTARTS   AGE
ma-alpine-58b8888c8-tdfpz   0/1     ContainerCreating   0          5s
√ ~ % kubectl get pod
NAME                        READY   STATUS             RESTARTS   AGE
ma-alpine-58b8888c8-tdfpz   0/1     CrashLoopBackOff   1          9s

Note:  Le Pod de type ‘alpine’ n’a rien à exécuter alors il est terminé puis, redémarré à l’infini.

Nous allons l’effacer:

$ kubectl delete pod ma-alpine-58b8888c8-tdfpz

pod "ma-alpine-58b8888c8-tdfpz" deleted

Note: Le pod va être recréé.  Il faut effacer le déploiement.

$ kubectl delete deployment(s) ma-alpine

Action 2.5.2 – Créer un pod ‘interactif’, sans déploiement.

$ kubectl run ma-alpine -it --image=alpine
/ # exit

# Pour s'y reconnecter:
$ kubectl attach ma-alpine -c ma-alpine -i -t

Tester avec Ctrl+PQ

Action 2.6 – Déployer un pod à partir d’une nginx

Syntaxe:

kubectl create deployment NAME --image=image [--dry-run] [options]
kubectl create deployment serveur-web --image=nginx

Résultat:

deployment.apps/serveur-web created

---------

NOTE:  voici le regex du nom

[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')

Note: Comme pour docker, les images sont téléchargées à partir de hub.docker.com.

Action 2.7 – Afficher les déploiements et les pods

kubectl get deployment
                       
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
serveur-web   1/1     1            1           91s

kubectl get pod 
      
NAME                           READY   STATUS    RESTARTS   AGE
serveur-web-54bf66d477-4gxtx   1/1     Running   0          3m33s

NOTE: Entre le déploiement et le pod, il y a une autre couche d’abstraction nommée ‘replicaset‘.

kubectl get replicaset 

NAME                     DESIRED   CURRENT   READY   AGE
serveur-web-54bf66d477   1         1         1       8m40s

Le ‘replicaset‘ permet de gérer les répliques – le nombre d’instances –  d’un pod.

NOTE: Nous n’avons pas à interagir avec les ‘replicaset‘.  Nous le ferons avec les déploiements et les pods.

Action 2.7.2 – Interagir avec un pod

 kubectl exec -it serveur-web-54bf66d477-8ctwr -- bash

Résumé

Prenons une pause ici pour mettre le tout en contexte.  Qu’avons nous fait?  Nous avons démarrez un service Web.  Au départ il se peut que le service soit peu sollicité.

Avec le temps, si nous sommes chanceux, il sera de plus en plus sollicité.  Puis à un certain moment, l’unique instance de notre service ne sera plus en mesure de répondre à la demande, nous devenons de plus en plus populaire.

Avec notre amas Kubernetes, il sera facile de dupliquer le service web sur d’autres serveurs.

En bref,

Et tout ce qui est sous le déploiement est géré par Kubernetes.

Voici la suite.

2.8 – Le manifeste de déploiement – un ficher YAML

Pour assurer la gestion correcte du Déploiement, K8s a généré un manifeste de déploiement.  Plus tard, nous verrons comment renseigner nos propres manifestes.  Ce schéma contient des informations tel que, le nombre de duplicatas requis, la version des images, les ports exposés, …

Le fichier est constitué de trois sections:

  1. Les Méta données (metadata:)
  2. Les spécifications (spec:)
  3. Ainsi que l’état du système (status:)

Les informations des manifestes sont stockées sur le noeud maitre dans la bibliothèque etcd.

Action 2.8.1 – Édition du manifeste de Déploiement

kubectl edit deployment serveur-web

 --- 
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2021-02-14T20:43:58Z"
  generation: 1
  labels:
    app: serveur-web
  name: serveur-web
  namespace: default
  resourceVersion: "1827"
  uid: 6384e7aa-0e00-4313-b485-cc8d1212e720
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: serveur-web
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:

...

NOTE: Lors de la création du déploiement, k8s a généré un fichier de configuration avec des valeurs par défaut.

Action 2.9 – Apportons une modification au fichier de configuration: version nginx:1.18-alpine-perl

NOTE: Nous somme dans ‘vi’. Il faut appuyer sur la touche ‘i’ pour passer en mode édition.

kubectl edit deployment serveur-web

# Remplacer: - image: nginx par, - image: nginx:1.18-alpine-perl

    spec:
      containers:
      - image: nginx:1.18-alpine-perl
        imagePullPolicy: Always
        name: nginx

NOTE:  Dans l’éditeur ‘vi’.  Pour enregistrer et quitter:  ‘ESC:wq’.

Il est possible de renseigner un autre éditeur via la variable d’environnement  »KUBE_EDITOR »

export KUBE_EDITOR= »code -w »

edit deployment serveur-web
deployment.apps/serveur-web edited

Action 2.10 – Afficher le résultat

kuberctl get pod   
NAME                           READY   STATUS    RESTARTS   AGE
serveur-web-6589df7667-vzzq4   1/1     Running   0          101s

NOTE: Remarquez la modification du nom du ‘pod’.  De plus, suite à la modification, le déploiement a été automatique.

Action 2.11 – Afficher l’historique des duplicatas.

kubectl get replicaset
NAME                     DESIRED   CURRENT   READY   AGE
serveur-web-54bf66d477   0         0         0       54m
serveur-web-6589df7667   1         1         1       4m56s

NOTE: Pas de ‘pods’ dans la version précédente: serveur-web-54bf66d477 0 0 0 54m

Action 2.11.2 – Afficher le log d’un pod

kubectl logs serveur-web-54bf66d477-8ctwr

---

/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up

Action 2.11.3 –   Obtenir une liste exhaustive d’information sur un pod

kubectl describe pod serveur-web-54bf66d477-8ctwr
----
Name:         serveur-web-54bf66d477-8ctwr
Namespace:    default
Priority:     0
Node:         minikube/192.168.99.100
Start Time:   Sat, 20 Mar 2021 17:47:22 -0400
Labels:       app=serveur-web
              pod-template-hash=54bf66d477
Annotations:  <none>
Status:       Running
IP:           172.17.0.2
IPs:
  IP:           172.17.0.2
Controlled By:  ReplicaSet/serveur-web-54bf66d477
Containers:
  nginx:

...

Note:  Il est possible d’appliquer la commande précédente sur d’autres objets.  Par exemple, ‘kubectl describe deployments‘.

Labo 2.12 – Renseigner 3 duplicatas dans le schéma puis, afficher la liste des pods.

Action 2.13 – Effacer un Déploiement

kubectl delete deployment serveur-web

kubectl get deployment
kubectl get replicaset
kubectl get pod

3 – Renseigner un manifeste de déploiement

3.0 – Manifeste d’un Pod

Action 3.0.1 – Manifeste d’un Pod, renseigner le fichier uneAlpine.yml

# ------------------------------------------------------------
# Exemple d'un manifeste pour un Pod avec des variables d'env.
# k apply -f uneAlpine.yml
# k logs meta-une-alpine
# ------------------------------------------------------------
apiVersion: v1
kind: Pod
# Section 1 - Les Méta-données
metadata:
  name: meta-une-alpine
# Section 2 - Les spécifications
spec:
  containers:
  - name: ma-alpine
    image: alpine
    command: ["/bin/sh", "-c",  "env"]
    env:
    - name: ENV01
      value: YoDouloudou
    - name: ENV02
      value: Coucou  
  restartPolicy: Never

Note: Remarquer le type du manifeste –  kind: Pod. 

Action 3.0.2 – Déployer le système:

$ kubectl apply -f uneAlpine.yml
pod/meta-une-alpine created
√ semaine08 % kubectl get pod
NAME                           READY   STATUS      RESTARTS   AGE
meta-une-alpine                0/1     Completed   0          92s

Note: Remarquer le ‘STATUS: Completed

Action 3.0.3 – Afficher les logs du déploiement précédent:

$ kubectl logs meta-une-alpine
KUBERNETES_PORT=tcp://10.96.0.1:443
NGINX_SERVICE_SERVICE_PORT=80
ENV01=YoDouloudou
ENV02=Coucou

Action 3.0.3.1 – Faire un test avec le bloc suivant:

kind: Pod
# Section 1 - Les Méta-données
metadata:
  # Placer 'name' en commentaire et appliquer le manifeste
  #name: meta-une-alpine

Résultat?

Action 3.0.3.2 – Effacer le résultat d’un manifeste:

Kubectl delete -f nomDuManifeste.yml

Action 3.0.4 – Manifeste d’un Pod avec deux conteneurs, fichier alpine-v2.yml:

# ---------------------------------------------------------
# Fichier: alpine-v2.yml
# Exemple d'un manifeste avec deux conteneurs dans un Pod
# ---------------------------------------------------------
# Lister les conteneurs d'un Pod
# kubectl get pods alpine-v2 -o json > resultat.json
 
apiVersion: v1
kind: Pod
metadata:
  name: alpine-v2
  # namespace: default
spec:
  containers:
  - image: alpine
    name: conteneur-alpine01
    stdin: true
    tty: true
#  restartPolicy: Always
  - image: alpine
    # Fournir une tâche à exécuter pour le conteneur
    # Sinon, il va s'arrêter.
    command: [ "/bin/sh", "-c", "while true; do sleep 5; done;" ]
    imagePullPolicy: IfNotPresent
    name: conteneur-alpine02
  restartPolicy: Always

Afficher le résultat:

$ kubectl get pod
NAME                           READY   STATUS      RESTARTS   AGE
alpine-v2                      2/2     Running     0          7m30s

Action 3.0.5 – Obtenir les détails du pod précédent:

kubectl get pods alpine-v2 -o json > resultat.json

====

Voici un extrait du fichier résultat.json:

    "spec": {
        "containers": [
            {
                "image": "alpine",
                "imagePullPolicy": "Always",
                "name": "conteneur-alpine01",
                "resources": {},
                "stdin": true,
                "terminationMessagePath": "/dev/termination-log",
                "terminationMessagePolicy": "File",
                "tty": true,
                "volumeMounts": [
                    {
                        "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
                        "name": "default-token-z4rpp",
                        "readOnly": true
                    }
                ]
            },
            {
                "command": [
                    "/bin/sh",
                    "-c",
                    "while true; do sleep 5; done;"
                ],
                "image": "alpine",
                "imagePullPolicy": "IfNotPresent",
                "name": "conteneur-alpine02",
                "resources": {},
                "terminationMessagePath": "/dev/termination-log",
                "terminationMessagePolicy": "File",
                "volumeMounts": [
                    {
                        "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
                        "name": "default-token-z4rpp",
                        "readOnly": true
                    }
                ]
            }
        ],

Action 3.0.5.1 – Extraire des information du résultat json, par exemple, la liste des conteneurs:

# 1 - Liste des conteneurs pour un Pod:
kubectl get pods pod-name -o jsonpath='{.spec.containers[*].name}'

# 2 - Liste des conteneurs de tous les Pods:
kubectl get pods -o jsonpath="{.items[*].spec.containers[*].name}"

# 3 - Liste des conteneurs par Pod de l'espace de nom par défaut - pretty:
kubectl get pods -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.name}{", "}{end}{end}' |\
sort

# 4 - Liste des conteneurs par Pod de tous les espaces de nom:
kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.name}{", "}{end}{end}' |\
sort

Référence: kubernetes

Action 3.0.6 – Exécuter une commande dans un conteneur lorsque le Pod en possède plusieurs:

$ kubectl exec -it alpine-v2 --container conteneur-alpine01 -- /bin/sh

Note:  Les deux conteneurs utilisent l’adresse IP du Pod.


3.1 – Manifeste d’un déploiement

(deployment vs daemonset)

Action 3.1 – Manifeste d’un déploiement, renseigner le fichier ‘deploiement-nginx.yml‘ suivant:

apiVersion: apps/v1
kind: Deployment
# Section 1 - Les Méta-données
metadata:
  name: nginx-deployment
  labels:
    app: nginx
# Section 2 - Les spécifications
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16
        ports:
        - containerPort: 80
# Section 3 - État du déploiement - sera complétée par K8s

Note: Remarquer –  kind: Deployment

Action 3.2 – Renseigner le fichier ‘service-nginx.yml‘ suivant:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      # Port à exposer au reseau local K8s
      port: 80
      # Port du conteneur - containerPort
      targetPort: 80

Note: Remarquer –  kind: Service

Action 3.3 – Nous allons maintenant appliquer nos deux schémas; le déploiement et le service.

kubectl apply -f deploiement-nginx.yml

deployment.apps/nginx-deployment created

--

kubectl apply -f service-nginx.yml

service/nginx-service created

--

kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           62s

kubectl get service               
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP   26d
nginx-service   ClusterIP   10.108.129.91   <none>        80/TCP    82s

Action 3.4 – Vérifier que le service achemine bien les requêtes http vers les pods de nginx

kubectl describe service nginx-service

Name:              nginx-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP:                10.108.129.91
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         172.17.0.2:80,172.17.0.5:80
Session Affinity:  None
Events:            <none>

Note: Remarquer la ligne ‘Endpoints: 172.17.0.2:80,172.17.0.5:80‘.  Les requêtes seront envoyées vers deux pods sur leur port 80.

Action 3.5 – Vérifier l’adresse IP deux deux pods.

kubectl get pod -o wide

NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE
nginx-deployment-f4b7bbcbc-qt8kd   1/1     Running   0          12m   172.17.0.5   minikube
nginx-deployment-f4b7bbcbc-tcr7l   1/1     Running   0          12m   172.17.0.2   minikube

Note:  Le service ‘nginx-service‘, qui est de type ‘clusterIP – voir kubectl get service‘ n’est pas encore disponible à l’extérieur du réseau du cluster.  À ce point, il n’est pas possible de tester le serveur Web dans un fureteur de notre poste de travail.

Action 3.6 – Obtenir le schéma complet du Déploiement.  Il est disponible dans le etcd.

kubectl get deployment nginx-deployment -o yaml > nginx-dep-info.yml

Action 3.7 – Exposer nginx au monde extérieur – service type: LoadBalancer.

En rappel, voici la configuration de service-nginx

nginx-service   ClusterIP   10.108.129.91   <none>        80/TCP    26m

Voici une version modifiée du fichier service-nginx.yml de l’action 3.2

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  # Ajout 1  
  type: LoadBalancer

  ports:
    - protocol: TCP
      # Port à exposer au reseau local K8s
      port: 80
      # Port du conteneur
      targetPort: 80
      # ajout 2 - port externe.  Doit être entre 30000 et 32767
      nodePort: 30000

Action 3.8 – Appliquer le schéma modifié

$ kubectl apply -f service-nginx.yml

service/nginx-service configured

---

$ kubectl get service               
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP      10.96.0.1       <none>        443/TCP        26d
nginx-service   LoadBalancer   10.108.129.91   <pending>     80:30000/TCP   60m

Note:  Remarquer que nginx-service est maintenant de type ‘LoadBalancer‘.  Remarquer aussi que ‘EXTERNAL-IP‘ est <pending> car sous minikube, la gestion des adresses externes est légèrement différente.  Nous aurons une étape de plus à réaliser avant que le serveur Web soit disponible via notre poste de travail.

Action 3.9 – Attribuer une adresse IP externe à nginx-service.

$ minikube service nginx-service

$ minikube service list

|-------------|---------------|--------------|-----------------------------|
|  NAMESPACE  |     NAME      | TARGET PORT  |             URL             |
|-------------|---------------|--------------|-----------------------------|
| default     | kubernetes    | No node port |
| default     | nginx-service |           80 | http://192.168.59.100:30000 |
| kube-system | kube-dns      | No node port |
|-------------|---------------|--------------|-----------------------------|

# Note: Selon la version de minikube et/ou du pilote de VM, il est possible
que le fureteur soit lancé automatiquement.

NOTE:  En classe, (D139) nous avons remarqué que le ‘tunneling’ de services ne fonctionnait pas avec le driver ‘docker’.  Voir:

Action 3.10 Consolidation des deux schémas.  Renseigner le fichier ‘nginx-dep+service.yml

# Voici la version consolidée de dep-nginx et service-nginx
apiVersion: apps/v1
kind: Deployment
# Section 1 - Les Méta-données
metadata:
  name: nginx-deployment
  # Les 'labels' ici, sont facultatifs.
  labels:
    app: nginx-app
# Section 2 - Les spécifications
spec:
  replicas: 4
  selector:
    matchLabels:
      # Le label app doit correspondre à celui de la ligne 21 
      app: nginx-app-label
  template:
    metadata:
      labels:
      # Le label app doit correspondre à celui de la ligne 16 
        app: nginx-app-label
    spec:
      containers:
      - name: conteneur-nginx
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
      # Le selector app doit correspondre au matchLabel de la ligne 16
      # Note: Il est aussi possible d'utiliser le nom d'un Pod.   
    app: nginx-app-label
  # Ajout 1  
  type: LoadBalancer
  ports:
    - protocol: TCP
      # Port à exposer au reseau local K8s
      port: 80
      # Port du conteneur
      targetPort: 80
      # ajout 2 - port externe.  Doit être entre 30000 et 32767
      nodePort: 30080

Labo 3.11 – Effacer les déploiements précédents, redéployer à partir du fichier 3.10 et tester le service Web.

Labo 3.12 – Remplacer l’image nginx utilisée dans le fichier de labo 3.11 par ‘alainboudreault/phpweb’  et augmenter le nombre de duplicatas à 20.


Référence 01 – K8S: Type de ressources

NOMNOM COURTVERSION APINAME
SPACED
KIND
bindingsv1trueBinding
componentstatusescsv1falseComponentStatus
configmapscmv1trueConfigMap
endpointsepv1trueEndpoints
eventsevv1trueEvent
limitrangeslimitsv1trueLimitRange
namespacesnsv1falseNamespace
nodesnov1falseNode
persistentvolumeclaimspvcv1truePersistentVolumeClaim
persistentvolumespvv1falsePersistentVolume
podspov1truePod
podtemplatesv1truePodTemplate
replicationcontrollersrcv1trueReplicationController
resourcequotasquotav1trueResourceQuota
secretsv1trueSecret
serviceaccountssav1trueServiceAccount
servicessvcv1trueService
mutatingwebhookconfigurationsadmissionregistration.
k8s.io/v1
falseMutatingWebhookConfiguration
validatingwebhookconfigurationsadmissionregistration.
k8s.io/v1
falseValidatingWebhookConfiguration
customresourcedefinitionscrd,crdsapiextensions.
k8s.io/v1
falseCustomResourceDefinition
apiservicesapiregistration
.k8s.io/v1
falseAPIService
controllerrevisionsapps/v1trueControllerRevision
daemonsetsdsapps/v1trueDaemonSet
deploymentsdeployapps/v1trueDeployment
replicasetsrsapps/v1trueReplicaSet
statefulsetsstsapps/v1trueStatefulSet
tokenreviewsauthentication.
k8s.io/v1
falseTokenReview
localsubjectaccessreviewsauthorization.
k8s.io/v1
trueLocalSubjectAccessReview
selfsubjectaccessreviewsauthorization.
k8s.io/v1
falseSelfSubjectAccessReview
selfsubjectrulesreviewsauthorization.k8s.io/v1falseSelfSubjectRulesReview
subjectaccessreviewsauthorization.k8s.io/v1falseSubjectAccessReview
horizontalpodautoscalershpaautoscaling/v2trueHorizontalPodAutoscaler
cronjobscjbatch/v1trueCronJob
jobsbatch/v1trueJob
certificatesigningrequestscsrcertificates.k8s.io/v1falseCertificateSigningRequest
leasescoordination.k8s.io/v1trueLease
endpointslicesdiscovery.k8s.io/v1trueEndpointSlice
eventsevevents.k8s.io/v1trueEvent
flowschemasflowcontrol.apiserver
.k8s.io/v1beta2
falseFlowSchema
prioritylevelconfigurationsflowcontrol.apiserver.
k8s.io/v1beta2
falsePriorityLevelConfiguration
ingressclassesnetworking.k8s.io/v1falseIngressClass
ingressesingnetworking.k8s.io/v1trueIngress
networkpoliciesnetpolnetworking.k8s.io/v1trueNetworkPolicy
runtimeclassesnode.k8s.io/v1falseRuntimeClass
poddisruptionbudgetspdbpolicy/v1truePodDisruptionBudget
podsecuritypoliciespsppolicy/v1beta1falsePodSecurityPolicy
clusterrolebindingsrbac.authorization.k8s.io/v1falseClusterRoleBinding
clusterrolesrbac.authorization.k8s.io/v1falseClusterRole
rolebindingsrbac.authorization.k8s.io/v1trueRoleBinding
rolesrbac.authorization.k8s.io/v1trueRole
priorityclassespcscheduling.k8s.io/v1falsePriorityClass
csidriversstorage.k8s.io/v1falseCSIDriver
csinodesstorage.k8s.io/v1falseCSINode
csistoragecapacitiesstorage.k8s.io/v1trueCSIStorageCapacity
storageclassesscstorage.k8s.io/v1falseStorageClass
volumeattachmentsstorage.k8s.io/v1falseVolumeAttachment
NOTE: Il est possible d'obtenir cette liste à partir du cli de K8S:
$ kubectl api-resources

Prochain document K8s-partie2


Document rédigé par Alain Boudreault (c) 2021 – version 2021.03.23.1