34 min de lecture · 7 282 mots

Kubernetes : Ressources, commandes kubectl, et configurations

Kubernetes : Ressources, commandes kubectl, et configurations

Introduction à Kubernetes

Architecture de base

Cluster Kubernetes:

- Control Plane (Master):

- API Server (kube-apiserver)

- Scheduler (kube-scheduler)

- Controller Manager (kube-controller-manager)

- etcd (base de données)

# - Nodes (Workers):

- kubelet (agent)

- kube-proxy (réseau)

- Container Runtime (Docker, containerd, CRI-O)

Vérifier version

kubectl version --short

Informations cluster

kubectl cluster-info kubectl get componentstatuses kubectl get nodes kubectl describe node

Configuration kubectl

Fichier de config par défaut: ~/.kube/config

Afficher la config

kubectl config view

Contextes (cluster + user + namespace)

kubectl config get-contexts kubectl config current-context kubectl config use-context

Créer un contexte

kubectl config set-context dev --cluster=dev-cluster --user=dev-user --namespace=development

Changer de namespace par défaut

kubectl config set-context --current --namespace=production

Clusters

kubectl config get-clusters kubectl config set-cluster --server=https://k8s.example.com:6443 --certificate-authority=/path/to/ca.crt

Users (credentials)

kubectl config set-credentials admin --client-certificate=/path/to/admin.crt --client-key=/path/to/admin.key kubectl config set-credentials user --token=

Supprimer

kubectl config delete-context kubectl config delete-cluster kubectl config delete-user

Commandes kubectl essentielles

Syntaxe générale

Structure: kubectl [commande] [type] [nom] [flags]

Commandes principales:

get - Lister ressources

describe - Détails d'une ressource

create - Créer depuis fichier

apply - Appliquer config (create/update)

delete - Supprimer ressource

edit - Éditer ressource

exec - Exécuter dans container

logs - Afficher logs

port-forward - Redirection port

Flags courants:

-n, --namespace - Spécifier namespace

-o, --output - Format sortie (yaml, json, wide, name)

-w, --watch - Surveiller changements

-l, --selector - Filtrer par labels

--all-namespaces - Toutes les namespaces

--dry-run=client - Simulation

-f, --filename - Fichier config

Commandes de base

GET - Lister ressources

kubectl get pods kubectl get pods -n kube-system kubectl get pods --all-namespaces kubectl get pods -o wide # Plus de colonnes kubectl get pods -o yaml # Format YAML kubectl get pods -o json # Format JSON kubectl get pods -o name # Seulement les noms kubectl get pods --show-labels # Afficher labels kubectl get pods -l app=nginx # Filtrer par label kubectl get pods --field-selector status.phase=Running kubectl get pods -w # Watch (surveiller)

Multiples ressources

kubectl get pods,services kubectl get all # Toutes ressources principales kubectl get all -A # Tous namespaces

DESCRIBE - Détails

kubectl describe pod kubectl describe node kubectl describe service

CREATE - Créer

kubectl create -f pod.yaml kubectl create -f ./configs/ # Dossier kubectl create namespace dev kubectl create deployment nginx --image=nginx kubectl create service clusterip my-svc --tcp=80:80

APPLY - Appliquer (recommandé)

kubectl apply -f pod.yaml kubectl apply -f ./configs/ kubectl apply -k ./kustomize-dir/ # Kustomize

DELETE - Supprimer

kubectl delete pod kubectl delete -f pod.yaml kubectl delete pods --all kubectl delete pods -l app=nginx kubectl delete namespace dev kubectl delete all --all -n dev # Tout dans namespace

EDIT - Éditer

kubectl edit pod kubectl edit deployment

SCALE - Mettre à l'échelle

kubectl scale deployment nginx --replicas=5 kubectl scale statefulset mysql --replicas=3

ROLLOUT - Gestion déploiements

kubectl rollout status deployment/nginx kubectl rollout history deployment/nginx kubectl rollout undo deployment/nginx kubectl rollout undo deployment/nginx --to-revision=2 kubectl rollout restart deployment/nginx kubectl rollout pause deployment/nginx kubectl rollout resume deployment/nginx

EXEC - Exécuter dans container

kubectl exec -- ls /app kubectl exec -it -- bash kubectl exec -it -c -- sh

LOGS - Afficher logs

kubectl logs kubectl logs -f # Follow kubectl logs -c kubectl logs --previous # Container précédent kubectl logs --since=1h kubectl logs --tail=100 kubectl logs -l app=nginx # Par label

PORT-FORWARD - Redirection port

kubectl port-forward pod/ 8080:80 kubectl port-forward service/ 8080:80 kubectl port-forward deployment/ 8080:80

CP - Copier fichiers

kubectl cp :/path/to/file ./local-file kubectl cp ./local-file :/path/to/file

TOP - Métriques (nécessite metrics-server)

kubectl top nodes kubectl top pods kubectl top pods --containers

LABEL - Gérer labels

kubectl label pods env=prod kubectl label pods env=prod --overwrite kubectl label pods env-

ANNOTATE - Gérer annotations

kubectl annotate pods description="Application web" kubectl annotate pods description-

DRAIN - Vider node (maintenance)

kubectl drain kubectl drain --ignore-daemonsets kubectl drain --delete-emptydir-data --force

CORDON/UNCORDON - Empêcher scheduling

kubectl cordon kubectl uncordon

TAINT - Gérer taints

kubectl taint nodes key=value:NoSchedule kubectl taint nodes key=value:NoExecute kubectl taint nodes key- # Retirer

API-RESOURCES - Lister types ressources

kubectl api-resources kubectl api-resources --namespaced=true kubectl api-resources --api-group=apps

EXPLAIN - Documentation ressource

kubectl explain pod kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain deployment.spec.strategy

Pods

Pod simple

pod-simple.yaml

apiVersion: v1 kind: Pod metadata: name: nginx-pod namespace: default labels: app: nginx env: prod annotations: description: "Serveur web Nginx" spec: containers: - name: nginx image: nginx:1.24 ports: - containerPort: 80 name: http protocol: TCP env: - name: ENVVAR value: "production" resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"

Pod multi-containers

pod-multi.yaml

apiVersion: v1 kind: Pod metadata: name: webapp spec: containers: # Container principal - name: app image: myapp:1.0 ports: - containerPort: 8080 volumeMounts: - name: shared-data mountPath: /app/data # Sidecar: proxy - name: proxy image: nginx:1.24 ports: - containerPort: 80 volumeMounts: - name: nginx-config mountPath: /etc/nginx/nginx.conf subPath: nginx.conf - name: shared-data mountPath: /usr/share/nginx/html # Sidecar: log collector - name: log-collector image: fluent/fluentd:v1.16 volumeMounts: - name: shared-logs mountPath: /var/log volumes: - name: shared-data emptyDir: {} - name: shared-logs emptyDir: {} - name: nginx-config configMap: name: nginx-config

Init Containers

pod-init.yaml

