Date: 14 février 2021 - Révision du 2025.12.05 TODO: Valider le document —
À l’origine développé par Google, Kubernetes est un projet ‘open-source’ d’orchestration de conteneurs conçu 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.
kube-proxy
kubelet
runtime. Habituellement, docker runtimeLe ReplicaSet
Le DaemonSet
Les étiquettes (Labels)
Voici un schéma présentant l’architecture de base de Kubernetes:

Helm est un registre de gestion de packages d’applications pour K8s.
Minikube est un environnement local de tests de la technologie Kubernetes.
C’est un système qui est proposé à l’intérieur d’une VM et qui permet d’apprendre la plupart des aspects de K8s sans avoir à installer un(des) serveur(s) maître(s) et des nœuds (ouvrier/worker). La VM de Minikube est configurée avec un nœud ‘maître/ouvrier’.
La commande cli standard de gestion de l’environnement K8s, kubectl, est disponible pour gérer le système Minikube.
Voir https://kind.sigs.k8s.io ou Docker-desktop comme alternative.
minikube start
# Résultat attendu:
# 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
Note: Par défaut, le gestionnaire d’amas devrait démarrer en utilisant le pilote de VM de Docker.
minikube status
# Résultat:
# minikube
# type: Control Plane
# host: Running
# kubelet: Running
# apiserver: Running
# kubeconfig: Configured
# timeToStop: Nonexistent
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 ajouter 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
minikube config set driver virtualbox
minikube start \
--driver=docker \
--container-runtime=docker \
--cpus 4 \
--memory 8192
# Driver: virtualbox, parallels, vmwarefusion, hyperkit, vmware, docker, podman (def to auto-detect)
minikube start --nodes 2 -p demo-multinode
Référence: Démarrage de minikube
minikube addons list
# Résultat:
# |-----------------------------|----------|--------------|
# | 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 |
# |-----------------------------|----------|--------------|
# Installer (ou configurer) Docker-Desktop avec wsl2
# - 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
TODO: À retirer du document

# #################################################################
# 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'

