Aller au contenu principal

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 :

  1. Créez un Deployment nommé api-deployment avec 3 réplicas
  2. Utilisez l'image hashicorp/http-echo:0.2.3 avec l'argument -text="Hello Kubernetes"
  3. Exposez le port 5678
  4. Scalez à 5 réplicas
  5. Mettez à jour l'image vers une version différente
  6. 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 :

  1. Créez un Service ClusterIP pour le Deployment précédent
  2. Créez un Service NodePort sur le port 30080
  3. 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 :

  1. Créez un ConfigMap avec des variables de configuration
  2. Créez un Secret pour les credentials de base de données
  3. 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 :

  1. Déployez deux applications : frontend et backend
  2. Créez des Services pour chacune
  3. Configurez un Ingress pour router / vers frontend et /api vers 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 :

  1. Créez un namespace dev-team
  2. Créez un ServiceAccount dev-sa
  3. Créez un Role permettant de lire et créer des Pods et Deployments
  4. Liez le Role au ServiceAccount
  5. 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

  1. Maîtrisez kubectl - La majorité des questions nécessitent kubectl
  2. Utilisez les alias - alias k=kubectl
  3. Connaissez la documentation - kubernetes.io est accessible pendant l'examen
  4. 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

CertificationFocusDurée
CKAAdministration cluster2h
CKADDéveloppement apps2h
CKSSé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

  1. Helm - Package manager Kubernetes
  2. Observabilité - Prometheus, Grafana
  3. Service Mesh - Istio, Linkerd
  4. GitOps - ArgoCD, Flux

← Retour à la table des matières