apiVersion: v1 kind: Pod metadata: name: app-with-init spec: # Init containers (s'exécutent avant les containers principaux) initContainers: - name: init-db image: busybox:1.36 command: - sh - -c - | echo "Attente de la base de données..." until nslookup mysql-service; do echo "En attente..." sleep 2 done echo "Base de données prête!" - name: init-config image: busybox:1.36 command: - sh - -c - | echo "Génération configuration..." echo "configdata" > /config/app.conf volumeMounts: - name: config mountPath: /config # Containers principaux containers: - name: app image: myapp:1.0 volumeMounts: - name: config mountPath: /etc/app volumes: - name: config emptyDir: {}

Probes (Santé)

pod-probes.yaml

apiVersion: v1 kind: Pod metadata: name: app-with-probes spec: containers: - name: app image: myapp:1.0 ports: - containerPort: 8080 # Liveness Probe - Redémarre si échoue livenessProbe: httpGet: path: /health port: 8080 httpHeaders: - name: X-Custom-Header value: Health initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 successThreshold: 1 # Readiness Probe - Retire du service si échoue readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 # Startup Probe - Pour apps lentes au démarrage startupProbe: httpGet: path: /startup port: 8080 initialDelaySeconds: 0 periodSeconds: 10 failureThreshold: 30 # 30 10s = 5min max ---

Autres types de probes

apiVersion: v1 kind: Pod metadata: name: probe-examples spec: containers: - name: app image: myapp:1.0 # TCP Socket Probe livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 20 # Exec Probe (commande) readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5 # gRPC Probe (K8s 1.24+) startupProbe: grpc: port: 9090 initialDelaySeconds: 0 periodSeconds: 10

Ressources et Limites

pod-resources.yaml

apiVersion: v1 kind: Pod metadata: name: resource-demo spec: containers: - name: app image: myapp:1.0 resources: # Requests - Garanties minimales requests: memory: "256Mi" # 256 mebibytes cpu: "500m" # 500 milliCPU (0.5 CPU) ephemeral-storage: "2Gi" # Limits - Maximums limits: memory: "512Mi" # OOMKilled si dépassé cpu: "1000m" # Throttle si dépassé ephemeral-storage: "4Gi" ---

QoS Classes (automatique selon resources)

1. Guaranteed: requests = limits pour CPU et memory

apiVersion: v1 kind: Pod metadata: name: qos-guaranteed spec: containers: - name: app image: nginx resources: requests: memory: "200Mi" cpu: "700m" limits: memory: "200Mi" cpu: "700m" ---

2. Burstable: requests < limits

apiVersion: v1 kind: Pod metadata: name: qos-burstable spec: containers: - name: app image: nginx resources: requests: memory: "128Mi" limits: memory: "256Mi" ---

3. BestEffort: aucune request/limit

apiVersion: v1 kind: Pod metadata: name: qos-besteffort spec: containers: - name: app image: nginx

Sécurité Pod

pod-security.yaml

apiVersion: v1 kind: Pod metadata: name: secure-pod spec: # Security Context au niveau Pod securityContext: runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 fsGroupChangePolicy: "OnRootMismatch" seccompProfile: type: RuntimeDefault supplementalGroups: [4000, 5000] containers: - name: app image: myapp:1.0 # Security Context au niveau Container securityContext: allowPrivilegeEscalation: false privileged: false readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 2000 capabilities: drop: - ALL add: - NETBINDSERVICE seLinuxOptions: level: "s0:c123,c456" volumeMounts: - name: tmp mountPath: /tmp - name: cache mountPath: /app/cache volumes: - name: tmp emptyDir: {} - name: cache emptyDir: {} ---

Pod avec ServiceAccount

apiVersion: v1 kind: Pod metadata: name: pod-with-sa spec: serviceAccountName: my-service-account automountServiceAccountToken: true containers: - name: app image: myapp:1.0

Affinity et Anti-Affinity

pod-affinity.yaml

apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: # Node Affinity - Placement sur nodes affinity: nodeAffinity: # Required - DOIT matcher requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - node-1 - node-2 - key: node-type operator: NotIn values: - spot # Preferred - Préférence (non bloquant) preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: zone operator: In values: - zone-a - weight: 50 preference: matchExpressions: - key: disk operator: In values: - ssd containers: - name: app image: myapp:1.0 ---

Pod Affinity/Anti-Affinity - Placement relatif aux autres Pods

apiVersion: v1 kind: Pod metadata: name: with-pod-affinity labels: app: web spec: affinity: # Pod Affinity - Proche d'autres pods podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - cache topologyKey: kubernetes.io/hostname preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: database topologyKey: zone # Pod Anti-Affinity - Éloigné d'autres pods podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: web topologyKey: kubernetes.io/hostname containers: - name: web image: nginx:1.24 ---

NodeSelector (simple)

apiVersion: v1 kind: Pod metadata: name: with-node-selector spec: nodeSelector: disktype: ssd environment: production containers: - name: app image: myapp:1.0

Taints et Tolerations

Appliquer taint sur node:

kubectl taint nodes node1 key=value:NoSchedule

kubectl taint nodes node1 key=value:NoExecute

kubectl taint nodes node1 key=value:PreferNoSchedule

pod-tolerations.yaml

apiVersion: v1 kind: Pod metadata: name: with-tolerations spec: tolerations: # Tolère taint exact - key: "node-role" operator: "Equal" value: "database" effect: "NoSchedule" # Tolère n'importe quelle valeur pour la clé - key: "environment" operator: "Exists" effect: "NoExecute" # Tolère pendant 300s avant éviction - key: "node.kubernetes.io/unreachable" operator: "Exists" effect: "NoExecute" tolerationSeconds: 300 # Tolère tous les taints - operator: "Exists" containers: - name: app image: myapp:1.0

Deployments

Deployment basique

deployment-basic.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx annotations: kubernetes.io/change-cause: "Update to nginx 1.24" spec: # Nombre de replicas replicas: 3 # Sélecteur pods selector: matchLabels: app: nginx # Template Pod template: metadata: labels: app: nginx version: v1 spec: containers: - name: nginx image: nginx:1.24 ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "100m" limits: memory: "128Mi" cpu: "200m"

Stratégies de déploiement

deployment-strategies.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: app-rolling spec: replicas: 5 # Rolling Update (défaut) strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # Max nouveaux pods (+1 = 6 total max) maxUnavailable: 1 # Max pods indisponibles (min 4 running) selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: app image: myapp:2.0 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 # Historique des révisions revisionHistoryLimit: 10 # Délai avant considéré comme failed progressDeadlineSeconds: 600 # Délai avant suppression pods terminés minReadySeconds: 10 ---

Recreate Strategy - Tout supprimer puis recréer

apiVersion: apps/v1 kind: Deployment metadata: name: app-recreate spec: replicas: 3 strategy: type: Recreate selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: app image: myapp:2.0

Deployment avancé