La commande kubectl
kubectl get nodes
# Résultat:
# NAME STATUS ROLES AGE VERSION
# monCluster Ready control-plane,master 106s v1.20.0
NOTE: Selon la configuration du cluster, il est possible qu’il n’y ait qu’un seul nœud, le master/worker (serveur maître/ouvrier) qui est le gestionnaire de l’orchestration et aussi le nœud ouvrier.
Le pod est une abstraction du conteneur.
kubectl get pod
# Résultat:
# No resources found in default namespace.
Note: Vide, nous n’avons pas encore lancé de déploiement.
kubectl get services
# Résultat:
# 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.
kubectl create -h
# Résultat:
# 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 d’une application. Ils sont habituellement créés par l’intermédiaire d’un deployment. L’objet deployment permet d’assurer la présence constante des pods constituant une application.
kubectl run ma-alpine --image=alpine
# Résultat:
# pod/ma-alpine created
kubectl get pod
# NAME READY STATUS RESTARTS AGE
# ma-alpine 0/1 ContainerCreating 0 5s
kubectl get pod
# NAME READY STATUS RESTARTS AGE
# ma-alpine 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
# Résultat:
# pod "ma-alpine" deleted
Alternative de création pour prévenir le ‘CrashLoopBackOff’:
kubectl run ma-alpine --image=alpine --restart=Never
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# ma-alpine 0/1 Completed 0 34s
kubectl run ma-alpine --image=alpine --restart=Never --dry-run=client -oyaml
# =========================================================================
# Résultat à l'écran:
# apiVersion: v1
# kind: Pod
# metadata:
# labels:
# run: ma-alpine
# name: ma-alpine
# spec:
# containers:
# - image: alpine
# name: ma-alpine
# resources: {}
# dnsPolicy: ClusterFirst
# restartPolicy: Never
# status: {}
# =========================================================================
# Sauvegarder le résultat dans un fichier
kubectl run ma-alpine --image=alpine --restart=Never --dry-run=client -oyaml > creer-pod-alpine.yaml
# NOTE: Nous utiliserons des manifestes un peu plus tard pour créer des ressources K8s
# Par exemple
kubectl delete pod ma-alpine
kubectl apply -f creer-pod-alpine.yaml
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
# Syntaxe:
# kubectl create deployment NAME --image=image [--dry-run=client] [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.
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.
kubectl exec -it serveur-web-54bf66d477-8ctwr -- bash
kubectl expose deployment serveur-web --port=80
kubectl get svc -owide
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 156m <none>
# serveur-web ClusterIP -->10.111.198.207 <none> 80/TCP 21m app=serveur-web
curl 10.111.198.207
# Résultat:
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# ...
# <p><em>Thank you for using nginx.</em></p>
# </body>
# </html>
# Changer le nombre de réplicats:
kubectl scale deploy serveur-web --replicas=5
kubectl get pods -owide
Prenons une pause ici pour mettre le tout en contexte. Qu’avons-nous fait? Nous avons démarré 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 populaires.
Avec notre amas Kubernetes, il sera facile de dupliquer le service web sur d’autres serveurs.
En bref:
Deployment permet la gestion d’un ReplicaSetReplicaSet permet la gestion de tous les duplicatas d’un PodPod est une abstraction d’un conteneurEt tout ce qui est sous le déploiement est géré par Kubernetes.
Voici la suite.
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 telles que: le nombre de duplicatas requis, la version des images, les ports exposés, etc.
Le fichier est constitué de trois sections:
metadata:)spec:)status:)Les informations des manifestes sont stockées sur le nœud maître dans la bibliothèque etcd.
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.
Version nginx:1.18-alpine-perl
- image: nginx par - image: nginx:1.18-alpine-perlNOTE: Nous sommes 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"
export KUBE_EDITOR="nano"
kubectl edit deployment serveur-web
# deployment.apps/serveur-web edited
kubectl 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.
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
kubectl logs serveur-web-54bf66d477-8ctwr
# Résultat:
# /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
kubectl describe pod serveur-web-54bf66d477-8ctwr
# Résultat:
# 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.
Renseigner 3 duplicatas dans le schéma puis, afficher la liste des pods.
kubectl delete deployment serveur-web
kubectl get deployment
kubectl get replicaset
kubectl get pod
Un manifeste Kubernetes est un fichier YAML qui décrit l’état désiré d’une ressource.
Structure commune :
apiVersion: <version-api> # Version de l'API, voir le tableau à la fin de ce document.
kind: <type-ressource> # Type de ressource: pod, service, configmap, secret, deployment, ...
metadata: # Nom, labels, annotations
name: <nom-ressource> # Nom de la ressource (requis!)
namespace: <nom-espace-de-nom> # Indique le 'NS' dans lequel la ressource sera créée (optionnel)
labels: # Paires de clés pour organiser et sélectionner les objets K8s
clé: valeur
clé: valeur
spec: # Spécification (état désiré) de la ressource, en fonction de 'kind'
# ------------------------------------------------------------
# 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.
kubectl apply -f uneAlpine.yml
# pod/meta-une-alpine created
kubectl get pod
# NAME READY STATUS RESTARTS AGE
# meta-une-alpine 0/1 Completed 0 92s
Note: Remarquer le ‘STATUS: Completed’
kubectl logs meta-une-alpine
# Résultat:
# KUBERNETES_PORT=tcp://10.96.0.1:443
# NGINX_SERVICE_SERVICE_PORT=80
# ENV01=YoDouloudou
# ENV02=Coucou
kind: Pod
# Section 1 - Les Méta-données
metadata:
# Placer 'name' en commentaire et appliquer le manifeste
#name: meta-une-alpine
Résultat?
kubectl delete -f nomDuManifeste.yml
Fichier alpine-v2.yml:
# ---------------------------------------------------------
# Fichier: alpine-v2.yml
# Auteur: Alain Boudreault
# Exemple d'un manifeste avec deux conteneurs dans un Pod
# ---------------------------------------------------------
# Lister les conteneurs d'un Pod
# $ k get pods alpine-v2 -o json > resultat.json
# $ k describe po alpine-v2
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
kubectl get pods alpine-v2 -o json > resultat.json
Voici un extrait du fichier resultat.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
}
]
}
],
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
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.
# ---------------------------------------------------------
# Fichier: demo-pod-init.yml
# Auteur: Alain Boudreault
# Exemple d'un 'initContainer' qui copie un contenu externe
# vers le dossier racine du serveur nginx.
# ---------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
spec:
volumes:
- name: shared-data
emptyDir: {}
initContainers:
- name: demo-init
image: busybox
command: ['sh', '-c', 'wget -O /usr/share/data/index.html http://google.com']
volumeMounts:
- name: shared-data
mountPath: /usr/share/data
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
kubectl apply -f demo-pod-init.yml
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# pod-demo 0/1 PodInitializing 0 5s
kubectl get pods -owide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
# pod-demo 1/1 Running 0 2m7s 10.244.0.12 k8smaster <none>
curl 10.244.0.12
Action: Tester dans un fureteur sur le serveur

