Déploiement d'une application
L'objectif de cet exemple est de créer un blog (basé sur Ghost) sur le cluster Kubernetes et de conserver les fichiers du blog sur un stockage persistant.
Commandes kubectl utiles
Voici quelques commandes essentielles pour exploiter et diagnostiquer le déploiement Ghost :
# Lister les ressources du namespace blog
kubectl -n blog get all
# Obtenir les détails d'un pod
kubectl -n blog describe pod <nom-du-pod>
# Consulter les logs du conteneur Ghost
kubectl -n blog logs-l app=ghost
# Redémarrer le pod Ghost
kubectl -n blog rollout restart deployment/ghost
# Vérifier l'état du PVC
kubectl -n blog get pvc
kubectl -n blog describe pvc claim-nfs-blog
# Tester l'accès HTTP depuis le cluster
kubectl -n blog run curl --rm -it --image=alpine --restart=Never -- sh -c 'apk add curl; curl http://ghost-svc:80'Bonnes pratiques
- Nommage explicite : Utilisez des noms clairs et cohérents pour les
Namespaces,Services,PVC, etc. - Labels et annotations : Ajoutez systématiquement des labels pour le suivi, la supervision et la gestion automatisée.
- Sécurité : Limitez les droits RBAC au strict nécessaire, privilégiez des
ServiceAccountsdédiés par application. - Stockage : Vérifiez la classe de stockage (
storageClassName) et le mode d'accès (ReadWriteManypour NFS partagé). - Ressources : Définissez des
requestsetlimitspour chaque conteneur afin d'éviter les dérives de consommation. - Sauvegarde : Ajoutez les annotations nécessaires pour l'intégration avec Velero ou tout autre outil de sauvegarde.
- Supervision : Utilisez des labels pour faciliter le monitoring (Prometheus, Grafana, etc.).
Labels et annotations recommandés
L'utilisation de labels et annotations standardisés facilite l'organisation, la supervision et l'automatisation des déploiements Kubernetes. Voici les plus courants et recommandés.
Labels standards
Les labels suivants sont recommandés par la communauté Kubernetes et largement adoptés :
metadata:
labels:
# Nom de l'application
app.kubernetes.io/name: ghost
# Instance unique de l'application (utile si plusieurs instances)
app.kubernetes.io/instance: ghost-prod
# Version de l'application
app.kubernetes.io/version: "2.6.1"
# Composant dans l'architecture (frontend, backend, database)
app.kubernetes.io/component: frontend
# Nom du projet/produit de niveau supérieur
app.kubernetes.io/part-of: blog-platform
# Outil utilisé pour gérer l'application (helm, kustomize, kubectl)
app.kubernetes.io/managed-by: kubectl
# Environnement de déploiement
environment: production
# Équipe responsable
team: platform
# Criticité de l'application
criticality: highLabels personnalisés courants
metadata:
labels:
# Identification du projet
project: blog
# Coût/facturation
cost-center: "CC-1234"
billing: "departement-it"
# Conformité et sécurité
data-classification: confidential
compliance: pci-dss
# Monitoring
monitoring: enabled
alerting: criticalExemple complet
Voici un exemple de Deployment avec labels et annotations recommandés :
apiVersion: apps/v1
kind: Deployment
metadata:
name: ghost
namespace: blog
labels:
app.kubernetes.io/name: ghost
app.kubernetes.io/instance: ghost-prod
app.kubernetes.io/version: "2.6.1"
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: blog-platform
app.kubernetes.io/managed-by: kubectl
environment: production
team: platform
annotations:
description: "Blog Ghost pour documentation interne"
owner: "platform-team@example.com"
documentation: "https://wiki.example.com/ghost"
deployed-by: "ci-cd-pipeline"
git-commit: "abc123"
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: ghost
app.kubernetes.io/instance: ghost-prod
template:
metadata:
labels:
app.kubernetes.io/name: ghost
app.kubernetes.io/instance: ghost-prod
app.kubernetes.io/version: "2.6.1"
environment: production
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "2368"
prometheus.io/path: /metrics
backup.velero.io/backup-volumes: nfs-pvc
spec:
containers:
- name: ghost
image: ghost:2.6.1-alpine
ports:
- containerPort: 2368
name: http
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: nfs-pvc
mountPath: "/var/lib/ghost/content/"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: claim-nfs-blogCréation du Namespace
Le Namespace permet d'isoler les ressources d'un projet, de faciliter la gestion des droits (RBAC), la séparation des environnements (dev, prod, test) et la gestion du cycle de vie applicatif. Il est recommandé d'adopter une convention de nommage explicite (ex : blog, webapp-prod).
apiVersion: v1
kind: Namespace
metadata:
name: blog
labels:
project: blog
annotations:
owner: "noreply@sdv.fr"
description: "Namespace dédié au blog Ghost"Création du stockage persistant (PVC)
Le PersistentVolumeClaim (PVC) permet de demander dynamiquement un volume de stockage auprès d'une StorageClass (ici NFS). Il est important de bien choisir le mode d'accès (ReadWriteMany pour NFS partagé) et d'ajouter des labels/annotations pour la traçabilité et la sauvegarde.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: claim-nfs-blog
namespace: blog
labels:
app: ghost
environment: production
spec:
storageClassName: managed-nfs-storage
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1GiDéploiement de l'application Ghost
Le Deployment permet de gérer la montée en charge, la résilience et la mise à jour de l'application. Utilisez l'apiVersion: apps/v1 (standard depuis K8s 1.16+). Ajoutez un selector explicite et des ressources pour garantir la stabilité.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ghost
namespace: blog
labels:
app: ghost
environment: production
spec:
replicas: 1
selector:
matchLabels:
app: ghost
template:
metadata:
labels:
app: ghost
annotations:
backup.velero.io/backup-volumes: nfs-pvc
spec:
containers:
- name: ghost
image: ghost:2.6.1-alpine
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: nfs-pvc
mountPath: "/var/lib/ghost/content/"
ports:
- containerPort: 2368
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: claim-nfs-blogExposition de l'application (Service)
Le Service permet d'exposer le ou les pods Ghost sur le réseau du cluster et de fournir un point d'accès stable. Ici, on expose le port HTTP 80 et on cible le port 2368 du conteneur Ghost.
apiVersion: v1
kind: Service
metadata:
name: ghost-svc
namespace: blog
labels:
app: ghost
environment: production
spec:
type: ClusterIP
selector:
app: ghost
ports:
- name: http
protocol: TCP
port: 80
targetPort: 2368Publication externe (Ingress)
Le Ingress permet d'exposer le service Ghost à l'extérieur du cluster, via une URL et des règles HTTP/S. Depuis Kubernetes 1.19+, utilisez l'apiVersion: networking.k8s.io/v1 et précisez le champ pathType.
Exemple d'Ingress public
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ghost
namespace: blog
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: public
rules:
- host: ghost.{{publicVIP}}.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ghost-svc
port:
number: 80Exemple d'Ingress privé
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ghost-internal
namespace: blog
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: private
rules:
- host: ghost.{{internalVIP}}.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ghost-svc
port:
number: 80Exemple d'Ingress avec TLS (Let's Encrypt)
Dans cet exemple nous présumons que vous avez suivi le guide d'installation de cert-manager et que vous avez à votre disposition le ClusterIssuer nommé cert-manager-clusterissuer-http01-production.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ghost-tls
namespace: blog
annotations:
ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: cert-manager-clusterissuer-http01-production
spec:
ingressClassName: public
tls:
- hosts:
- ghost.{{publicVIP}}.nip.io
secretName: ghost-tls-cert
rules:
- host: ghost.{{publicVIP}}.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ghost-svc
port:
number: 80Notes d’exploitation
- Pour appliquer les manifestes :
kubectl apply -f namespace.yaml
kubectl apply -f pvc.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml- Pour vérifier le déploiement :
kubectl -n blog get all
kubectl -n blog describe pod
kubectl -n blog logs -l app=ghost- Pour supprimer l'ensemble :
kubectl delete namespace blog