deployment-advanced.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: web-app labels: app: web tier: frontend spec: replicas: 4 selector: matchLabels: app: web template: metadata: labels: app: web version: v2.1 annotations: prometheus.io/scrape: "true" prometheus.io/port: "9090" spec: # Service Account serviceAccountName: web-sa # Image Pull Secret imagePullSecrets: - name: registry-credentials # Init Container initContainers: - name: migration image: myapp:2.1 command: - /bin/sh - -c - | echo "Running migrations..." /app/migrate.sh env: - name: DBHOST value: "mysql-service" # Containers containers: - name: web image: myapp:2.1 imagePullPolicy: Always ports: - name: http containerPort: 8080 protocol: TCP - name: metrics containerPort: 9090 env: - name: PORT value: "8080" - name: DBPASSWORD valueFrom: secretKeyRef: name: db-secret key: password - name: CONFIGFILE valueFrom: configMapKeyRef: name: app-config key: config.json - name: PODNAME valueFrom: fieldRef: fieldPath: metadata.name - name: PODIP valueFrom: fieldRef: fieldPath: status.podIP resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 volumeMounts: - name: config mountPath: /etc/config readOnly: true - name: data mountPath: /var/data - name: cache mountPath: /tmp/cache # Volumes volumes: - name: config configMap: name: app-config - name: data persistentVolumeClaim: claimName: data-pvc - name: cache emptyDir: sizeLimit: 1Gi # Affinity affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: web topologyKey: kubernetes.io/hostname # Topology Spread topologySpreadConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: web

Services

Service ClusterIP

service-clusterip.yaml

apiVersion: v1 kind: Service metadata: name: backend-service labels: app: backend spec: # Type par défaut - IP interne cluster uniquement type: ClusterIP # Sélecteur pods selector: app: backend # Ports ports: - name: http port: 80 # Port du service targetPort: 8080 # Port du container protocol: TCP - name: metrics port: 9090 targetPort: 9090 # IP fixe (optionnel) clusterIP: 10.0.0.10 # Session affinity sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800

Service NodePort

service-nodeport.yaml

apiVersion: v1 kind: Service metadata: name: web-nodeport spec: # Accessible depuis l'extérieur via : type: NodePort selector: app: web ports: - name: http port: 80 targetPort: 8080 nodePort: 30080 # Port sur chaque node (30000-32767) protocol: TCP # Restreindre aux nodes spécifiques externalTrafficPolicy: Local # Préserve source IP

Service LoadBalancer

service-loadbalancer.yaml

apiVersion: v1 kind: Service metadata: name: web-lb annotations: # Annotations cloud provider (exemple AWS) service.beta.kubernetes.io/aws-load-balancer-type: "nlb" service.beta.kubernetes.io/aws-load-balancer-internal: "false" spec: # Crée un load balancer externe (cloud provider) type: LoadBalancer selector: app: web ports: - name: http port: 80 targetPort: 8080 - name: https port: 443 targetPort: 8443 # IP publique fixe (si supporté) loadBalancerIP: 203.0.113.10 # Restreindre IPs sources loadBalancerSourceRanges: - 192.168.1.0/24 - 10.0.0.0/8 externalTrafficPolicy: Local

Service ExternalName

service-externalname.yaml

apiVersion: v1 kind: Service metadata: name: external-db spec: # Alias DNS vers service externe type: ExternalName externalName: database.example.com # Pas de selector ni de ports

Service Headless

service-headless.yaml

apiVersion: v1 kind: Service metadata: name: mysql-headless spec: # Pas de ClusterIP - retourne IPs pods directement clusterIP: None selector: app: mysql ports: - name: mysql port: 3306 targetPort: 3306 # Publier pods non-ready publishNotReadyAddresses: true ---

Utilisé avec StatefulSet pour DNS stable

mysql-0.mysql-headless.default.svc.cluster.local

mysql-1.mysql-headless.default.svc.cluster.local

Endpoints manuel

Service sans selector

apiVersion: v1 kind: Service metadata: name: external-service spec: ports: - port: 80 targetPort: 80 ---

Endpoints manuel

apiVersion: v1 kind: Endpoints metadata: name: external-service subsets:
  • addresses:
  • - ip: 192.168.1.100 - ip: 192.168.1.101 ports: - port: 80

ConfigMaps et Secrets

ConfigMap

configmap-literal.yaml

apiVersion: v1 kind: ConfigMap metadata: name: app-config data: # Paires clé-valeur simples databaseurl: "mysql://db.example.com:3306" maxconnections: "100" loglevel: "info" # Fichiers de configuration nginx.conf: | server { listen 80; servername example.com; location / { proxypass http://backend:8080; } } app.json: | { "api": { "version": "v2", "timeout": 30 }, "features": { "analytics": true, "cache": true } } ---

Utilisation dans Pod

apiVersion: v1 kind: Pod metadata: name: app-with-config spec: containers: - name: app image: myapp:1.0 # Variable d'environnement depuis ConfigMap env: - name: DATABASEURL valueFrom: configMapKeyRef: name: app-config key: databaseurl - name: LOGLEVEL valueFrom: configMapKeyRef: name: app-config key: loglevel # Toutes les clés comme env vars envFrom: - configMapRef: name: app-config prefix: CONFIG # Volume depuis ConfigMap volumeMounts: - name: config mountPath: /etc/nginx/nginx.conf subPath: nginx.conf - name: app-config mountPath: /etc/app volumes: - name: config configMap: name: app-config items: - key: nginx.conf path: nginx.conf - name: app-config configMap: name: app-config defaultMode: 0644

Créer ConfigMap

Depuis littéraux

kubectl create configmap app-config --from-literal=key1=value1 --from-literal=key2=value2

Depuis fichier

kubectl create configmap nginx-config --from-file=nginx.conf

Depuis dossier

kubectl create configmap configs --from-file=./config-dir/

Depuis env file

kubectl create configmap env-config --from-env-file=.env

Voir

kubectl get configmap kubectl describe configmap app-config kubectl get configmap app-config -o yaml

Secrets

secret-generic.yaml

apiVersion: v1 kind: Secret metadata: name: db-credentials type: Opaque data: # Valeurs encodées en base64 username: YWRtaW4= # admin password: cGFzc3dvcmQxMjM= # password123 stringData: # Valeurs en clair (encodées automatiquement) host: "mysql.example.com" port: "3306" ---

Secret TLS

apiVersion: v1 kind: Secret metadata: name: tls-cert type: kubernetes.io/tls data: tls.crt: LS0tLS1CRUdJTi... # Base64 encoded tls.key: LS0tLS1CRUdJTi... ---

Secret Docker Registry

apiVersion: v1 kind: Secret metadata: name: registry-credentials type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: eyJhdXRocyI6eyJodH... ---

Secret SSH Auth

apiVersion: v1 kind: Secret metadata: name: ssh-key type: kubernetes.io/ssh-auth data: ssh-privatekey: LS0tLS1CRUdJTi... ---

Secret Basic Auth

apiVersion: v1 kind: Secret metadata: name: basic-auth type: kubernetes.io/basic-auth stringData: username: admin password: secretpass ---