# ---------------------------------------------------------
# Fichier: mem-info.yml
# Auteur: Alain Boudreault
# Exemple d'un 'initContainer' qui envoie le contenu
# de /proc/meminfo vers le dossier racine du serveur nginx
# ---------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
name: plusieurs-pods
spec:
volumes:
- name: dossier-de-partage
emptyDir: {}
initContainers:
- name: meminfo
image: alpine
restartPolicy: Always
command: ['sh', '-c', 'sleep 5; while true; do cat /proc/meminfo > /usr/share/data/index.html; sleep 10; done;']
volumeMounts:
- name: dossier-de-partage
mountPath: /usr/share/data
containers:
- name: nginx
image: nginx
volumeMounts:
- name: dossier-de-partage
mountPath: /usr/share/nginx/html
# ---------------------------------------------------------
# Fichier: init-via-git.yml
# Auteur: Alain Boudreault
# Exemple d'un 'initContainer' qui clone le contenu
# d'un dépôt vers le dossier racine du serveur nginx
# ---------------------------------------------------------
apiVersion: v1
kind: Pod
metadata:
name: nginx-super-init
spec:
volumes:
- name: www
containers:
- name: nginx-superminou
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/
initContainers:
- name: git
image: alpine
# Installation de git dans le conteneur, suivi d'un git clone vers le dossier de partage
command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/ve2cuy/superMinou /www" ]
volumeMounts:
- name: www
mountPath: /www/
Renseigner le fichier 3.1-deploiement-nginx.yml suivant:
# ---------------------------------------------------------
# Fichier: 3.1-deploiement-nginx.yml
# Auteur: Alain Boudreault
# Déploiement de deux pods nginx version 1.16
# ---------------------------------------------------------
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
Fichier 3.2-service-nginx.yml:
# -------------------------------------------------------------------------------------
# Fichier: 3.2-service-nginx.yml
# Auteur: Alain Boudreault
# Voici comment exposer un service de type Cluster-IP -via un port- au réseau local K8s
# pour accéder aux pods nginx déployés dans le manifeste 3.1-deploiement-nginx.yml
# Le lien entre le service et les pods est fait via les labels:
# selector:
# app: nginx
# fait référence au label app: nginx dans le manifeste 3.1-deploiement-nginx.yml
# -------------------------------------------------------------------------------------
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
# fait référence au label app: nginx dans le manifeste 3.1-deploiement-nginx.yml
selector:
app: nginx
ports:
- protocol: TCP
# Port à exposer au reseau local K8s
port: 80
# Port du conteneur - containerPort
targetPort: 80
Note: Remarquer – kind: Service
Nous allons maintenant appliquer nos deux schémas: le déploiement et le service.
kubectl apply -f 3.1-deploiement-nginx.yml
# deployment.apps/nginx-deployment created
kubectl apply -f 3.2-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
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.
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
Action: Tester dans le fureteur disponible sur le serveur:

