Exercices et Projets
1 - Exercices pratiques
Exercice 1 : Pods et Conteneurs
Objectif : Créer et gérer des Pods
# Créez un Pod avec les spécifications suivantes :
# - Nom : web-server
# - Image : nginx:1.25
# - Port : 80
# - Labels : app=web, tier=frontend
# - Resource requests : 100m CPU, 128Mi memory
# - Resource limits : 200m CPU, 256Mi memory
# - Liveness probe : HTTP GET /healthz port 80
# - Readiness probe : HTTP GET / port 80
Solution
apiVersion: v1
kind: Pod
metadata:
name: web-server
labels:
app: web
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 3
Exercice 2 : Deployments
Objectif : Créer un Deployment avec scaling
Tâches :
- Créez un Deployment nommé
api-deploymentavec 3 réplicas - Utilisez l'image
hashicorp/http-echo:0.2.3avec l'argument-text="Hello Kubernetes" - Exposez le port 5678
- Scalez à 5 réplicas
- Mettez à jour l'image vers une version différente
- Effectuez un rollback
Solution
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: hashicorp/http-echo:0.2.3
args:
- "-text=Hello Kubernetes"
ports:
- containerPort: 5678
# Appliquer
kubectl apply -f deployment.yaml
# Scaler à 5 réplicas
kubectl scale deployment api-deployment --replicas=5
# Mettre à jour l'image
kubectl set image deployment/api-deployment api=hashicorp/http-echo:0.2.3
# Vérifier l'historique
kubectl rollout history deployment/api-deployment
# Rollback
kubectl rollout undo deployment/api-deployment
Exercice 3 : Services
Objectif : Exposer une application avec différents types de Services
Tâches :
- Créez un Service ClusterIP pour le Deployment précédent
- Créez un Service NodePort sur le port 30080
- Testez l'accès depuis l'intérieur du cluster
Solution
# service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: api-clusterip
spec:
type: ClusterIP
selector:
app: api
ports:
- port: 80
targetPort: 5678
---
# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: api-nodeport
spec:
type: NodePort
selector:
app: api
ports:
- port: 80
targetPort: 5678
nodePort: 30080
# Tester depuis l'intérieur du cluster
kubectl run test --rm -it --image=busybox -- wget -qO- http://api-clusterip
Exercice 4 : ConfigMaps et Secrets
Objectif : Gérer la configuration d'une application
Tâches :
- Créez un ConfigMap avec des variables de configuration
- Créez un Secret pour les credentials de base de données
- Utilisez-les dans un Pod
Solution
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: production
LOG_LEVEL: info
config.json: |
{
"apiUrl": "https://api.example.com",
"timeout": 30
}
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
DB_HOST: mysql.default.svc.cluster.local
DB_USER: appuser
DB_PASSWORD: secretpassword123
---
# pod-with-config.yaml
apiVersion: v1
kind: Pod
metadata:
name: configured-app
spec:
containers:
- name: app
image: busybox
command: ['sh', '-c', 'env && sleep 3600']
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: db-credentials
volumeMounts:
- name: config-file
mountPath: /etc/config
volumes:
- name: config-file
configMap:
name: app-config
items:
- key: config.json
path: config.json
Exercice 5 : Ingress
Objectif : Configurer le routage HTTP avec Ingress
Tâches :
- Déployez deux applications :
frontendetbackend - Créez des Services pour chacune
- Configurez un Ingress pour router
/vers frontend et/apivers backend
Solution
# deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: hashicorp/http-echo:0.2.3
args: ["-text=Frontend"]
ports:
- containerPort: 5678
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 2
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: hashicorp/http-echo:0.2.3
args: ["-text=Backend API"]
ports:
- containerPort: 5678
---
# services.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-svc
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: backend-svc
spec:
selector:
app: backend
ports:
- port: 80
targetPort: 5678
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend-svc
port:
number: 80
Exercice 6 : RBAC
Objectif : Configurer le contrôle d'accès
Tâches :
- Créez un namespace
dev-team - Créez un ServiceAccount
dev-sa - Créez un Role permettant de lire et créer des Pods et Deployments
- Liez le Role au ServiceAccount
- Testez les permissions
Solution
# rbac-setup.yaml
apiVersion: v1
kind: Namespace
metadata:
name: dev-team
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: dev-sa
namespace: dev-team
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dev-role
namespace: dev-team
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-role-binding
namespace: dev-team
subjects:
- kind: ServiceAccount
name: dev-sa
namespace: dev-team
roleRef:
kind: Role
name: dev-role
apiGroup: rbac.authorization.k8s.io
# Tester les permissions
kubectl auth can-i create pods -n dev-team --as system:serviceaccount:dev-team:dev-sa
kubectl auth can-i delete secrets -n dev-team --as system:serviceaccount:dev-team:dev-sa
2 - Projet complet : Application de vote
Description
Déployez une application de vote complète comprenant :
- Frontend : Interface utilisateur (voting-app)
- API : Traitement des votes (worker)
- Redis : File d'attente des votes
- PostgreSQL : Stockage des résultats
- Results : Affichage des résultats
Architecture Kubernetes
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: voting-app
labels:
app: voting
---
# redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: voting-app
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: voting-app
spec:
selector:
app: redis
ports:
- port: 6379
---
# postgres.yaml
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
namespace: voting-app
stringData:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres123
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: voting-app
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: voting-app
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
envFrom:
- secretRef:
name: postgres-secret
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres-pvc
---
apiVersion: v1
kind: Service
metadata:
name: db
namespace: voting-app
spec:
selector:
app: postgres
ports:
- port: 5432
---
# voting-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: voting-app
namespace: voting-app
spec:
replicas: 3
selector:
matchLabels:
app: voting-app
template:
metadata:
labels:
app: voting-app
spec:
containers:
- name: voting-app
image: dockersamples/examplevotingapp_vote
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: voting-app
namespace: voting-app
spec:
type: ClusterIP
selector:
app: voting-app
ports:
- port: 80
---
# worker.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker
namespace: voting-app
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: worker
image: dockersamples/examplevotingapp_worker
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
---
# result-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: result-app
namespace: voting-app
spec:
replicas: 2
selector:
matchLabels:
app: result-app
template:
metadata:
labels:
app: result-app
spec:
containers:
- name: result-app
image: dockersamples/examplevotingapp_result
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
name: result-app
namespace: voting-app
spec:
type: ClusterIP
selector:
app: result-app
ports:
- port: 80
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: voting-ingress
namespace: voting-app
spec:
ingressClassName: nginx
rules:
- host: vote.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: voting-app
port:
number: 80
- host: results.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: result-app
port:
number: 80
---
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: voting-app
spec:
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-voting-to-redis
namespace: voting-app
spec:
podSelector:
matchLabels:
app: redis
ingress:
- from:
- podSelector:
matchLabels:
app: voting-app
- podSelector:
matchLabels:
app: worker
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-worker-to-db
namespace: voting-app
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: worker
- podSelector:
matchLabels:
app: result-app
---
# resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: voting-quota
namespace: voting-app
spec:
hard:
requests.cpu: "2"
requests.memory: 2Gi
limits.cpu: "4"
limits.memory: 4Gi
pods: "20"
---
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: voting-app-hpa
namespace: voting-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: voting-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Déploiement
# Créer tous les fichiers dans un dossier voting-app/
# Puis appliquer
kubectl apply -f voting-app/
# Vérifier le déploiement
kubectl get all -n voting-app
# Voir les logs
kubectl logs -n voting-app -l app=worker
# Tester l'application
# Ajouter dans /etc/hosts : <INGRESS_IP> vote.local results.local
# Ouvrir http://vote.local et http://results.local
3 - Préparation à la certification CKA/CKAD
Conseils pour l'examen
- Maîtrisez kubectl - La majorité des questions nécessitent kubectl
- Utilisez les alias -
alias k=kubectl - Connaissez la documentation - kubernetes.io est accessible pendant l'examen
- Pratiquez avec des clusters réels - Minikube, Kind, ou playground
Commandes essentielles
# Créer rapidement des ressources
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > deployment.yaml
kubectl expose deployment nginx --port=80 --type=ClusterIP --dry-run=client -o yaml > service.yaml
# Debugging
kubectl describe pod <pod-name>
kubectl logs <pod-name> -c <container-name>
kubectl exec -it <pod-name> -- /bin/bash
kubectl get events --sort-by='.lastTimestamp'
# Contextes et namespaces
kubectl config set-context --current --namespace=<namespace>
kubectl config use-context <context-name>
# Documentation rapide
kubectl explain pod.spec.containers
kubectl explain deployment.spec.strategy
Ressources pour la certification
| Certification | Focus | Durée |
|---|---|---|
| CKA | Administration cluster | 2h |
| CKAD | Développement apps | 2h |
| CKS | Sécurité | 2h |
Résumé du cours
Félicitations ! Vous avez complété le cours Kubernetes. Vous maîtrisez maintenant :
- L'architecture Kubernetes et ses composants
- La création et gestion des Pods, Deployments, Services
- La configuration avec ConfigMaps et Secrets
- Le stockage persistant avec PV/PVC
- La sécurité avec RBAC et Network Policies
- Le scaling et les mises à jour
Prochaines étapes recommandées
- Helm - Package manager Kubernetes
- Observabilité - Prometheus, Grafana
- Service Mesh - Istio, Linkerd
- GitOps - ArgoCD, Flux