logo-kubernetes

Atelier DevOps - Kubernetes

We love K8s, but not ice so much.

Sommaire

  • 1 - Kubernetes
  • 2 - Kubectl
  • 3 - Pods
  • 4 - Labels / Annotations
  • 5 - Services
  • 6 - Ingress
  • 7 - ReplicaSets
  • 8 - Deployments
  • 9 - DaemonSet
  • 10 - ConfigMaps et Secrets
  • 11 - RBAC
  • 12 - Pour aller plus loin (que la slide 92)

no-ice-cube-summary

(Il a vu le nombre de slides.)

1. Kubernetes

Ou K8s, numéronyme, pour le nombre de lettres entre le K et le s.

Définition

Kubernetes vient de κυβερνήτης, grec pour "timonier" ou "pilote".

Kubernetes est un orchestrateur de conteneurs permettant l'automatisation de déploiement et de scaling logicielle.
Kubernetes permet de rassembler des machines en cluster(s), en les manageant depuis une machine extérieure.

Histoire

Première version publiée le 9 septembre 2014, avec une sortie de la 1.0 le
21 juillet 2015.
Développé en GO, originalement par Google, puis actuellement maintenu
par la Cloud Native Computing Foundation (CNCF).

top-right-image

Containers

K8s se base sur des conteneurs pour tout faire tourner. Il est facilement possible de créer de nouvelles images avec des outils comme Docker.
L'application de containérisations utilisée en backend doit être compatible avec l'Open Container Initiative (OCI).
Des exemples de runtimes compatibles:

  • containerd
  • runc
  • cri-o
  • docker

top-right-image

Organisation de K8s

kubernetes-cluster

Pourquoi utiliser K8s

  • Immutabilité
  • Configuration déclarative
  • Self-healing
  • Microservices
  • Scaling
  • Abstraction d’architecture

Pourquoi utiliser K8s

Immutabilité

Les images déployées sur Kubernetes ne changent pas au runtime.
Pour appliquer des changements à une application, il faut déployer une nouvelle image.

Pourquoi utiliser K8s

Configuration déclarative

Aussi appelé Infrastructure as Code (IaC), toutes les ressources déployées sur K8s sont définies par des configurations qui représentent l'état souhaité de l'infrastructure.
En cas de déviation de l'infrastructure par rapport à cette configuration, K8s va automatiquement la réappliquer pour retourner dans son état désiré.
Les fichiers de configurations sont des manifestes, qui peuvent être sous deux formats :

YAML: Propre, lisible, utilisable, commentable. emoji
JSON: Maladie mentale. emoji

Pourquoi utiliser K8s

Self-healing

Afin de retourner dans l'état désiré, K8s surveille constamment l'état du système pour s'assurer que le cluster est toujours dans un bon état. Si un problème est repéré, il peut supprimer et recréer des ressources à sa guise.

Pourquoi utiliser K8s

Microservices

Il est recommandé de faire des logiciels à base de microservices pour déployer sur K8s. L'architecture par microservices consiste à découper les applications en beaucoup de petits modules, chaque module ayant une tâche spécifique.

Pourquoi utiliser K8s

Scaling

Si une application a besoin de plus ou moins de ressources, K8s peut ajouter ou supprimer des Pods dynamiquement. K8s peut également, si l'environnement dans lequel il est déployé le permet, ajouter ou retirer des nœuds à son cluster au runtime.

Pourquoi utiliser K8s

Abstraction d'architecture

La configuration de K8s lui permet d'être cloud agnostique. Il est facilement déployable sur une nouvelle infrastructure, ou cloud, sans changer les configurations, qui resteront communes.

2. Kubectl

# Average kubectl command
kubectl patch pods -n default  \
  --type='json' -p '{"spec":{"containers":[{"name":"pv-recycler","image":"nexus.caillou.sh:8444/build-image/debian-base:bookworm-v1.0.3"}]}}' \
  recycler-for-pv-cnpg-rundeck-nfs-2

Définition

La CLI pour manager un cluster est kubectl. Tous les objets de K8s sont représentés par des ressources RESTful, modifiables via des requêtes HTTP.
kubectl permet de visionner les ressources avec des affichages différents, comme une représentation adaptée pour l'humain, ou les représentations JSON ou YAML brutes.

Namespaces

Les namespaces permettent d'isoler des groupes de ressources au sein d'un cluster.
La portée des ressources basées sur les namespaces, est limitée aux objets créés dans les mêmes namespaces et ne s'applique pas aux objets à l'échelle du cluster entier.

# namespace.yaml
# Création d'un namespace via un manifeste.
apiVersion: v1 # Version de l'API à utiliser
kind: Namespace # Définition du type de la ressource (e.g. Namespace, Deployment, Pods)
metadata:
  name: demo
# Création d'un namespace via la cli.
$ kubectl create namespace demo
namespace/demo created

Contextes

kubectl permet de définir des contextes, qui contiennent des informations concernant une session, comme par exemple le namespace par défaut à utiliser, ou le cluster utilisé.

Il est possible de changer de contexte rapidement, avec la commande suivante:

# Création d'un contexte pour changer le namespace par défaut.
$ kubectl config set-context demo-context --namespace=demo --cluster=${K8S_CLUSTER} --user=${USERNAME}
Context "demo-context" created.

# Changement de contexte.
$ kubectl config use-context demo-context
Switched to context "demo-context".

Kubectl cheat sheet

Manifeste du pod que nous allons utiliser dans cette section

# pod.yaml
apiVersion: v1
kind: Pod # Ressource de type Pod.
metadata:
  name: wordpress # Nom du pod à créer.
  namespace: demo # Namespace dans lequel la ressource va être créée.
spec:
  containers: # Spécification du Pod.
    # Liste des containers à créer.
    - name: wordpress
      image: "nexus.caillou.sh:8443/wordpress:latest"

Kubectl cheat sheet

Création ou mise à jour d'une ressource via un manifeste

$ kubectl apply -f pod.yaml
pod/wordpress created

Kubectl cheat sheet

Affichage d'une ressource

# Ici le `-n demo` est facultatif, comme notre contexte a été changé pour mettre ce namespace par défaut.
$ kubectl get pods -n demo
NAME        READY   STATUS    RESTARTS   AGE
wordpress   1/1     Running   0          96s

Kubectl cheat sheet

Affichage d'une ressource plus détaillée

$ kubectl get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP                NODE                     NOMINATED NODE   READINESS GATES
wordpress   1/1     Running   0          2m16s   192.168.183.162   node07.kube.caillou.sh   <none>           <none>

Kubectl cheat sheet

Description d'une ressource

$ kubectl describe pods wordpress
Name:             wordpress
Namespace:        demo
Priority:         0
Service Account:  default
Node:             node07.kube.caillou.sh/172.27.3.39
Start Time:       Fri, 05 Sep 2025 13:28:55 +0200
Labels:           <none>
Annotations:      cni.projectcalico.org/containerID: 3d4a8dc5fc5a966df0d18ff697fe28426347a68c768a7fb24425ee0b8b395609
                  cni.projectcalico.org/podIP: 192.168.183.170/32
                  cni.projectcalico.org/podIPs: 192.168.183.170/32
Status:           Running
IP:               192.168.183.170
IPs:
  IP:  192.168.183.170
