Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

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 :

Terminal
# 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 ServiceAccounts dédiés par application.
  • Stockage : Vérifiez la classe de stockage (storageClassName) et le mode d'accès (ReadWriteMany pour NFS partagé).
  • Ressources : Définissez des requests et limits pour 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: high

Labels 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: critical

Exemple complet

Voici un exemple de Deployment avec labels et annotations recommandés :

deployment.yaml
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-blog

Cré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).

namespace.yaml
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.

pvc.yaml
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: 1Gi

Dé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é.

deployment.yaml
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-blog

Exposition 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.

service.yaml
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: 2368

Publication 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

ingress.yaml
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: 80

Exemple d'Ingress privé

ingress-private.yaml
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: 80

Exemple 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.

ingress-with-tls.yaml
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: 80

Notes d’exploitation

  • Pour appliquer les manifestes :
Terminal
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 :
Terminal
kubectl -n blog get all
kubectl -n blog describe pod
kubectl -n blog logs -l app=ghost
  • Pour supprimer l'ensemble :
Terminal
kubectl delete namespace blog