Il est disponible dans le etcd:
kubectl get deployment nginx-deployment -o yaml > nginx-dep-info.yml
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 3.2-service-nginx.yml de l’action 3.2:
# --------------------------------------------------------------------------------------
# Fichier: 3.7-service-nginx-LB.yml
# Auteur: Alain Boudreault
# Voici comment exposer un service de type LoadBalancer -via un port- au reseau local K8s
# pour accéder aux pods nginx déployés dans le manifeste 3.1-deploiement-nginx.yml
# Le lien entre le service et les pods est fait via les labels:
# selector:
# app: nginx
# fait référence au label app: nginx dans le manifeste 3.1-deploiement-nginx.yml
# --------------------------------------------------------------------------------------
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
kubectl apply -f 3.7-service-nginx-LB.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
# Note: Sous Docker_Desktop+Kubernetes, le tunnel vers votre machine sera automatique
# et le service accessible via 'localhost'
# |-------------|---------------|--------------|-----------------------------|
# | 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:
Renseigner le fichier 3.10-nginx-dep+service.yml:
# -----------------------------------------------------------
# Fichier: 3.10-nginx-dep+service.yml
# Auteur: Alain Boudreault
# -----------------------------------------------------------
# Voici la version consolidée de:
# 3.1-deploiement-nginx.yml et
# 3.7-service-nginx-LB.yml
# -----------------------------------------------------------
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 réseau local K8s
port: 80
# Port du conteneur
targetPort: 80
# ajout 2 - port externe. Doit être entre 30000 et 32767
nodePort: 30080
Effacer les déploiements précédents, redéployer à partir du fichier 3.10 et tester le service Web.
Remplacer l’image nginx utilisée dans le fichier de labo 3.11 par alainboudreault/phpweb et augmenter le nombre de duplicatas à 20.
curl http://192.168.99.100:30080/info.php| NOM | NOM COURT | VERSION API | NAMESPACED | KIND |
|---|---|---|---|---|
bindings |
v1 | true | Binding | |
componentstatuses |
cs |
v1 | false | ComponentStatus |
configmaps |
cm |
v1 | true | ConfigMap |
endpoints |
ep |
v1 | true | Endpoints |
events |
ev |
v1 | true | Event |
limitranges |
limits |
v1 | true | LimitRange |
namespaces |
ns |
v1 | false | Namespace |
nodes |
no |
v1 | false | Node |
persistentvolumeclaims |
pvc |
v1 | true | PersistentVolumeClaim |
persistentvolumes |
pv |
v1 | false | PersistentVolume |
pods |
po |
v1 | true | Pod |
podtemplates |
v1 | true | PodTemplate | |
replicationcontrollers |
rc |
v1 | true | ReplicationController |
resourcequotas |
quota |
v1 | true | ResourceQuota |
secrets |
v1 | true | Secret | |
serviceaccounts |
sa |
v1 | true | ServiceAccount |
services |
svc |
v1 | true | Service |
daemonsets |
ds |
apps/v1 | true | DaemonSet |
deployments |
deploy |
apps/v1 | true | Deployment |
replicasets |
rs |
apps/v1 | true | ReplicaSet |
statefulsets |
sts |
apps/v1 | true | StatefulSet |
horizontalpodautoscalers |
hpa |
autoscaling/v2 | true | HorizontalPodAutoscaler |
cronjobs |
cj |
batch/v1 | true | CronJob |
jobs |
batch/v1 | true | Job | |
ingresses |
ing |
networking.k8s.io/v1 | true | Ingress |
networkpolicies |
netpol |
networking.k8s.io/v1 | true | NetworkPolicy |
storageclasses |
sc |
storage.k8s.io/v1 | false | StorageClass |
# 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 © 2021-2026
Version 2025.12.03.1
Site par ve2cuy