Ce document rassemble une série de questions et scénarios types que vous pourriez rencontrer lors de l'examen CKA (Certified Kubernetes Administrator). L'objectif est de vous familiariser avec les tâches courantes et les commandes kubectl essentielles.
Il est fortement recommandé de configurer quelques alias et options dès le début de l'examen pour gagner du temps.
alias k=kubectl # Alias court pour kubectl (généralement pré-configuré)
export do="--dry-run=client -o yaml" # Pour générer rapidement le YAML d'une ressource sans la créer
export now="--force --grace-period=0" # Pour forcer la suppression immédiate d'un Pod (à utiliser avec prudence)
# Optionnel mais utile : définir le namespace par défaut pour un contexte donné
# k config set-context --current --namespace=<nom-namespace>
Pour l'éditeur vim (si vous l'utilisez), ajouter ceci au fichier ~/.vimrc améliore la lisibilité du YAML :
set tabstop=2 # Taille d'une tabulation
set expandtab # Utiliser des espaces au lieu des tabulations
set shiftwidth=2 # Nombre d'espaces pour l'indentation automatique
autocmd FileType yaml setlocal ts=2 sts=2 sw=2 expandtab # Applique spécifiquement pour les fichiers YAML
Dans cette liste de questions, j'ai mis des questions typiques qui m'ont posé problème durant l'examen blanc.
Objectif : Créer un Pod nommé nginx-master utilisant l'image nginx:1.25 (ou une version récente). Ce Pod ne doit pouvoir être schedulé que sur un nœud ayant le rôle control-plane ou master.
Étapes de résolution :
Identifier les Taints et Labels des nœuds master : Les nœuds master ont souvent un taint (ex: node-role.kubernetes.io/control-plane:NoSchedule ou node-role.kubernetes.io/master:NoSchedule) pour empêcher les Pods normaux d'y être schedulés, et un label correspondant (ex: node-role.kubernetes.io/control-plane= ou node-role.kubernetes.io/master=).
# Examiner un nœud master (remplacer master1 par le nom réel)
k describe node master1
# Rechercher spécifiquement les Taints
k describe node master1 | grep Taints
# Exemple de sortie: Taints: node-role.kubernetes.io/control-plane:NoSchedule
# Rechercher spécifiquement les Labels
k describe node master1 | grep -A 5 "Labels:"
# Exemple de sortie pertinente: node-role.kubernetes.io/control-plane=
# node-role.kubernetes.io/master=
Créer le manifeste du Pod : Le Pod aura besoin :
toleration pour le taint NoSchedule trouvé.nodeSelector (ou nodeAffinity) pour cibler le label du nœud master.apiVersion: v1
kind: Pod
metadata:
name: nginx-master
spec:
containers:
- name: nginx-container
image: nginx:1.25 # Utiliser une version récente
tolerations:
# Tolérer le taint appliqué aux nœuds control-plane/master
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
# Alternative si le taint est node-role.kubernetes.io/master
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
nodeSelector:
# Exiger le label présent sur les nœuds control-plane/master
node-role.kubernetes.io/control-plane: ""
# Alternative:
# node-role.kubernetes.io/master: ""
Note : L'opérateur Exists pour la toleration correspond à un taint sans valeur ou avec n'importe quelle valeur. Le nodeSelector avec une valeur vide "" correspond à un label présent sans valeur spécifique assignée (ce qui est courant pour les labels de rôle).
Appliquer le manifeste :
k apply -f pod-master.yaml # En supposant que le YAML est dans ce fichier
Vérifier le placement du Pod :
k get pod nginx-master -o wide
# Vérifier que le Pod est Running et que la colonne NODE correspond à un nœud master.
Afficher l'utilisation des noeuds :
kubectl top node
Afficher l'utilisation des pods ET des containers s'il y en a :
kubectl top pod --containers=true
Objectif : Déterminer comment les composants principaux (kubelet, kube-apiserver, kube-scheduler, kube-controller-manager, etcd) et le service DNS sont installés et exécutés sur un nœud master du cluster.
Méthodologie :
Identifier le mode d'exécution du Kubelet : Le Kubelet est presque toujours exécuté comme un service systemd directement sur le nœud.
# Se connecter au nœud master (ex: ssh cluster1-master1)
systemctl status kubelet
# ou
ps aux | grep kubelet
Résultat probable : process (géré par systemd).
Identifier le mode d'exécution des autres composants du Control Plane : Dans un cluster kubeadm, ces composants (kube-apiserver, etcd, kube-scheduler, kube-controller-manager) sont généralement exécutés comme des Pods Statiques gérés par le Kubelet du nœud master.
/etc/kubernetes/manifests/).ls /etc/kubernetes/manifests/
# Sortie attendue : etcd.yaml, kube-apiserver.yaml, kube-controller-manager.yaml, kube-scheduler.yaml
kube-system. Les Pods Statiques auront le nom du nœud master ajouté comme suffixe.# Depuis n'importe où avec kubectl configuré
k get pods -n kube-system -o wide | grep <nom-du-noeud-master>
# Sortie attendue :
# etcd-<nom-master> 1/1 Running ...
# kube-apiserver-<nom-master> 1/1 Running ...
# kube-controller-manager-<nom-master> 1/1 Running ...
# kube-scheduler-<nom-master> 1/1 Running ...
Résultat probable : static-pod pour ces 4 composants.
Identifier le mode d'exécution du DNS : Le service DNS (généralement CoreDNS) est typiquement exécuté comme un Deployment standard dans le namespace kube-system.
# Lister les Deployments dans kube-system
k get deployment -n kube-system
# Sortie attendue (contient généralement 'coredns') :
# NAME READY UP-TO-DATE AVAILABLE AGE
# coredns 2/2 2 2 155m
# Confirmer avec les Pods
k get pods -n kube-system -l k8s-app=kube-dns # Label standard pour le DNS
# Sortie attendue :
# NAME READY STATUS RESTARTS AGE
# coredns-xxxx-yyyy 1/1 Running 0 155m
# coredns-xxxx-zzzz 1/1 Running 0 155m
Résultat probable : pod (géré par un Deployment), Nom : coredns.
Exemple de fichier réponse (/opt/response/X/master-components.txt) :
kubelet: process
kube-apiserver: static-pod
kube-scheduler: static-pod
kube-controller-manager: static-pod
etcd: static-pod
dns: pod coredns # Ou juste 'pod' si le nom n'est pas demandé
(Note : Si une question mentionne un composant spécifique comme kube-scheduler-special, il faut vérifier son état de la même manière)
Connectez-vous au nœud maître avec ssh cluster2-master1. Arrêtez temporairement le kube-scheduler, de manière à pouvoir le relancer par la suite.
Créez un Pod unique nommé manual-schedule de l'image httpd:2.4-alpine, confirmez sa création mais ne le schedule sur aucun noeud.
Maintenant que vous êtes le scheduler et que vous avez tout son pouvoir, planifiez manuellement ce pod sur le nœud cluster1-master1. Assurez-vous qu'il est en cours d'exécution.
Redémarrez le kube-scheduler et confirmez son fonctionnement correct en créant un second pod nommé manual-schedule2 de l'image httpd:2.4-alpine et vérifiez qu'il fonctionne sur cluster2-worker1.
# On va aller déplacer le manifest du static-pod kube-scheduler :
$ cd /etc/kubernetes/manifests/
$ mv kube-scheduler.yaml ../
# Cela va stopper le static-pod
Si on vérifier :
$ kubectl -n kube-system get pod | grep scheduler-master
Rien ne ressort car le pod s'est stoppé. On va maintenant lancer un pod, mais celui-ci ne sera pas assigné :
$ k run manual-schedule --image=httpd:2.4-alpine
$ k get pod manual-schedule -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
manual-schedule 0/1 Pending 0 17s <none> <none> <none> <none>
On va donc récupérer le yaml de ce pod :
$ k get pod manual-schedule -o yaml > manual-schedule.yaml
En réalité, le scheduler rajoute juste le nom de noeud (nodeName) dans le YAML :
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2022-03-20T15:26:44Z"
labels:
run: manual-schedule
name: manual-schedule
namespace: default
resourceVersion: "30688"
uid: 23f5daf4-7aed-437e-90f5-122a5f173481
spec:
nodeName: cluster1-master1 # ajouter le nom du noeud master
containers:
- image: httpd:2.4-alpine
imagePullPolicy: IfNotPresent
name: manual-schedule
...
On ne peut pas simplement appliquer le fichier :
$ k apply -f manual-schedule.yaml
Warning: resource pods/manual-schedule is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
On va donc forcer la recréation du pod :
$ k -f manual-schedule.yaml replace --force
pod "manual-schedule" deleted
pod/manual-schedule replaced
On va maintenant relancer le kube-scheduler :
$ cd /etc/kubernetes/
$ mv kube-scheduler.yaml manifests/
Créer un nouveau ServiceAccount au nom de processor dans le Namespace project-hamster. Créez un Role et un RoleBinding, tous deux nommés processor également. Ceux-ci devraient permettre au nouveau ServiceAccount de créer uniquement des Secrets et des ConfigMaps dans ce Namespace.
Tips: Plutot que de tout faire en yaml. Faire via CLI :
$ k -n project-hamster create role processor --verb=create --resource=secrets --resource=configmaps
RoleBinding :
$ k -n project-hamster create rolebinding processor --role processor --serviceaccount project-hamster:processor
Pour tester notre configuration RBAC, nous pouvons utiliser kubectl auth can-i :
$ k -n project-hamster auth can-i -h
...
$ k -n project-hamster auth can-i create secret --as system:serviceaccount:project-hamster:processor
yes
$ k -n project-hamster auth can-i get secret --as system:serviceaccount:project-hamster:processor
no
Le but est de lancer un déploiement avec 3 réplicas. 1 pod maximum par noeud ! (l'équivalent d'un daemonset via un deployment) :
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
id: very-important
name: deploy-important
namespace: project-tiger
spec:
replicas: 3
selector:
matchLabels:
id: very-important
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
id: very-important
spec:
containers:
- image: nginx:1.17.6-alpine
name: container1
affinity:
# Ici, si un pod avec l'id "very-important" tourne déjà sur le noeud, on en démarre pas un 2ème
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: id
operator: In
values:
- very-important
topologyKey: kubernetes.io/hostname
Si on regarde le pod qui n'est pas schedule on voit :
Warning FailedScheduling 63s (x3 over 65s) default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match pod affinity/anti-affinity, 2 node(s) didn't satisfy existing pods anti-affinity rules.
Le déploiement peut aussi se faire via topologySpreadConstraints, plus simple à comprendre pour ma part :
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
id: very-important
name: deploy-important
namespace: project-tiger
spec:
replicas: 3
selector:
matchLabels:
id: very-important
template:
metadata:
labels:
id: very-important
spec:
containers:
- image: nginx:1.17.6-alpine
name: container1
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
id: very-important
Si on regarde le pod qui n'est pas schedule on voit :
Warning FailedScheduling 16s default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match pod topology spread constraints.
1/ et 2/ On en voit 1 master et 2 workers
$ k get node
NAME STATUS ROLES AGE VERSION
cluster1-master1 Ready master 27h v1.32.1
cluster1-worker1 Ready <none> 27h v1.32.1
cluster1-worker2 Ready <none> 27h v1.32.1
3/ Pour voir cela, il faut se connecter sur le master et aller dans les fichiers de conf de kube-apiserver. 10.96.0.0/12 est la réponse.
$ cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep range
- --service-cluster-ip-range=10.96.0.0/12
4/ En regardant dans le dossier de conf du cni, on voit que c'est weave qui est utilisé :
$ find /etc/cni/net.d/
/etc/cni/net.d/
/etc/cni/net.d/10-weave.conflist
$ cat /etc/cni/net.d/10-weave.conflist
{
"cniVersion": "0.3.0",
"name": "weave",
...
5/ Le suffixe sera -cluster1-worker1.
Créez un nouveau namespace appelé cka-master.
Écrivez les noms de toutes les ressources Kubernetes qui peuvent contenir des namespaces (comme Pod, Secret, ConfigMap...) dans /opt/course/16/resources.txt.
Trouvez le Namespace du projet-* avec le plus grand nombre de Roles définis et écrivez son nom et le nombre de Roles dans /opt/course/16/crowded-namespace.txt.
$ k create ns cka-master
$ k api-resources --namespaced -o name > /opt/course/16/resources.txt
Ensuite on va lister les roles et connaitre le nombre par namespace :
$ k -n project-c13 get role --no-headers | wc -l
No resources found in project-c13 namespace.
0
$ k -n project-c14 get role --no-headers | wc -l
300
$ k -n project-hamster get role --no-headers | wc -l
No resources found in project-hamster namespace.
0
$ k -n project-snake get role --no-headers | wc -l
No resources found in project-snake namespace.
0
$ k -n project-tiger get role --no-headers | wc -l
No resources found in project-tiger namespace.
0
Etonnemment je ne l'avais jamais vu jusque là :
$ kubeadm token create --print-join-command
kubeadm join 192.168.100.31:6443 --token leqq1l.1hlg4rw8mu7brv73 --discovery-token-ca-cert-hash sha256:2e2c3407a256fc768f0d8e70974a8e24d7b9976149a79bd08858c4d7aa2ff79a
Il peut être demandé d'écrire la date d'expiration dans un fichier txt. Pour ce faire :
$ openssl x509 -noout -text -in /etc/kubernetes/pki/etcd/server.crt | grep Validity -A2
Validity
Not Before: Sep 13 13:01:31 2021 GMT
Not After : Sep 13 13:01:31 2022 GMT
Cette section couvre les nouvelles exigences du curriculum CKA 2025, notamment Helm, Kustomize, Gateway API, CRDs/Operators, et configurations avancées.
Contexte : Vous devez déployer une application nginx sur le cluster en utilisant Helm, puis effectuer une mise à jour et un rollback en cas de problème.
Tâches :
bitnami (https://charts.bitnami.com/bitnami)production avec le nom de release web-appSolution :
# 1. Ajouter le dépôt
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# 2. Créer le namespace
kubectl create namespace production
# 3. Déployer avec personnalisation
helm install web-app bitnami/nginx \
--version 22.2.6 \
--namespace production \
--set replicaCount=3 \
--set service.type=NodePort
# Vérifier le déploiement
helm list -n production
kubectl get pods -n production
# 4. Mettre à jour
helm upgrade web-app bitnami/nginx \
--version 22.3.2 \
--namespace production \
--reuse-values # Conserve les valeurs personnalisées
# Vérifier l'historique
helm history web-app -n production
# 5. Rollback si nécessaire
helm rollback web-app -n production
# Vérifier le rollback
helm history web-app -n production
Vérification :
# État de la release
helm status web-app -n production
# Valeurs utilisées
helm get values web-app -n production
# Supprimer la release
helm uninstall web-app -n production
Contexte : Créer une configuration Kustomize avec une base commune et des overlays pour dev, staging et production.
Structure attendue :
/opt/app/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml
Tâches :
dev, label env: devstaging, label env: stagingprod, label env: prod, resource requests/limitsSolution :
# Créer la structure
mkdir -p /opt/app/{base,overlays/{dev,staging,prod}}
# Base deployment.yaml
cat <<EOF > /opt/app/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29.5
ports:
- containerPort: 80
EOF
# Base service.yaml
cat <<EOF > /opt/app/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
EOF
# Base kustomization.yaml
cat <<EOF > /opt/app/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
EOF
# Overlay dev
cat <<EOF > /opt/app/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: dev
commonLabels:
env: dev
bases:
- ../../base
EOF
# Overlay staging
cat <<EOF > /opt/app/overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: staging
commonLabels:
env: staging
bases:
- ../../base
replicas:
- name: nginx-app
count: 2
EOF
# Overlay prod avec patch pour resources
cat <<EOF > /opt/app/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: prod
commonLabels:
env: prod
bases:
- ../../base
replicas:
- name: nginx-app
count: 3
patches:
- patch: |-
- op: add
path: /spec/template/spec/containers/0/resources
value:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
target:
kind: Deployment
name: nginx-app
EOF
# Créer les namespaces
kubectl create namespace staging
# Appliquer pour staging
kubectl apply -k /opt/app/overlays/staging
# Vérifier
kubectl get all -n staging
kubectl get deployment nginx-app -n staging -o yaml | grep replicas
Contexte : Configurer Gateway API avec Envoy Gateway pour router le trafic vers deux services différents.
Tâches :
main-gateway dans le namespace default écoutant sur le port 80app-route routant :
/api/* vers le service api-service:8080/web/* vers le service web-service:80Solution :
# 1. Installer Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
# Installer Envoy Gateway
kubectl apply --server-side -f https://github.com/envoyproxy/gateway/releases/download/latest/install.yaml
# Vérifier l'installation
kubectl get pods -n envoy-gateway-system
kubectl get gatewayclass
# 2. Créer le Gateway
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: main-gateway
namespace: default
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
EOF
# 3. Créer le HTTPRoute
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: default
spec:
parentRefs:
- name: main-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /web
backendRefs:
- name: web-service
port: 80
EOF
# 4. Vérifier le Gateway
kubectl get gateway main-gateway
kubectl describe gateway main-gateway
# Vérifier le HTTPRoute
kubectl get httproute app-route
kubectl describe httproute app-route
# Obtenir l'IP du Gateway
ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system -o name | grep envoy-default-main-gateway | head -1)
kubectl get ${ENVOY_SERVICE} -n envoy-gateway-system
Contexte : Configurer Pod Security Admission pour appliquer le niveau restricted sur un namespace de production.
Tâches :
secure-prodrestricted en mode enforce, audit et warnrestrictedSolution :
# 1. Créer le namespace avec labels PSS
kubectl create namespace secure-prod
# 2. Appliquer PSS
kubectl label namespace secure-prod \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
# Vérifier
kubectl get namespace secure-prod -o yaml | grep pod-security
# 3. Tenter Pod non-conforme (sera rejeté)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: unsafe-pod
namespace: secure-prod
spec:
containers:
- name: nginx
image: nginx
securityContext:
runAsUser: 0
EOF
# Erreur attendue: violates PodSecurity "restricted"
# 4. Créer Pod conforme
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: safe-pod
namespace: secure-prod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: nginx
image: nginx
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
volumes:
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
EOF
# Vérifier
kubectl get pod safe-pod -n secure-prod
Contexte : Configurer des quotas et des limites de ressources pour un namespace de développement.
Tâches :
dev-teamSolution :
# 1. Créer le namespace
kubectl create namespace dev-team
# 2. Créer le ResourceQuota
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev-team
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
EOF
# 3. Créer le LimitRange
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: dev-team
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 250m
memory: 256Mi
max:
cpu: 2
memory: 2Gi
min:
cpu: 100m
memory: 128Mi
EOF
# Vérifier
kubectl get resourcequota -n dev-team
kubectl describe resourcequota dev-quota -n dev-team
kubectl describe limitrange dev-limits -n dev-team
# 4. Déployer Pod sans ressources
kubectl run test-pod --image=nginx -n dev-team
# Vérifier l'injection automatique
kubectl get pod test-pod -n dev-team -o yaml | grep -A 6 resources:
Contexte : Effectuer une sauvegarde complète d'etcd et restaurer en cas de problème.
Tâches :
/backup/etcd-snapshot-$(date +%Y%m%d).dbSolution :
# 1. Créer le backup
ETCDCTL_API=3 sudo etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 2. Vérifier l'intégrité
ETCDCTL_API=3 sudo etcdctl snapshot status /backup/etcd-snapshot-$(date +%Y%m%d).db --write-out=table
# Résultat attendu : table avec HASH, REVISION, TOTAL KEYS, TOTAL SIZE
# 3. Simuler perte de données
kubectl create namespace test-data
kubectl create deployment nginx --image=nginx -n test-data
kubectl delete namespace test-data
# 4. Restaurer (ATTENTION : opération critique)
# Arrêter API server temporairement
sudo mv /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/
# Restaurer etcd
ETCDCTL_API=3 sudo etcdctl snapshot restore /backup/etcd-snapshot-$(date +%Y%m%d).db \
--data-dir=/var/lib/etcd-restore
# Modifier etcd.yaml pour pointer vers le nouveau data-dir
sudo sed -i 's|/var/lib/etcd|/var/lib/etcd-restore|g' /etc/kubernetes/manifests/etcd.yaml
# Redémarrer API server
sudo mv /etc/kubernetes/kube-apiserver.yaml /etc/kubernetes/manifests/
# Vérifier
kubectl get nodes
Contexte : Le cluster semble avoir des problèmes. Diagnostiquer et réparer.
Scénario 1 : API Server ne répond pas
# Vérifier l'état de kubelet
sudo systemctl status kubelet
sudo journalctl -u kubelet -f
# Vérifier les logs du container API server
sudo crictl logs $(sudo crictl ps -a | grep kube-apiserver | awk '{print $1}')
# Vérifier le manifeste
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
# Problème courant : certificat expiré
sudo kubeadm certs check-expiration
# Renouveler tous les certificats
sudo kubeadm certs renew all
# Redémarrer kubelet
sudo systemctl restart kubelet
Scénario 2 : Pods ne peuvent pas communiquer
# Vérifier le CNI
kubectl get pods -n kube-system | grep -E 'calico|flannel|weave'
# Vérifier les logs du CNI
kubectl logs -n kube-system <cni-pod-name>
# Vérifier la configuration CNI
ls -l /etc/cni/net.d/
cat /etc/cni/net.d/*.conf
# Vérifier iptables (sur les nodes)
sudo iptables -L -n -v | grep cali
sudo iptables -t nat -L -n | grep KUBE
# Redéployer CNI si nécessaire
kubectl delete pods -n kube-system -l k8s-app=<cni-name>
Contexte : Mettre à niveau un cluster de la version 1.31.x vers 1.32.3.
Tâches :
Solution :
# 1. Vérifications pré-upgrade
kubectl version --short
kubectl get nodes -o wide
sudo kubeadm certs check-expiration
# 2. Backup etcd
ETCDCTL_API=3 sudo etcdctl snapshot save /backup/etcd-pre-upgrade-$(date +%Y%m%d-%H%M%S).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 3. Upgrader le control plane
# Drain le control plane
kubectl drain k8s-control --ignore-daemonsets
# Upgrader kubeadm
sudo apt-get update
sudo apt-get install -y --allow-change-held-packages kubeadm=1.32.3-1.1
# Planifier l'upgrade
sudo kubeadm upgrade plan v1.32.3
# Appliquer l'upgrade
sudo kubeadm upgrade apply v1.32.3
# Upgrader kubelet et kubectl
sudo apt-get install -y --allow-change-held-packages kubelet=1.32.3-1.1 kubectl=1.32.3-1.1
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# Uncordon
kubectl uncordon k8s-control
# Vérifier
kubectl get nodes
# 4. Upgrader les workers (un par un)
kubectl drain k8s-worker1 --ignore-daemonsets --force
# Sur le worker
sudo apt-get update
sudo apt-get install -y --allow-change-held-packages kubeadm=1.32.3-1.1
sudo kubeadm upgrade node
sudo apt-get install -y --allow-change-held-packages kubelet=1.32.3-1.1 kubectl=1.32.3-1.1
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# Depuis le control plane
kubectl uncordon k8s-worker1
# Répéter pour chaque worker
Contexte : Créer et utiliser une CRD pour gérer des bases de données personnalisées.
Tâches :
Database avec spec contenant type (mysql/postgres/redis) et sizepostgres et size 10GiSolution :
# 1. Créer la CRD
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databases.example.com
spec:
group: example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
type:
type: string
enum: ["mysql", "postgres", "redis"]
size:
type: string
scope: Namespaced
names:
plural: databases
singular: database
kind: Database
shortNames:
- db
EOF
# 2. Créer une instance
cat <<EOF | kubectl apply -f -
apiVersion: example.com/v1
kind: Database
metadata:
name: my-postgres
namespace: default
spec:
type: postgres
size: 10Gi
EOF
# 3. Lister les databases
kubectl get databases
kubectl get db # Utiliser le shortname
# Décrire
kubectl describe database my-postgres
# Supprimer
kubectl delete database my-postgres