Utilisation dans Pod

apiVersion: v1 kind: Pod metadata: name: app-with-secrets spec: containers: - name: app image: myapp:1.0 # Variable d'environnement depuis Secret env: - name: DBUSERNAME valueFrom: secretKeyRef: name: db-credentials key: username - name: DBPASSWORD valueFrom: secretKeyRef: name: db-credentials key: password # Toutes les clés comme env vars envFrom: - secretRef: name: db-credentials # Volume depuis Secret volumeMounts: - name: tls mountPath: /etc/tls readOnly: true - name: ssh mountPath: /root/.ssh defaultMode: 0400 volumes: - name: tls secret: secretName: tls-cert - name: ssh secret: secretName: ssh-key items: - key: ssh-privatekey path: idrsa # Pull secret imagePullSecrets: - name: registry-credentials

Créer Secrets

Secret générique depuis littéraux

kubectl create secret generic db-secret --from-literal=username=admin --from-literal=password=secret123

Depuis fichiers

kubectl create secret generic ssh-key --from-file=ssh-privatekey=~/.ssh/idrsa

Secret TLS

kubectl create secret tls tls-cert --cert=path/to/tls.crt --key=path/to/tls.key

Docker registry

kubectl create secret docker-registry registry-cred --docker-server=registry.example.com --docker-username=user --docker-password=pass --docker-email=user@example.com

Encoder/décoder base64

echo -n 'admin' | base64 # Encoder echo 'YWRtaW4=' | base64 -d # Décoder

Voir secrets

kubectl get secrets kubectl describe secret db-secret kubectl get secret db-secret -o yaml kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d

Volumes

Volume Types

pod-volumes.yaml

apiVersion: v1 kind: Pod metadata: name: volume-examples spec: containers: - name: app image: nginx:1.24 volumeMounts: - name: empty-dir mountPath: /cache - name: host-path mountPath: /host-data - name: config mountPath: /etc/config - name: secret mountPath: /etc/secrets readOnly: true - name: pvc mountPath: /data - name: nfs mountPath: /shared volumes: # emptyDir - Temporaire, partagé entre containers - name: empty-dir emptyDir: sizeLimit: 1Gi medium: Memory # ou "" pour disque # hostPath - Montage depuis node (à éviter en prod) - name: host-path hostPath: path: /data type: DirectoryOrCreate # Types: Directory, File, Socket, etc. # configMap - name: config configMap: name: app-config defaultMode: 0644 items: - key: config.json path: app.json # secret - name: secret secret: secretName: db-credentials defaultMode: 0400 # persistentVolumeClaim - name: pvc persistentVolumeClaim: claimName: my-pvc # nfs - name: nfs nfs: server: nfs-server.example.com path: /exports/data readOnly: false

PersistentVolume et PersistentVolumeClaim

pv-local.yaml

apiVersion: v1 kind: PersistentVolume metadata: name: local-pv spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce # RWO - Un seul node en lecture/écriture # - ReadOnlyMany # ROX - Plusieurs nodes en lecture # - ReadWriteMany # RWX - Plusieurs nodes en lecture/écriture # - ReadWriteOncePod # RWOP - Un seul pod (K8s 1.22+) persistentVolumeReclaimPolicy: Retain # Retain - Manuel (données conservées) # Delete - Supprime automatiquement # Recycle - Nettoyage basique (déprécié) storageClassName: local-storage local: path: /mnt/data nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - node-1 ---

pv-nfs.yaml

apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 50Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs mountOptions: - hard - nfsvers=4.1 nfs: server: nfs-server.example.com path: /exports/data ---

pvc.yaml

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: data-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi storageClassName: local-storage # Sélecteur PV spécifique (optionnel) selector: matchLabels: type: fast matchExpressions: - key: environment operator: In values: - prod ---

Pod utilisant PVC

apiVersion: v1 kind: Pod metadata: name: app-with-pvc spec: containers: - name: app image: nginx:1.24 volumeMounts: - name: data mountPath: /usr/share/nginx/html volumes: - name: data persistentVolumeClaim: claimName: data-pvc

StorageClass

storageclass-local.yaml

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-local provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer reclaimPolicy: Delete ---

storageclass-aws-ebs.yaml

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: aws-ebs-gp3 annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: ebs.csi.aws.com parameters: type: gp3 iops: "3000" throughput: "125" encrypted: "true" kmsKeyId: arn:aws:kms:us-east-1:123456789012:key/... volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true reclaimPolicy: Delete ---

storageclass-nfs.yaml

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-client provisioner: nfs-subdir-external-provisioner parameters: archiveOnDelete: "true" pathPattern: "${.PVC.namespace}/${.PVC.name}" reclaimPolicy: Delete allowVolumeExpansion: true ---

PVC avec StorageClass

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: dynamic-pvc spec: accessModes: - ReadWriteOnce storageClassName: aws-ebs-gp3 resources: requests: storage: 20Gi

Commandes volumes

PersistentVolumes

kubectl get pv kubectl describe pv kubectl delete pv

PersistentVolumeClaims

kubectl get pvc kubectl describe pvc kubectl delete pvc

StorageClasses

kubectl get storageclass kubectl describe storageclass kubectl get sc -o yaml

Expansion volume (si allowVolumeExpansion: true)

kubectl edit pvc

Modifier spec.resources.requests.storage

Debug

kubectl get events --sort-by='.lastTimestamp' kubectl describe pvc | grep -A 5 Events

StatefulSets

StatefulSet basique

statefulset-basic.yaml

apiVersion: v1 kind: Service metadata: name: mysql-headless spec: clusterIP: None selector: app: mysql ports: - port: 3306 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql-headless replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 ports: - containerPort: 3306 name: mysql env: - name: MYSQLROOTPASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password volumeMounts: - name: data mountPath: /var/lib/mysql # VolumeClaimTemplates - PVC par pod volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: fast-ssd resources: requests: storage: 10Gi

Pods créés avec noms stables:

mysql-0, mysql-1, mysql-2

DNS: mysql-0.mysql-headless.default.svc.cluster.local

StatefulSet avancé

statefulset-advanced.yaml

apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: web-headless replicas: 5 # Ordre de déploiement podManagementPolicy: OrderedReady # OrderedReady - Un par un dans l'ordre # Parallel - Tous en parallèle # Stratégie de mise à jour updateStrategy: type: RollingUpdate rollingUpdate: partition: 2 # Met à jour uniquement pods >= partition selector: matchLabels: app: web template: metadata: labels: app: web spec: terminationGracePeriodSeconds: 30 containers: - name: nginx image: nginx:1.24 ports: - containerPort: 80 name: http volumeMounts: - name: www mountPath: /usr/share/nginx/html livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 5 volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteOnce storageClassName: ssd resources: requests: storage: 1Gi # Historique révisions revisionHistoryLimit: 10 # Temps min avant pod considéré ready minReadySeconds: 10

Commandes StatefulSet

Lister

kubectl get statefulset kubectl get sts # Alias