Containers:
  wordpress:
    Container ID:   containerd://1c7d758645041bbcd8fef7a357e5259eaeb9498eaae59559efe11af7838fa32c
    Image:          nexus.caillou.sh:8443/wordpress:latest
    Image ID:       nexus.caillou.sh:8443/wordpress@sha256:c5f075fe71c9120e769edbf761bcf20bf0b73d72d49dfde042a06aafcdfef08d
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Fri, 05 Sep 2025 13:29:14 +0200
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-fqrgq (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True 
  Initialized                 True 
  Ready                       True 
  ContainersReady             True 
  PodScheduled                True 
Volumes:
  kube-api-access-fqrgq:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    Optional:                false
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  47s   default-scheduler  Successfully assigned demo/wordpress to node07.kube.caillou.sh
  Normal  Pulling    47s   kubelet            Pulling image "nexus.caillou.sh:8443/wordpress:latest"
  Normal  Pulled     28s   kubelet            Successfully pulled image "nexus.caillou.sh:8443/wordpress:latest" in 18.555s (18.555s including waiting). Image size: 262795710 bytes.
  Normal  Created    28s   kubelet            Created container: wordpress
  Normal  Started    28s   kubelet            Started container wordpress

Kubectl cheat sheet

Mise à jour d'une ressource

$ diff pod.yaml pod-version.yaml
11c11
<       image: "nexus.caillou.sh:8443/wordpress:latest"
---
>       image: "nexus.caillou.sh:8443/wordpress:6.8"
$ kubectl apply -f pod-version.yaml
pod/wordpress configured

Kubectl cheat sheet

Affichage des logs d'un pod

$ kubectl logs wordpress
WordPress not found in /var/www/html - copying now...
Complete! WordPress has been successfully copied to /var/www/html
[05-Sep-2025 11:30:58] NOTICE: fpm is running, pid 1
[05-Sep-2025 11:30:58] NOTICE: ready to handle connections

Kubectl cheat sheet

Execution de commande dans un pod

$ kubectl exec -it wordpress -- ls -l /var/www/html
total 244
-rw-r--r--  1 www-data www-data   405 Feb  6  2020 index.php
-rw-r--r--  1 www-data www-data 19903 Mar  6  2025 license.txt
-rw-r--r--  1 www-data www-data  7425 Mar  7 08:45 readme.html
-rw-r--r--  1 www-data www-data  7387 Feb 13  2024 wp-activate.php
drwxr-xr-x  9 www-data www-data  4096 Jul 15 15:09 wp-admin
-rw-r--r--  1 www-data www-data   351 Feb  6  2020 wp-blog-header.php
-rw-r--r--  1 www-data www-data  2323 Jun 14  2023 wp-comments-post.php
-rw-r--r--  1 www-data www-data  5818 Aug 13 21:07 wp-config-docker.php
-rw-r--r--  1 www-data www-data  3336 Oct 15  2024 wp-config-sample.php
drwxr-xr-x  5 www-data www-data  4096 Jul 14 09:24 wp-content
-rw-r--r--  1 www-data www-data  5617 Aug  2  2024 wp-cron.php
drwxr-xr-x 30 www-data www-data 16384 Jul 15 15:09 wp-includes
-rw-r--r--  1 www-data www-data  2502 Nov 26  2022 wp-links-opml.php
-rw-r--r--  1 www-data www-data  3937 Mar 11  2024 wp-load.php
-rw-r--r--  1 www-data www-data 51414 Feb  3  2025 wp-login.php
-rw-r--r--  1 www-data www-data  8727 Feb  8  2025 wp-mail.php
-rw-r--r--  1 www-data www-data 30081 Mar  4  2025 wp-settings.php
-rw-r--r--  1 www-data www-data 34516 Mar 10 18:16 wp-signup.php
-rw-r--r--  1 www-data www-data  5102 Oct 18  2024 wp-trackback.php
-rw-r--r--  1 www-data www-data  3205 Nov  8  2024 xmlrpc.php

Kubectl cheat sheet

Suppression d'une ressource

$ kubectl delete -f pod-version.yaml
pod "wordpress" deleted

Kubectl cheat sheet

Résumé des commandes

kubectl apply -f "${MANIFESTE}"  # Création ou mise à jour d'une ressource
kubectl get pods -n "${NAMESPACE}"  # Affichage d'une ressource
kubectl get pods -n "${NAMESPACE}" -o wide  # Affichage d'une ressource plus détaillée
kubectl get pods -n "${NAMESPACE}" -o wide -w  # Affichage d'une ressource plus détaillée, et watch les résultats
kubectl describe "${RESOURCE_TYPE}" -n "${NAMESPACE}" "${RESOURCE_NAME}"  # Description d'une ressource
kubectl apply -f "${MANIFESTE}"  # Mise à jour d'une ressource
kubectl delete -f "${MANIFESTE}"  # Suppression d'une ressource
kubectl logs -n "${NAMESPACE}" "${POD_NAME}"  # Affichage des logs d'un pod
kubectl logs -f -n "${NAMESPACE}" "${POD_NAME}"  # Affichage des logs d'un pod en continue
kubectl exec -it -n "${NAMESPACE}" "${POD_NAME}" -- "${CMD}"  # Execution de commande dans un pod
kubectl port-forward "${POD_NAME}" "${LOCAL_PORT}:${POD_PORT}"  # Forward un port local vers un pod du container

whale-pod

3. Pods

A pod is a term used to describe a group of marine mammals, such as whales,
dolphins, or seals, that travel together.

Définition

Les pods sont les plus petites entités déployables de K8s. Ils sont composés d'un ou plusieurs conteneurs, tournant ensemble sur le même noeud.

Sidecars

Les sidecars sont les conteneurs secondaires qui tournent dans un pod. Pour savoir s'il vaut mieux créer plusieurs pods, ou un seul pod avec plusieurs containers, il suffit en général de répondre à la question :

Est-ce que ces conteneurs vont fonctionner correctement s'ils sont déployés sur des machines différentes ?

Si la réponse est non, il vaut mieux grouper les containers dans un pod. En revanche, s'il n'y avait pas de soucis de fonctionnement sur deux serveurs, plusieurs pods avec un seul conteneur devraient être créés.

Une utilisation répandue des sidecars est d'ajouter un conteneur pour la configuration réseau du pod.

Volumes

Comme les changements sur les file systems des containers ne sont pas persistant, K8s permet de creer des volumes, qui seront monte dans les containers.
Il y a differents types de volumes present par default:

  • emptyDir: dossier temporaire partager par les containers dans le pod.
  • hostPath: partage un dossier de la machine hote vers le container. Aussi utiliser pour acceder au composants physiques du serveur.
  • ConfigMaps / Secret: exporte une config kubernetes en tant que fichiers.
  • PersistentVolume (PV): permets d'allouer des resources de stockage de maniere abstraite.

Il est possible d'ajouter d'autres solution de stockage, grace au PersistentVolume.

Volumes

Manifeste

  containers:
      ...
      volumeMounts:
        - mountPath: /var/lib/postgresql/data
          name: postgres-data-volume
      ...
  volumes:
  - name: postgres-data-volume
    nfs:
      server: synology.caillou.sh
      path: /volume1/wordpress_demo_itinov/postgres

Health check

Il est possible de mettre en place des sondes pour vérifier l'état des conteneurs. Les sondes peuvent vérifier l'état du conteneur de différentes manières :

  • En se connectant au conteneur avec des requêtes HTTP.
  • Utilisant un socket TCP pour communiquer avec l'application dans le conteneur.
  • Exécutant un binaire à l'intérieur du conteneur.

Il y a deux types de sondes :

  • Readiness : cette sonde va être utilisée pour déterminer si le pod est en état d'accepter des connexions.
  • Liveness: cette sonde vérifie que le conteneur est toujours en bonne santé, et n'a pas besoin d'être redéployé.

Health check

Manifeste

livenessProbe:
  httpGet:
    path: "/health"
    port: 80
  initialDelaySeconds: 5
  timeoutSeconds: 1
  periodSeconds: 10
  failureThreshold: 3
readinessProbe:
  httpGet:
    path: "/health"
    port: 80
  initialDelaySeconds: 5
  timeoutSeconds: 1
  periodSeconds: 10
  failureThreshold: 3

Management des ressources

Requête

K8s permet de quantifier les ressources requises pour faire tourner un conteneur. Il est possible de définir la RAM minimale requise, et le minimum de CPU à allouer au conteneur.
Le management des ressources ne se limite pas seulement à ces metrics, il est par exemple également possible d'allouer des GPUs.

Management des ressources

Limite

Un maximum peut également être défini pour ces deux metrics, lorsque le conteneur essaye d'allouer de la RAM au-delà du maximum autorisé, il va être OOM Killed.
La limite maximum du CPU, quant à elle, définit le maximum du CPU que le conteneur pourra utiliser.

Management des ressources

Manifeste

resources:
  requests:
    memory: "250Mi" # Peut-être représenté en Mebibit (Mi: 2^10), en Gibibit (Gi: 2^20), en Megabit (M: 10^3), ou en Gigabit (G: 10^6)
    cpu: "100m" # m représente l'unité `milli` (10^-3).
  limits:
    memory: "500Mi"
    cpu: "200m"

Fonctionnement de la création

Slide technique

Pour créer un pod, il faut envoyer un manifeste au serveur d'API de K8s.
Une fois le manifeste traité par l'API, le scheduler va planifier le déploiement du pod sur une machine, en fonction des ressources demandées et disponibles sur les machines.
Quand le pod a un nœud d'attribué, il est déployé par le service kubelet du nœud correspondant. Le service kubelet est responsable de tout le cycle de vie du pod, de la création à la suppression, en passant par le monitoring.

Kubectl

# Creation d'un pod a partir d'une image
# TODO: idk why this doesn't run on my infra rn.
kubectl run -n demo shell --image=alpine -it --command -- bash

Kubectl

Manifeste du pod que nous allons utiliser dans cette section

# pod-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: wordpress
  namespace: "demo"
spec:
  containers:
    - name: wordpress
      image: "nexus.caillou.sh:8443/wordpress:6.8"
      ports:
      - name: wordpress-port # Nomme un port, afin de faciliter sa réutilisation.
        containerPort: 80
      resources:
        requests:
          memory: "250Mi"
          cpu: "100m"
        limits:
          memory: "500Mi"
          cpu: "200m"
      livenessProbe:
        httpGet:
          # Path temporaire, comme Wordpress n'est pas configuré.
          path: "/wp-admin/setup-config.php"
          port: wordpress-port
        initialDelaySeconds: 10
        timeoutSeconds: 10
        periodSeconds: 10
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: "/wp-admin/setup-config.php"
          port: wordpress-port
        initialDelaySeconds: 10
        timeoutSeconds: 10
        periodSeconds: 10
        failureThreshold: 3

Kubectl

Manipularion du nouveau pod

# Creation du pod depuis le manifeste.
$ kubectl apply -f pod-resources.yaml
pod/wordpress created

# Vérification du statut du pod juste après la création.
# Il y a 0/1 pod ready, car le ReadinessCheck n'est pas encore réussi sur le pod.
$ kubectl get pods
NAME        READY   STATUS    RESTARTS   AGE
wordpress   0/1     Running   0          10s

# Après quelques instants, le pod est prêt à recevoir des connexions.
$ kubectl get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP                NODE                     NOMINATED NODE   READINESS GATES
wordpress   1/1     Running   0          2m28s   192.168.183.154   node07.kube.caillou.sh   <none>           <none>

# Pour se connecter depuis un navigateur au nouvea pod, via l'adresse: http://localhost:8080
$ kubectl port-forward "wordpress" "8080:80"
Forwarding from 127.0.0.1:8080 -> 80
Handling connection for 8080

Kubectl

Description du nouveau pod

# Affichage des informations du pod cree.
$ kubectl describe pods -n demo atelier-kube
Name:             wordpress
Namespace:        demo
...
Containers:
  wordpress:
    ...
    Limits:
      cpu:     200m
      memory:  500Mi
    Requests:
      cpu:        100m
      memory:     250Mi
    Liveness:     http-get http://:wordpress-port/wp-admin/setup-config.php delay=10s timeout=10s period=10s #success=1 #failure=3
    Readiness:    http-get http://:wordpress-port/wp-admin/setup-config.php delay=10s timeout=10s period=10s #success=1 #failure=3
    ...
...

4. Labels / Annotations

kube.atelier.caillou.eu/git-commit-sha: a63b8713

kube.atelier.caillou.eu/git-commit-url: https://gitlab.caillou.eu/caillou/atelier-devops-kube/-/commit/a63b8713

Labels

Les labels permettent d'identifier et grouper des objets, les sélecteurs de K8 filtrent grâce aux labels.
Ce sont des données d'identification, qui permettent d'isoler une ressource.

metadata:
  labels:
    environment: "production"
    category: "database"
    app: "postgres"

Annotations

Contrairement aux labels, les annotations servent à stocker des métadonnées, qui apportent seulement des informations supplémentaires.
Elles peuvent, par exemple, être utilisées pour stocker des configurations d'outils d'administration.

metadata:
  annotations:
    kubernetes.io/change-cause: "Update to green deployment"
    cni.projectcalico.org/containerID: "b9605f905dd56f6d0f6c851c43a2b003e441b0d9f695707ed1e33678ff9d6254"
    cni.projectcalico.org/podIP: "192.168.183.162/32"
    cni.projectcalico.org/podIPs: "192.168.183.162/32"

Kubectl

Manifeste des pods que nous allons utiliser dans cette section (1/2)

# pod-labels.yaml
apiVersion: v1
kind: Pod
metadata:
  name: wordpress
  namespace: demo
  labels:
    environment: "production"
spec:
  containers:
    - name: wordpress
      image: "nexus.caillou.sh:8443/wordpress:6.8"

Kubectl

Manifeste des pods que nous allons utiliser dans cette section (2/2)

# pod-labels.yaml
apiVersion: v1
kind: Pod
metadata:
  name: postgres
  namespace: demo
  labels:
    environment: "prod"
    category: "database"
    app: "postgres"
spec:
  containers:
    - name: postgres
      image: "nexus.caillou.sh:8443/postgres:17.6"
      env:
        - name: "POSTGRES_PASSWORD"
          value: "qweqwe"

Kubectl

Manipulation des labels

# # Création des pods à partir du manifeste.
$ kubectl apply -f pod-labels.yaml
pod/wordpress created
pod/postgres created

# Affichage des pods avec les labels.
$ kubectl get pods --show-labels
NAME        READY   STATUS    RESTARTS   AGE   LABELS
postgres    1/1     Running   0          23s   app=postgres,category=database,environment=prod
wordpress   1/1     Running   0          23s   environment=production

# Création d'un label.
$ kubectl label pods wordpress "app=wordpress" "test=true"
pod/wordpress labeled

# Affichage des pods avec les labels, filtrant sur test=true
$ kubectl get pods --show-labels --selector="test=true"
NAME        READY   STATUS    RESTARTS   AGE     LABELS
wordpress   1/1     Running   0          3m43s   app=wordpress,environment=production,test=true

# Suppression du label test.
$ kubectl label pods wordpress "test-"
pod/wordpress unlabeled

# Affichage des pods avec les labels, filtrant sur test=true
$ kubectl get pods --show-labels --selector="test=true"
No resources found in demo namespace.

5. Services

services

Absolutely horrible army recruiters close at 1pm.
No wonder us military has become so bad.

Définition

Les services permettent d'exposer des ressources, via un point d'entrée commun à tous les backends de cette ressource. Ce point d'entrée permet d'exposer le cluster au trafic extérieur.

Noms de domaines

Les ressources dans le même namespace peuvent y accéder de la même manière, ou via juste le nom du service.
Kubernetes crée des noms de domaines pour les services qu'il crée. Ils sont accessibles pour les ressources n'appartenant pas au même namespace via les noms suivants: {service_name}.{namespace_name}.svc.cluster.local ou {service_name}.{namespace_name}.

Types de services

Cluster IP: Assigne une IP virtuelle au service.
NodePort: Forward tout le trafic reçu sur un port assigné, sur toutes les machines du cluster, vers ce service.
Load Balancer: Basé sur le NodePort, en ajoutant la création d'un load balancer redirigeant vers votre cluster.

Services discovery

L'adresse du service ne change pas, contrairement à celle des ressources, qui doivent pouvoir changer à la volée.
Le service Discovery permet de mettre en relation le point d'entrée du service, avec l'adresse dynamique d'une ressource qui est prête à recevoir des connexions.

Kubectl

Manifeste du service que nous allons utiliser dans cette section

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: "demo"
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: wordpress-port
  selector:
    app: "wordpress"

Kubectl

Creation et description du service

# Creation des pods a partir du manifeste
$ kubectl apply -f service.yaml
service/wordpress created

# Description du service wordpress
$ kubectl describe service wordpress
Name:                     wordpress
Namespace:                demo
Labels:                   <none>
Annotations:              <none>
Selector:                 app=wordpress
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.105.18.163
IPs:                      10.105.18.163
Port:                     <unset>  80/TCP
TargetPort:               wordpress-port/TCP
Endpoints:                192.168.183.179
Session Affinity:         None
Internal Traffic Policy:  Cluster
Events:                   <none>

# Test de l'endpoint du service
$ curl http://192.168.183.179/wp-admin/setup-config.php
HTTP/1.1 200 OK
Date: Fri, 05 Sep 2025 17:29:26 GMT
Server: Apache/2.4.65 (Debian)
X-Powered-By: PHP/8.2.29
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Content-Type: text/html; charset=utf-8

6. Ingress

Ingress: the act of entering something.

Ingress

K8s nomme son Load Balancer HTTP Ingress.
Il permet à Kubernetes d'héberger plusieurs services HTTP avec le même endpoint. Pour ce faire, il différencie la destination des requêtes via l'hôte spécifié dans la requête HTTP. Il va rediriger le trafic vers le bon service, en se basant sur les labels du service.

Spécification

L'ingress est défini via des spécifications, puis implémenté par des contrôleurs. Chaque contrôleur implémente ses spécifications à leur manière, et peut avoir des features supplémentaires. Un contrôleur très commun est Nginx.

Kubectl

Manifeste de l'ingress que nous allons utiliser dans cette section

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress-ingress
  namespace: "demo"
  annotations:
    spec.ingressClassName: "nginx"
spec:
  ingressClassName: nginx
  rules:
  - host: wordpress.atelier.caillou.eu
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: wordpress
            port:
              name: wordpress-port

Kubectl

Manifeste du pod que nous allons utiliser dans cette section

# pod-final.yaml
apiVersion: v1
kind: Pod
metadata:
  name: wordpress
  namespace: "demo"
  labels:
    environment: "production"
    app: "wordpress"
spec:
  containers:
    - name: wordpress
      image: "nexus.caillou.sh:8443/wordpress:6.8"
      ports:
      - name: wordpress-port # Nomme un port, afin de faciliter sa réutilisation.
        containerPort: 80
      resources:
        requests:
          memory: "250Mi"
          cpu: "100m"
        limits:
          memory: "500Mi"
          cpu: "200m"
      livenessProbe:
        httpGet:
          # Path temporaire, comme Wordpress n'est pas configuré.
          path: "/wp-admin/setup-config.php"
          port: wordpress-port
        initialDelaySeconds: 10
        timeoutSeconds: 10
        periodSeconds: 10
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: "/wp-admin/setup-config.php"
          port: wordpress-port
        initialDelaySeconds: 10
        timeoutSeconds: 10
        periodSeconds: 10
        failureThreshold: 3

kubectl

Manipulation de l'ingress

# Création de l'ingress
$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/wordpress-ingress created

# Description de l'ingress
$ kubectl describe ingress wordpress-ingress
Name:             wordpress-ingress
Labels:           <none>
Namespace:        demo
Address:          172.27.3.200
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host                          Path  Backends
  ----                          ----  --------
  wordpress.atelier.caillou.eu  
                                /   wordpress:wordpress-port (192.168.183.179)
Annotations:                    spec.ingressClassName: nginx
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    55s (x2 over 68s)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    55s (x2 over 68s)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    55s (x2 over 68s)  nginx-ingress-controller  Scheduled for sync

kubectl

Démonstration d'une requête

# Vérification de l'adresse IP du domaine wordpress.atelier.caillou.eu
$ ping -c 1 wordpress.atelier.caillou.eu
PING kube.caillou.eu (192.168.45.80) 56(84) bytes of data.
64 bytes from haproxy.kube.caillou.sh (192.168.45.80): icmp_seq=1 ttl=64 time=10.1 ms

--- kube.caillou.eu ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 10.094/10.094/10.094/0.000 ms

# Requete avec le nom de domaine.
$ curl http://wordpress.atelier.caillou.eu/wp-admin/setup-config.php
HTTP/1.1 200 OK
Date: Sat, 06 Sep 2025 15:32:50 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
X-Powered-By: PHP/8.2.29
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private

7. ReplicaSet

⭐ 1/10 - This... is extraordinarily bad

I honestly just don't know where to begin. I think I'm just going to ask... how did a script like this get made. How. This is beyond mind boggling. A script so incredibly bad that it brings down pretty cool production design, cinematography and acting to an embarrassing level. This quite literally feels like a 5 year old child wanted to write a science fiction movie. Everything about the story, the dialog, the sci fi conceptual framework, it was all written horribly. Wish I could be more positive here and forgiving like I am with nearly every movie I see but this was confusingly bad. I don't understand how a script in this condition could possibly get made. Keanu Reeves and the production team are certainly not at fault here, they did what they could with such an embarrassingly bad story.

Définition

Les ReplicaSet permettent d'orchestrer des pods. Automatisant leur création et suppression, et gérant les pods non réactifs.
La définition des pods à l'intérieur d'un ReplicaSet est la même que pour la création d'un Pod.
Les principales raisons d'utiliser un ReplicaSet:

  • Redondance: Tolérance aux erreurs grâce aux multiples instances.
  • Scale: Avoir plusieurs instances permet de gérer plus de requêtes.
  • FragmentationSharding: Les pods répliqués peuvent calculer différentes parties en parallèle.

Reconciliation Loops

Slide technique

Les réconciliations loops sont la base du concept des ReplicaSet. Elles tournent en arrière-plan, et vont constamment comparer l'état actuel du système avec l'état désiré. En cas de déviation du système actuel, elles vont prendre des actions afin d'essayer de le faire correspondre à l'état désiré.

Details d'implementation

Slide technique

Les ReplicaSet ne sont pas propriétaires des Pods créés, ils utilisent des labels pour savoir quels Pods leur appartiennent. Pour gérer ces pods, ils utilisent la même API que celle exposée aux utilisateurs, ce qui permet d'avoir une template de définition des pods homogène.
Cette gestion des pods permet de retirer des Pods de la liste de gestion du ReplicaSet, pour par exemple retirer un pod en erreur et le débugger, sans affecter les performances de la production.

Scaling

scaling-graph

Scaling

Comme mentionné précédemment, les ReplicaSet ont des capacités de scaling. Mais le nombre de Pods désiré est souvent variable, et le prérequis est juste qu'il faut "assez" de replicas.
Pour ce faire Kubernetes propose du scaling dynamique via 2 manières différentes, l'Horizontal Pod Autoscaler (HPA), ou le Vertical Pod Autoscaler (VPA). Les deux peuvent être déclenchés via des metrics classiques, comme l'utilisation CPU ou RAM, ou des metrics custom.

  • Horizontal Pod Autoscaler: Ajoute ou supprime des pods via le ReplicaSet.
  • Vertical Pod Autoscaler: Attribue automatiquement les requêtes de CPU et RAM des Pod.

Kubectl

Exemple de manifeste

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: wordpress
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: wordpress
        version: "6.8.2"
    spec:
      containers:
        ... Définition de pod

Kubectl

Demo commune avec les Deployments, ReplicaSet, et DaemonSet.

8. Deployments

pods-group-question

Définition

Les deployments existent pour manager les sorties de nouvelles versions. Ils décrivent une application déployée, d'une manière qui transcende toute version particulière.
Ils permettent aussi de faciliter le changement de version, que ce soit une montée de version, ou une restauration de version, grâce au processus de "rollout".
De la même manière que les ReplicaSets gèrent des Pods, les Deployments gèrent des ReplicaSets.

Rollout

Lors d'un changement de version, un batch de pods va être mis à jour. La taille du batch est, sauf exceptions, plus petite que le nombre de pods défini dans le Deployment. Lorsque ces pods sont prêts, ce qui est défini grâce à la probe ReadinessCheck, K8s peut passer au batch de pods à mettre à jour suivant.
Toutes les facettes de ce processus sont configurables.

strategy:
  type: RollingUpdate # RollingUpdate ou Recreate
  rollingUpdate:
    maxUnavailable: 1  # Nombre de pods maximale pouvant etre indisponible pendant l'update
    maxSurge: 1        # Nombre de pods supplementaire pouvant etre deploye pendant l'update

Erreur lors d'un rollout

Si une erreur survient lors d'un batch, K8s va appliquer le comportement choisi par l'utilisateur, comme par exemple restaurer la version précédente.
Un rollout peut être suspendu, stoppé, ou repris à tout moment par l'utilisateur.
K8s garde un historique de rollout, dont sa taille est modifiable.

Kubectl

Exemple de manifeste

apiVersion: apps/v1
kind: Deployments
metadata:
  name: wordpress
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: wordpress
        version: "6.8.2"
    spec:
      containers:
        ... Définition de pod

Kubectl

Demo commune avec les Deployments, ReplicaSet, et DaemonSet.

9. DaemonSet

Demon's Souls is a 2009 action role-playing game developed by FromSoftware and published by Sony Computer Entertainment for the PlayStation 3.

Définition

Les DaemonSet sont semblables aux ReplicaSet, à la différence qu'ils s'assurent qu'une copie de leur pod tourne sur chaque nœud défini d'un cluster. Ils peuvent être déployés sur tout un cluster, ou en limitant les noeuds sur lesquels il est présent.
Les DaemonSet peuvent également utiliser les mêmes stratégies de mise à jour que les Deployment.

Différences avec ReplicaSet

Les ReplicaSet doivent être utilisés quand l'applicatif est complètement découpé du nœud sur lequel il tourne, et plusieurs copies peuvent fonctionner sur un même noeud sans considération particulière.
Les DaemonSet, eux, quand une seule copie de l'application doit être présente sur tous les noeuds, ou un sous-ensemble de nœuds du cluster.

Architecture découplée

Slide technique

Les DaemonSet et ReplicaSet sont de bons exemples de la qualité de l'architecture découplée de K8s.
Toutes les commandes utilisées pour manager les pods dans un ReplicaSet sont les mêmes pour les pods créés par les DaemonSet

(c'est des micro-services en gros)

Comparaison avec ReplicaSet et Deployment

DaemonSet ReplicaSet Deployment
Pods déployé sur tous les noeuds. A ne pas utiliser, globalement. À utiliser 99 % du temps, Pods déployé où Kube a envie.

Kubectl

Démonstration manuelle

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
  namespace: "demo"
spec:
  selector:
    matchLabels:
      app: wordpress
  replicas: 3
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
        - name: wordpress
          image: "nexus.caillou.sh:8443/wordpress:6.8"
          ports:
          - name: wordpress-port
            containerPort: 80
          resources:
            requests:
              memory: "250Mi"
              cpu: "100m"
            limits:
              memory: "500Mi"
              cpu: "200m"
          livenessProbe:
            httpGet:
              path: "/"
              port: wordpress-port
            initialDelaySeconds: 10
            timeoutSeconds: 10
            periodSeconds: 10
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: "/"
              port: wordpress-port
            initialDelaySeconds: 10
            timeoutSeconds: 10
            periodSeconds: 10
            failureThreshold: 3
          volumeMounts:
            - mountPath: /var/www/html
              name: wordpress-data-volume
      volumes:
      - name: wordpress-data-volume
        nfs:
          server: synology.caillou.sh
          path: /volume1/wordpress_demo_itinov/wordpress

10. ConfigMaps et Secrets

pikachu-cm

Definition

Les ConfigMaps sont utilisés pour approvisionner les pods avec des informations de configuration. Ce sont des configurations de type clé, valeur.
Les Secrets sont similaires, mais stockés en Base64, et utilisés pour des données sensibles.

apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-config
  namespace: "demo"
  labels:
    app: postgres
    type: configmap
    version: "17.6"
data:
  postgres-db: wordpress
  postgres-user: wordpress_user
  postgres-password: "k4CbAzr**MK@*MapwzNzA2&k$y@A*UjDvYS#B"

Utilisation

Les ConfigMaps peuvent être utilisés de deux manières principales:

  • Environment: les configmaps peuvent aussi être utilisés comme des variables d'environnement, ou des arguments de CLI.
  • FileSystem: les configmaps peuvent être montés comme des volumes, les clés deviennent des noms de fichier, et la valeur le contenu des fichiers.

Backend des secrets

Slide technique

Le stockage des secrets par défaut n'est pas chiffré, et est stocké directement sur etcd.
Il est possible de changer le backend dans lequel sont stockés les secrets du cluster, par exemple pour GKE, Google utilise KMS par défaut.

Kubectl

Manifeste d'exemple

apiVersion: v1
kind: Pod
metadata:
  name: postgres
  namespace: demo
  labels:
    environment: "prod"
    category: "database"
    app: "postgres"
spec:
  containers:
    - name: postgres
      image: "nexus.caillou.sh:8443/postgres:17.6"
      imagePullPolicy: Always
      command:
        - "/kuard"
      env: # Environnement depuis une configmap.
        - name: "POSTGRES_USER"
          valueFrom:
            configMapKeyRef:
              name: postgres-config
              key: postgres-user
        - name: "POSTGRES_PASSWORD"
          valueFrom:
            configMapKeyRef:
              name: postgres-config
              key: postgres-password
        - name: "POSTGRES_DB"
          valueFrom:
            configMapKeyRef:
              name: postgres-config
              key: postgres-db
      volumeMounts: # Volume depuis une ConfigMaps
        - name: config-volume
          mountPath: /config
  volumes:
    - name: config-volume
      configMap:
        name: my-config
  restartPolicy: Never

11. RBAC

Retarded BACcalauréat

alphabet

Role Based Access Control

Implémentation de sécurité basée sur des rôles, comme dans tous les clouds....

12. Pour aller plus loin (que la slide 92)

Vous pouvez également vous renseigner sur:

  • Helm
  • ArgoCD
  • FluxCD

14. ArgoCD

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
:))))))))))))))))))))))))