Détails

kubectl describe sts mysql

Scale

kubectl scale sts mysql --replicas=5

Update

kubectl apply -f statefulset.yaml

Stratégie partition

kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'

Rollout

kubectl rollout status sts web kubectl rollout history sts web kubectl rollout undo sts web

Supprimer

kubectl delete sts mysql kubectl delete sts mysql --cascade=orphan # Garde les pods

Pods

kubectl get pods -l app=mysql kubectl delete pod mysql-0 # Recréé automatiquement

PVCs

kubectl get pvc -l app=mysql kubectl delete pvc data-mysql-0

DaemonSets

DaemonSet basique

daemonset-basic.yaml

apiVersion: apps/v1 kind: DaemonSet metadata: name: node-exporter labels: app: node-exporter spec: selector: matchLabels: app: node-exporter template: metadata: labels: app: node-exporter spec: # Tolérer taints master tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule # Host network pour accéder métriques node hostNetwork: true hostPID: true containers: - name: node-exporter image: prom/node-exporter:v1.6.1 args: - --path.sysfs=/host/sys - --path.rootfs=/host/root - --path.procfs=/host/proc ports: - containerPort: 9100 hostPort: 9100 name: metrics volumeMounts: - name: sys mountPath: /host/sys readOnly: true - name: root mountPath: /host/root mountPropagation: HostToContainer readOnly: true - name: proc mountPath: /host/proc readOnly: true resources: requests: memory: 30Mi cpu: 100m limits: memory: 50Mi cpu: 200m volumes: - name: sys hostPath: path: /sys - name: root hostPath: path: / - name: proc hostPath: path: /proc

DaemonSet avec sélection nodes

daemonset-selective.yaml

apiVersion: apps/v1 kind: DaemonSet metadata: name: ssd-monitor spec: selector: matchLabels: app: ssd-monitor template: metadata: labels: app: ssd-monitor spec: # Node selector - Seulement nodes avec label nodeSelector: disktype: ssd environment: production # Ou Node Affinity affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd - nvme containers: - name: monitor image: ssd-monitor:1.0 securityContext: privileged: true

Stratégie de mise à jour DaemonSet

daemonset-update.yaml

apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd spec: updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 # ou pourcentage: 25% selector: matchLabels: app: fluentd template: metadata: labels: app: fluentd spec: containers: - name: fluentd image: fluent/fluentd:v1.16

Jobs et CronJobs

Job simple

job-simple.yaml

apiVersion: batch/v1 kind: Job metadata: name: pi-calculation spec: # Nombre de complétions réussies requises completions: 1 # Nombre de pods parallèles parallelism: 1 # Nombre de tentatives en cas d'échec backoffLimit: 4 # Délai avant suppression automatique ttlSecondsAfterFinished: 100 # Timeout activeDeadlineSeconds: 600 template: spec: restartPolicy: Never # Ou OnFailure containers: - name: pi image: perl:5.34 command: - perl - -Mbignum=bpi - -wle - print bpi(2000)

Job parallèle

job-parallel.yaml

apiVersion: batch/v1 kind: Job metadata: name: parallel-job spec: completions: 10 # 10 complétions totales parallelism: 3 # 3 pods à la fois backoffLimit: 5 template: metadata: labels: app: worker spec: restartPolicy: OnFailure containers: - name: worker image: busybox:1.36 command: - /bin/sh - -c - | echo "Processing job $HOSTNAME" sleep 30 echo "Job $HOSTNAME completed"

Job avec index

job-indexed.yaml

apiVersion: batch/v1 kind: Job metadata: name: indexed-job spec: completions: 5 parallelism: 3 completionMode: Indexed # Chaque pod a un index 0-4 template: spec: restartPolicy: OnFailure containers: - name: worker image: busybox:1.36 command: - /bin/sh - -c - | echo "Processing index $JOBCOMPLETIONINDEX" # Traitement basé sur index sleep 10

CronJob

cronjob-basic.yaml

apiVersion: batch/v1 kind: CronJob metadata: name: backup-job spec: # Schedule (cron format) schedule: "0 2 " # Tous les jours à 2h du matin # ┌───────────── minute (0 - 59) # │ ┌───────────── heure (0 - 23) # │ │ ┌───────────── jour du mois (1 - 31) # │ │ │ ┌───────────── mois (1 - 12) # │ │ │ │ ┌───────────── jour de la semaine (0 - 6, 0 = dimanche) # │ │ │ │ │ # # Timezone (K8s 1.25+) timeZone: "Europe/Paris" # Politique concurrence concurrencyPolicy: Forbid # Allow - Permet jobs concurrents # Forbid - Interdit (skip si précédent running) # Replace - Remplace job en cours # Délai de démarrage autorisé startingDeadlineSeconds: 300 # Historique successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 # Suspendre suspend: false jobTemplate: spec: backoffLimit: 3 ttlSecondsAfterFinished: 86400 # 24h template: spec: restartPolicy: OnFailure containers: - name: backup image: backup-tool:1.0 command: - /bin/sh - -c - | echo "Starting backup at $(date)" /usr/local/bin/backup.sh echo "Backup completed at $(date)" env: - name: BACKUPDIR value: /backups volumeMounts: - name: backup mountPath: /backups volumes: - name: backup persistentVolumeClaim: claimName: backup-pvc ---

Exemples de schedules

"/5 " - Toutes les 5 minutes

"0 " - Toutes les heures

"0 0 " - Tous les jours à minuit

"0 0 0" - Tous les dimanches à minuit

"0 0 1 " - Premier jour du mois

"0 0 1 1 " - 1er janvier

"30 2 1-5" - 2h30 du lundi au vendredi

"0 /6 " - Toutes les 6 heures

"0 9-17 1-5" - 9h à 17h, lundi à vendredi

Commandes Jobs et CronJobs

Jobs

kubectl get jobs kubectl describe job pi-calculation kubectl logs job/pi-calculation kubectl delete job pi-calculation

Créer job depuis CronJob

kubectl create job backup-manual --from=cronjob/backup-job

CronJobs

kubectl get cronjobs kubectl get cj # Alias kubectl describe cronjob backup-job

Suspendre/reprendre

kubectl patch cronjob backup-job -p '{"spec":{"suspend":true}}' kubectl patch cronjob backup-job -p '{"spec":{"suspend":false}}'

Logs dernière exécution

kubectl logs -l job-name=backup-job-28239200

Nettoyer jobs terminés

kubectl delete jobs --field-selector status.successful=1

Ingress

Ingress basique

ingress-basic.yaml

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80

Ingress avec TLS

ingress-tls.yaml

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: secure-ingress annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: ingressClassName: nginx tls: - hosts: - example.com - www.example.com secretName: example-tls rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80

Ingress multi-services

ingress-multi.yaml

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: multi-service-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx rules: - host: api.example.com http: paths: # Path types: # Prefix - Match préfixe (/api, /api/users) # Exact - Match exact uniquement # ImplementationSpecific - Dépend de l'ingress controller - path: /v1(/|$)(.) pathType: ImplementationSpecific backend: service: name: api-v1 port: number: 8080 - path: /v2(/|$)(.) pathType: ImplementationSpecific backend: service: name: api-v2 port: number: 8080 - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: frontend port: number: 80 - path: /api pathType: Prefix backend: service: name: backend port: number: 3000

Annotations Ingress courantes

ingress-annotations.yaml

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: advanced-ingress annotations: # Redirection nginx.ingress.kubernetes.io/rewrite-target: /$2 nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # CORS nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS" nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com" nginx.ingress.kubernetes.io/cors-allow-credentials: "true" # Rate limiting nginx.ingress.kubernetes.io/limit-rps: "10" nginx.ingress.kubernetes.io/limit-connections: "5" # Timeouts nginx.ingress.kubernetes.io/proxy-connect-timeout: "30" nginx.ingress.kubernetes.io/proxy-send-timeout: "30" nginx.ingress.kubernetes.io/proxy-read-timeout: "30" # Body size nginx.ingress.kubernetes.io/proxy-body-size: "10m" # IP Whitelist nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.1.0/24" # Auth nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" # Custom headers nginx.ingress.kubernetes.io/configuration-snippet: | moresetheaders "X-Custom-Header: Value"; moresetheaders "X-Frame-Options: DENY"; # Backend protocol nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # Session affinity nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route" nginx.ingress.kubernetes.io/session-cookie-max-age: "86400" # Canary deployments nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "20" spec: ingressClassName: nginx rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80

NetworkPolicies

NetworkPolicy par défaut

network-policy-deny-all.yaml

Deny all ingress

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress namespace: production spec: podSelector: {} policyTypes: - Ingress ---

Deny all egress

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-egress namespace: production spec: podSelector: {} policyTypes: - Egress ---

Allow all ingress

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all-ingress spec: podSelector: {} ingress: - {} policyTypes: - Ingress

NetworkPolicy ingress

network-policy-ingress.yaml

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-policy namespace: production spec: # S'applique aux pods podSelector: matchLabels: app: backend tier: api policyTypes: - Ingress ingress: # Règle 1: Depuis frontend sur port 8080 - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080 # Règle 2: Depuis namespace monitoring - from: - namespaceSelector: matchLabels: name: monitoring ports: - protocol: TCP port: 9090 # Règle 3: Depuis IPs spécifiques - from: - ipBlock: cidr: 192.168.1.0/24 except: - 192.168.1.5/32 ports: - protocol: TCP port: 8080

NetworkPolicy egress

network-policy-egress.yaml

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: app-egress spec: podSelector: matchLabels: app: webapp policyTypes: - Egress egress: # Accès à la base de données - to: - podSelector: matchLabels: app: database ports: - protocol: TCP port: 5432 # Accès à l'API externe - to: - ipBlock: cidr: 203.0.113.0/24 ports: - protocol: TCP port: 443 # DNS (kube-dns/CoreDNS) - to: - namespaceSelector: matchLabels: name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53

NetworkPolicy complexe

network-policy-complex.yaml

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: complex-policy namespace: production spec: podSelector: matchLabels: role: api policyTypes: - Ingress - Egress ingress: # Frontend dans même namespace OU monitoring namespace - from: - podSelector: matchLabels: role: frontend - namespaceSelector: matchLabels: name: monitoring ports: - protocol: TCP port: 8080 - protocol: TCP port: 9090 egress: # Base de données - to: - podSelector: matchLabels: role: database ports: - protocol: TCP port: 5432 # Services externes - to: - ipBlock: cidr: 0.0.0.0/0 except: - 169.254.169.254/32 # Metadata service ports: - protocol: TCP port: 443 - protocol: TCP port: 80 # DNS - to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - protocol: TCP port: 53

RBAC (Role-Based Access Control)

Role et RoleBinding

role-developer.yaml

apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: developer namespace: development rules:

Pods

  • apiGroups: [""]
  • resources: ["pods", "pods/log"] verbs: ["get", "list", "watch", "create", "delete"]

    Deployments

  • apiGroups: ["apps"]
  • resources: ["deployments", "replicasets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

    Services

  • apiGroups: [""]
  • resources: ["services"] verbs: ["get", "list", "watch", "create", "delete"]

    ConfigMaps et Secrets (lecture seule)

  • apiGroups: [""]
  • resources: ["configmaps", "secrets"] verbs: ["get", "list"] ---

    rolebinding-developer.yaml

    apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: developer-binding namespace: development subjects:

    User

  • kind: User
  • name: john@example.com apiGroup: rbac.authorization.k8s.io

    Group

  • kind: Group
  • name: developers apiGroup: rbac.authorization.k8s.io

    ServiceAccount

  • kind: ServiceAccount
  • name: dev-sa namespace: development roleRef: kind: Role name: developer apiGroup: rbac.authorization.k8s.io

    ClusterRole et ClusterRoleBinding

    clusterrole-viewer.yaml

    apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cluster-viewer rules:

    Lecture tous les pods

  • apiGroups: [""]
  • resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"]

    Lecture deployments, daemonsets, statefulsets

  • apiGroups: ["apps"]
  • resources: ["deployments", "daemonsets", "statefulsets", "replicasets"] verbs: ["get", "list", "watch"]

    Lecture services et ingress

  • apiGroups: [""]
  • resources: ["services", "endpoints"] verbs: ["get", "list", "watch"]
  • apiGroups: ["networking.k8s.io"]
  • resources: ["ingresses"] verbs: ["get", "list", "watch"]

    Lecture nodes

  • apiGroups: [""]
  • resources: ["nodes"] verbs: ["get", "list"] ---

    clusterrolebinding-viewer.yaml

    apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: viewer-binding subjects:
  • kind: Group
  • name: viewers apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: cluster-viewer apiGroup: rbac.authorization.k8s.io

    ServiceAccount

    serviceaccount.yaml

    apiVersion: v1 kind: ServiceAccount metadata: name: app-sa namespace: production automountServiceAccountToken: true imagePullSecrets:
  • name: registry-credentials
  • ---

    Role pour ServiceAccount

    apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-role namespace: production rules:
  • apiGroups: [""]
  • resources: ["configmaps"] verbs: ["get", "list"]
  • apiGroups: [""]
  • resources: ["secrets"] resourceNames: ["app-secret"] # Secret spécifique uniquement verbs: ["get"] ---

    RoleBinding

    apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-rolebinding namespace: production subjects:
  • kind: ServiceAccount
  • name: app-sa namespace: production roleRef: kind: Role name: app-role apiGroup: rbac.authorization.k8s.io ---

    Utilisation dans Pod

    apiVersion: v1 kind: Pod metadata: name: app-with-sa namespace: production spec: serviceAccountName: app-sa containers: - name: app image: myapp:1.0

    Commandes RBAC

    Roles

    kubectl get roles -n development kubectl describe role developer -n development kubectl create role developer --verb=get,list --resource=pods -n development

    RoleBindings

    kubectl get rolebindings -n development kubectl describe rolebinding developer-binding -n development kubectl create rolebinding dev-binding --role=developer --user=john@example.com -n development

    ClusterRoles

    kubectl get clusterroles kubectl describe clusterrole cluster-viewer kubectl create clusterrole viewer --verb=get,list --resource=pods

    ClusterRoleBindings

    kubectl get clusterrolebindings kubectl describe clusterrolebinding viewer-binding

    ServiceAccounts

    kubectl get serviceaccounts kubectl get sa # Alias kubectl create serviceaccount app-sa -n production

    Vérifier permissions

    kubectl auth can-i get pods --as=john@example.com kubectl auth can-i delete deployments --as=system:serviceaccount:prod:app-sa -n prod kubectl auth can-i --list --as=john@example.com

    Qui peut faire quoi

    kubectl auth reconcile -f rbac.yaml

    ResourceQuotas et LimitRanges

    ResourceQuota

    resourcequota.yaml

    apiVersion: v1 kind: ResourceQuota metadata: name: compute-quota namespace: development spec: hard: # Compute resources requests.cpu: "10" requests.memory: 20Gi limits.cpu: "20" limits.memory: 40Gi # Storage requests.storage: 100Gi persistentvolumeclaims: "10" # Objects count pods: "50" services: "20" services.loadbalancers: "2" services.nodeports: "5" replicationcontrollers: "20" secrets: "50" configmaps: "50" ---

    Quota par priorité

    apiVersion: v1 kind: ResourceQuota metadata: name: high-priority-quota namespace: production spec: hard: pods: "10" requests.cpu: "5" requests.memory: 10Gi scopeSelector: matchExpressions: - operator: In scopeName: PriorityClass values: ["high"] ---

    Quota par QoS

    apiVersion: v1 kind: ResourceQuota metadata: name: besteffort-quota namespace: development spec: hard: pods: "5" scopes: - BestEffort

    LimitRange

    limitrange.yaml

    apiVersion: v1 kind: LimitRange metadata: name: resource-limits namespace: development spec: limits: # Contraintes Containers - type: Container max: cpu: "2" memory: 2Gi min: cpu: 100m memory: 64Mi default: cpu: 500m memory: 512Mi defaultRequest: cpu: 250m memory: 256Mi maxLimitRequestRatio: cpu: 2 memory: 2 # Contraintes Pods - type: Pod max: cpu: "4" memory: 4Gi min: cpu: 200m memory: 128Mi # Contraintes PVC - type: PersistentVolumeClaim max: storage: 10Gi min: storage: 1Gi

    HorizontalPodAutoscaler (HPA)

    HPA basique

    hpa-basic.yaml

    apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: web-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web-app minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 - type: Pods value: 2 periodSeconds: 60 selectPolicy: Min scaleUp: stabilizationWindowSeconds: 0 policies: - type: Percent value: 100 periodSeconds: 30 - type: Pods value: 4 periodSeconds: 30 selectPolicy: Max

    HPA avec métriques custom

    hpa-custom.yaml

    apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: custom-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: api-server minReplicas: 3 maxReplicas: 20 metrics: # Resource metrics - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 # Pods metrics (depuis annotations Prometheus) - type: Pods pods: metric: name: httprequestspersecond target: type: AverageValue averageValue: "1000" # Object metrics - type: Object object: metric: name: requests-per-second describedObject: apiVersion: networking.k8s.io/v1 kind: Ingress name: main-route target: type: Value value: "10k" # External metrics - type: External external: metric: name: queuemessagesready selector: matchLabels: queue: worker-tasks target: type: AverageValue averageValue: "30"

    Commandes HPA

    Créer HPA

    kubectl autoscale deployment web --cpu-percent=70 --min=2 --max=10

    Lister

    kubectl get hpa kubectl describe hpa web-hpa

    Éditer

    kubectl edit hpa web-hpa

    Supprimer

    kubectl delete hpa web-hpa

    Voir métriques (nécessite metrics-server)

    kubectl top nodes kubectl top pods

    Watch HPA

    kubectl get hpa -w

    Kustomize

    Structure de base

    Structure projet Kustomize

    base/ ├── kustomization.yaml ├── deployment.yaml ├── service.yaml └── configmap.yaml overlays/ ├── dev/ │ ├── kustomization.yaml │ └── patch-replicas.yaml ├── staging/ │ ├── kustomization.yaml │ └── patch-replicas.yaml └── production/ ├── kustomization.yaml ├── patch-replicas.yaml └── patch-resources.yaml

    Base Kustomization

    base/kustomization.yaml

    apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization

    Common labels

    commonLabels: app: myapp managed-by: kustomize

    Common annotations

    commonAnnotations: version: "1.0.0"

    Name prefix/suffix

    namePrefix: app- nameSuffix: -v1

    Namespace

    namespace: default

    Resources

    resources:
  • deployment.yaml
  • service.yaml
  • configmap.yaml
  • ConfigMap generator

    configMapGenerator:
  • name: app-config
  • literals: - LOGLEVEL=info - MAXCONNECTIONS=100 files: - config.properties

    Secret generator

    secretGenerator:
  • name: db-credentials
  • literals: - username=admin - password=secret123 type: Opaque

    Images

    images:
  • name: myapp
  • newName: registry.example.com/myapp newTag: 1.2.3

    Overlay Development

    overlays/dev/kustomization.yaml

    apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization

    Base

    bases:
  • ../../base
  • Namespace override

    namespace: development

    Replicas patch

    patchesStrategicMerge:
  • patch-replicas.yaml
  • ConfigMap overlay

    configMapGenerator:
  • name: app-config
  • behavior: merge literals: - LOGLEVEL=debug - ENVIRONMENT=development

    Labels

    commonLabels: environment: dev ---

    overlays/dev/patch-replicas.yaml

    apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 1

    Overlay Production

    overlays/production/kustomization.yaml

    apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization bases:
  • ../../base
  • namespace: production patchesStrategicMerge:
  • patch-replicas.yaml
  • patch-resources.yaml
  • Patches JSON

    patchesJson6902:
  • target:
  • group: apps version: v1 kind: Deployment name: myapp patch: |- - op: add path: /spec/template/spec/containers/0/env/- value: name: CACHEENABLED value: "true" configMapGenerator:
  • name: app-config
  • behavior: merge literals: - LOG
    LEVEL=warn - ENVIRONMENT=production - CACHEENABLED=true commonLabels: environment: prod images:
  • name: myapp
  • newTag: 1.2.3-stable ---

    overlays/production/patch-resources.yaml

    apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: template: spec: containers: - name: myapp resources: requests: cpu: 500m memory: 512Mi limits: cpu: 1000m memory: 1Gi

    Commandes Kustomize

    Build (voir YAML généré)

    kubectl kustomize ./base kubectl kustomize ./overlays/dev kubectl kustomize ./overlays/production

    Apply directement

    kubectl apply -k ./overlays/dev kubectl apply -k ./overlays/production

    Delete

    kubectl delete -k ./overlays/dev

    Diff

    kubectl diff -k ./overlays/production

    Helm

    Commandes Helm essentielles

    Installation Helm 3

    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

    Ajouter repository

    helm repo add stable https://charts.helm.sh/stable helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

    Mettre à jour repos

    helm repo update

    Chercher charts

    helm search repo nginx helm search hub wordpress

    Installer chart

    helm install my-release bitnami/nginx helm install my-nginx bitnami/nginx --version 13.2.0 helm install my-app ./my-chart helm install my-app ./my-chart --namespace production --create-namespace helm install my-app ./my-chart -f values-prod.yaml helm install my-app ./my-chart --set replicaCount=3 --set image.tag=1.2.3

    Dry-run (voir ce qui serait créé)

    helm install my-app ./my-chart --dry-run --debug

    Lister releases

    helm list helm list --all-namespaces helm list -n production

    Status

    helm status my-release helm status my-release -n production

    Upgrade

    helm upgrade my-release bitnami/nginx helm upgrade my-release ./my-chart -f values.yaml helm upgrade --install my-release ./my-chart # Install si n'existe pas

    Rollback

    helm rollback my-release helm rollback my-release 2 # Revision spécifique helm history my-release

    Uninstall

    helm uninstall my-release helm uninstall my-release --keep-history

    Get values

    helm get values my-release helm get values my-release --all helm get manifest my-release

    Show chart info

    helm show chart bitnami/nginx helm show values bitnami/nginx helm show all bitnami/nginx

    Template (générer YAML)

    helm template my-release ./my-chart helm template my-release ./my-chart -f values-prod.yaml

    Lint (valider chart)

    helm lint ./my-chart

    Package

    helm package ./my-chart helm package ./my-chart --version 1.2.3

    Create chart

    helm create my-app

    Debugging et Troubleshooting

    Commandes de debug

    Logs

    kubectl logs -f kubectl logs --previous kubectl logs -c kubectl logs -l app=nginx --all-containers=true kubectl logs --since=1h kubectl logs --tail=100

    Describe (événements)

    kubectl describe pod kubectl describe node kubectl describe service

    Events

    kubectl get events --sort-by='.lastTimestamp' kubectl get events --field-selector involvedObject.name= kubectl get events -n kube-system

    Exec dans pod

    kubectl exec -it -- /bin/bash kubectl exec -it -c -- sh kubectl exec -- env kubectl exec -- ps aux kubectl exec -- cat /etc/resolv.conf

    Port forward

    kubectl port-forward pod/ 8080:80 kubectl port-forward service/ 8080:80

    Debug avec container ephemeral (K8s 1.23+)

    kubectl debug -it --image=busybox:1.36 kubectl debug -it --image=nicolaka/netshoot --target=

    Debug node

    kubectl debug node/ -it --image=ubuntu

    Proxy API server

    kubectl proxy --port=8001

    Accès: http://localhost:8001/api/v1/namespaces/default/pods

    Top resources

    kubectl top nodes kubectl top pods --all-namespaces kubectl top pods --containers

    Get raw

    kubectl get pod -o yaml kubectl get pod -o json kubectl get pods -o wide kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,IP:.status.podIP

    Dry run

    kubectl create deployment test --image=nginx --dry-run=client -o yaml kubectl apply -f pod.yaml --dry-run=server

    Diff

    kubectl diff -f deployment.yaml

    Explain

    kubectl explain pod kubectl explain pod.spec.containers kubectl explain pod --recursive

    API resources

    kubectl api-resources kubectl api-resources --namespaced=true kubectl api-resources --api-group=apps

    Problèmes courants

    Pod en CrashLoopBackOff

    kubectl logs --previous kubectl describe pod # Voir events kubectl get pod -o yaml # Vérifier config

    Pod en ImagePullBackOff

    kubectl describe pod # Erreur pull kubectl get pod -o jsonpath='{.spec.containers[*].image}'

    Pod Pending

    kubectl describe pod # Raison scheduling kubectl get events --field-selector involvedObject.name= kubectl describe nodes # Resources disponibles

    Service ne répond pas

    kubectl get endpoints # Vérifier endpoints kubectl get pods -l app=

    Annexes

    Labels et selectors courants

    Labels recommandés

    metadata: labels: app.kubernetes.io/name: myapp app.kubernetes.io/instance: myapp-prod app.kubernetes.io/version: "1.2.3" app.kubernetes.io/component: backend app.kubernetes.io/part-of: ecommerce app.kubernetes.io/managed-by: helm # Custom environment: production tier: backend team: platform

    Selectors

    kubectl get pods -l app=nginx kubectl get pods -l 'environment in (prod,staging)' kubectl get pods -l 'environment!=dev' kubectl get pods -l 'app=nginx,tier=frontend' kubectl get pods -l 'version' # Has label kubectl get pods -l '!version' # Doesn't have label

    Annotations courantes

    metadata:
      annotations:
        # General
        description: "Application web principale"
        owner: "team-platform@example.com"
        documentation: "https://docs.example.com/myapp"
    
        # Kubernetes
        kubernetes.io/change-cause: "Update to v1.2.3"
    
        # Ingress
        nginx.ingress.kubernetes.io/rewrite-target: /
        cert-manager.io/cluster-issuer: letsencrypt-prod
    
        # Prometheus
        prometheus.io/scrape: "true"
        prometheus.io/port: "9090"
        prometheus.io/path: "/metrics"
    
        # Service mesh (Istio)
        sidecar.istio.io/inject: "true"
    

    Variables d’environnement utiles

    env:
    

    Pod metadata

  • name: PODNAME
  • valueFrom: fieldRef: fieldPath: metadata.name
  • name: PODNAMESPACE
  • valueFrom: fieldRef: fieldPath: metadata.namespace
  • name: PODIP
  • valueFrom: fieldRef: fieldPath: status.podIP
  • name: NODENAME
  • valueFrom: fieldRef: fieldPath: spec.nodeName
  • name: SERVICEACCOUNT
  • valueFrom: fieldRef: fieldPath: spec.serviceAccountName

    Resource limits

  • name: CPUREQUEST
  • valueFrom: resourceFieldRef: containerName: app resource: requests.cpu
  • name: MEMORYLIMIT
  • valueFrom: resourceFieldRef: containerName: app resource: limits.memory

    Raccourcis kubectl

    `bash

    Alias

    alias k=’kubectl’
    alias kg=’kubectl get’
    alias kd=’kubectl describe’
    alias kdel=’kubectl delete’
    alias kl=’kubectl logs’
    alias kx=’kubectl exec -it’
    alias kaf=’kubectl apply -f’
    alias kdf=’kubectl delete -f’

    Completion bash

    source <(kubectl completion bash) complete -o default -F _startkubectl k

    Changer namespace rapidement

    alias kns=’kubectl config set-context –current –namespace’
    kns production

    Une remarque, un retour ?

    Cet article est vivant — corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.