really-happy

# Qu'est-ce que c'est ?

![top-right-image](./images/logo-definition.png)

TODO: Talk about etcd, kube-api-server, controller-manager

![top-right-image](./images/immutable.png)

![top-right-image](./images/json-config.png)

![top-right-image](./images/self-healing.png)

![top-right-image](./images/microservices.png)

![top-right-image](./images/scaling.png)

![top-right-image](./images/abstract.png)

![top-right-image](./images/logo-definition.png)

![top-right-image](./images/namespace.png)

![top-right-image](./images/context.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube-small](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube-small](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![no-ice-cube](./images/no-ice-cube.png)

![top-right-image](./images/logo-definition.png)

![top-right-image](./images/moto-sidecar.png)

![top-right-image](./images/volumes.png)

![no-ice-cube](./images/no-ice-cube.png)

TODO: add manifeste for volume, when storage section is done.

![no-ice-cube-small](./images/no-ice-cube.png)

![top-right-image](./images/requirements.png)

![top-right-image](./images/limit.png)

![no-ice-cube](./images/no-ice-cube.png)

TODO: add kubectl command to create a pod

Premiere demo interactive, presenter la creation du pod, et le port-forward pour me connecter au pod

![top-right-image](./images/logo-definition.png)

TODO: finish this kubectl

```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress namespace: "demo" spec: rules: - host: demo.example.com http: paths: - backend: service: name: demo port: number: 80 ```

TODO: finish this slide

![top-right-image](./images/logo-definition.png)

Maybe cut this slide out

Cut this one first lmfao

TODO: add manifest example.

TODO: add kubectl scaling from cli, with warning that not best practice

![top-right-image](./images/logo-definition.png)

TODO: do the kubectl part of daemonset

TODO: find a quote

TODO: find a quote