Questions d'entretien DevOps essentielles : Guide complet 2026

Préparez vos entretiens DevOps avec les questions incontournables sur CI/CD, Kubernetes, Docker, Terraform et les pratiques SRE. Réponses détaillées incluses.

Questions d'entretien DevOps essentielles

Les entretiens DevOps évaluent une combinaison unique de compétences en développement, opérations et culture d'automatisation. Ce guide rassemble les questions les plus fréquentes, organisées par domaine, avec des réponses structurées pour démontrer une maîtrise approfondie des concepts.

Conseil préparation

Au-delà des connaissances techniques, les recruteurs évaluent la capacité à expliquer des concepts complexes simplement et à partager des expériences concrètes de résolution de problèmes.

Fondamentaux et culture DevOps

Les premières questions visent souvent à évaluer la compréhension globale de la philosophie DevOps.

Q1 : Qu'est-ce que DevOps et quels problèmes cette approche résout-elle ?

DevOps représente une culture et un ensemble de pratiques qui unifient le développement logiciel (Dev) et les opérations informatiques (Ops). Cette approche vise à raccourcir le cycle de développement tout en maintenant une haute qualité.

yaml
# devops-principles.yaml
# Les piliers de la culture DevOps
principles:
  collaboration:
    description: "Briser les silos entre équipes"
    practices:
      - "Responsabilité partagée du code en production"
      - "Communication continue via ChatOps"
      - "Post-mortems sans blâme (blameless)"

  automation:
    description: "Automatiser les tâches répétitives"
    practices:
      - "Infrastructure as Code (IaC)"
      - "CI/CD pipelines"
      - "Tests automatisés à tous les niveaux"

  measurement:
    description: "Mesurer pour améliorer"
    metrics:
      - "Deployment frequency"
      - "Lead time for changes"
      - "Mean time to recovery (MTTR)"
      - "Change failure rate"

  sharing:
    description: "Partager les connaissances"
    practices:
      - "Documentation as Code"
      - "Runbooks automatisés"
      - "Sessions de partage régulières"

Les problèmes résolus incluent les déploiements lents et risqués, le manque de visibilité entre équipes, et l'incohérence entre environnements.

Q2 : Quelle est la différence entre CI, CD (Continuous Delivery) et CD (Continuous Deployment) ?

Ces trois concepts forment une progression dans l'automatisation du cycle de livraison.

bash
# ci-cd-pipeline-stages.sh
# Illustration des étapes CI/CD

# ============================================
# CI (Continuous Integration)
# ============================================
# Objectif : Intégrer fréquemment le code dans un dépôt partagé
# Automatisation : Build + Tests
echo "CI: Code commit → Build → Unit Tests → Integration Tests"

# ============================================
# CD (Continuous Delivery)
# ============================================
# Objectif : Code toujours déployable en production
# Automatisation : CI + Déploiement en staging + Approbation manuelle
echo "CD Delivery: CI → Deploy Staging → Manual Approval → Deploy Prod"

# ============================================
# CD (Continuous Deployment)
# ============================================
# Objectif : Déploiement automatique en production
# Automatisation : Tout le pipeline sans intervention humaine
echo "CD Deployment: CI → Deploy Staging → Auto Tests → Auto Deploy Prod"

La distinction clé réside dans le niveau d'automatisation : Continuous Delivery requiert une validation manuelle avant la production, tandis que Continuous Deployment automatise entièrement le processus.

CI/CD et pipelines

Les questions sur CI/CD testent la capacité à concevoir et optimiser des pipelines de livraison.

Q3 : Comment structurer un pipeline CI/CD robuste ?

Un pipeline bien conçu suit des étapes progressives avec des points de contrôle à chaque niveau.

yaml
# .gitlab-ci.yml
# Pipeline CI/CD complet avec stages parallèles et séquentiels
stages:
  - validate
  - build
  - test
  - security
  - deploy-staging
  - integration-tests
  - deploy-production

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

# ============================================
# Stage 1 : Validation rapide (< 2 min)
# ============================================
lint:
  stage: validate
  script:
    - npm run lint
    - npm run type-check
  # Exécution sur chaque commit
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH

# ============================================
# Stage 2 : Build de l'application
# ============================================
build:
  stage: build
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE
  # Cache des layers Docker pour accélérer les builds
  cache:
    key: docker-$CI_COMMIT_REF_SLUG
    paths:
      - .docker-cache/

# ============================================
# Stage 3 : Tests en parallèle
# ============================================
unit-tests:
  stage: test
  script:
    - npm run test:unit -- --coverage
  coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

integration-tests:
  stage: test
  services:
    - postgres:16-alpine
    - redis:7-alpine
  script:
    - npm run test:integration
  # Parallélisation avec les unit tests
  parallel: 3

# ============================================
# Stage 4 : Analyse de sécurité
# ============================================
sast:
  stage: security
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $DOCKER_IMAGE
  allow_failure: false

dependency-scan:
  stage: security
  script:
    - npm audit --audit-level=high
  allow_failure: true  # Alerte sans bloquer

# ============================================
# Stage 5 : Déploiement staging
# ============================================
deploy-staging:
  stage: deploy-staging
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE -n staging
    - kubectl rollout status deployment/app -n staging --timeout=300s
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

# ============================================
# Stage 6 : Tests E2E sur staging
# ============================================
e2e-tests:
  stage: integration-tests
  script:
    - npm run test:e2e -- --base-url=https://staging.example.com
  artifacts:
    when: on_failure
    paths:
      - cypress/screenshots/
      - cypress/videos/
  only:
    - develop

# ============================================
# Stage 7 : Déploiement production
# ============================================
deploy-production:
  stage: deploy-production
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE -n production
    - kubectl rollout status deployment/app -n production --timeout=300s
  environment:
    name: production
    url: https://app.example.com
  # Déploiement manuel avec protection
  when: manual
  only:
    - main

Ce pipeline illustre les bonnes pratiques : stages parallèles pour la rapidité, artifacts pour la traçabilité, et environnements protégés pour la production.

Q4 : Comment gérer les secrets dans un pipeline CI/CD ?

La gestion des secrets requiert une approche multicouche combinant chiffrement, rotation et principe du moindre privilège.

yaml
# kubernetes-secrets-management.yaml
# Approche 1 : External Secrets Operator avec HashiCorp Vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
  namespace: production
spec:
  refreshInterval: 1h  # Rotation automatique
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: app-secrets
    creationPolicy: Owner
  data:
    # Référence au secret dans Vault
    - secretKey: DATABASE_PASSWORD
      remoteRef:
        key: secret/data/production/database
        property: password
    - secretKey: API_KEY
      remoteRef:
        key: secret/data/production/api
        property: key
---
# Configuration du SecretStore
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "external-secrets"
          # ServiceAccount dédié avec permissions minimales
          serviceAccountRef:
            name: external-secrets-sa

Les pratiques recommandées incluent : ne jamais stocker de secrets en clair dans le code, utiliser des gestionnaires de secrets dédiés (Vault, AWS Secrets Manager), et activer la rotation automatique.

Anti-pattern

Éviter les variables d'environnement CI/CD visibles dans les logs. Toujours masquer les secrets avec les fonctionnalités natives de la plateforme CI (masked variables).

Kubernetes et orchestration

Les questions Kubernetes évaluent la compréhension des concepts d'orchestration et la capacité à résoudre des problèmes concrets.

Q5 : Expliquez l'architecture de Kubernetes et le rôle de chaque composant.

Kubernetes suit une architecture maître-nœuds avec des composants aux responsabilités distinctes.

yaml
# kubernetes-architecture.yaml
# Composants du Control Plane (Master)
control_plane:
  api_server:
    role: "Point d'entrée de toutes les requêtes API"
    responsibilities:
      - "Validation et configuration des objets API"
      - "Authentification et autorisation"
      - "Interface REST pour kubectl et autres clients"

  etcd:
    role: "Base de données clé-valeur distribuée"
    responsibilities:
      - "Stockage de l'état du cluster"
      - "Source de vérité pour la configuration"
      - "Consensus via algorithme Raft"

  scheduler:
    role: "Affectation des Pods aux nœuds"
    responsibilities:
      - "Évaluation des contraintes (resources, affinity)"
      - "Sélection du nœud optimal"
      - "Respect des PodDisruptionBudgets"

  controller_manager:
    role: "Boucles de contrôle pour l'état désiré"
    controllers:
      - "ReplicaSet Controller"
      - "Deployment Controller"
      - "Service Controller"
      - "Node Controller"

# Composants des Worker Nodes
worker_nodes:
  kubelet:
    role: "Agent sur chaque nœud"
    responsibilities:
      - "Communication avec le Control Plane"
      - "Gestion du cycle de vie des Pods"
      - "Reporting de l'état du nœud"

  kube_proxy:
    role: "Proxy réseau sur chaque nœud"
    responsibilities:
      - "Règles iptables/IPVS pour les Services"
      - "Load balancing intra-cluster"

  container_runtime:
    role: "Exécution des conteneurs"
    options:
      - "containerd (recommandé)"
      - "CRI-O"

Cette architecture permet une haute disponibilité : le Control Plane peut être répliqué, et les workloads sont distribués sur les Worker Nodes.

Q6 : Comment déboguer un Pod qui ne démarre pas ?

Le debugging Kubernetes suit une approche méthodique en analysant les différentes couches.

bash
# kubernetes-debugging.sh
# Workflow de debugging d'un Pod défaillant

# Étape 1 : Vérifier l'état du Pod
kubectl get pod my-app-pod -o wide
# STATUS: CrashLoopBackOff, ImagePullBackOff, Pending, etc.

# Étape 2 : Détails et événements du Pod
kubectl describe pod my-app-pod
# Sections importantes :
# - Conditions (PodScheduled, Initialized, Ready)
# - Events (erreurs de scheduling, pull, etc.)

# Étape 3 : Logs du conteneur
kubectl logs my-app-pod --previous  # Logs du crash précédent
kubectl logs my-app-pod -c init-container  # Logs init container

# Étape 4 : Exécution interactive pour debugging
kubectl exec -it my-app-pod -- sh
# Vérifier : variables d'env, fichiers montés, réseau

# Étape 5 : Vérifier les ressources disponibles
kubectl describe node <node-name>
# Sections : Allocatable, Allocated resources

# Étape 6 : Debug avec un Pod éphémère (K8s 1.25+)
kubectl debug my-app-pod -it --image=busybox --share-processes

Les causes fréquentes incluent : resources insuffisantes, image introuvable, secrets manquants, ou probes mal configurées.

yaml
# pod-debugging-checklist.yaml
# Checklist de debugging selon le status
debugging_by_status:
  Pending:
    causes:
      - "Ressources insuffisantes sur les nœuds"
      - "PersistentVolumeClaim non bound"
      - "Affinity/Taints non satisfaits"
    commands:
      - "kubectl describe pod <name> | grep -A 20 Events"
      - "kubectl get pvc"
      - "kubectl describe nodes | grep -A 5 Allocated"

  ImagePullBackOff:
    causes:
      - "Image inexistante ou tag incorrect"
      - "Registry privé sans imagePullSecrets"
      - "Rate limiting Docker Hub"
    commands:
      - "kubectl get events --field-selector reason=Failed"
      - "kubectl get secret <pull-secret> -o yaml"

  CrashLoopBackOff:
    causes:
      - "Erreur applicative au démarrage"
      - "Configuration manquante (env vars, configmaps)"
      - "Liveness probe trop agressive"
    commands:
      - "kubectl logs <pod> --previous"
      - "kubectl describe pod <pod> | grep -A 10 Liveness"

  OOMKilled:
    causes:
      - "Limite mémoire trop basse"
      - "Memory leak dans l'application"
    commands:
      - "kubectl describe pod <pod> | grep -A 5 Last State"
      - "kubectl top pod <pod>"

Prêt à réussir tes entretiens DevOps ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Infrastructure as Code

Les questions IaC évaluent la maîtrise des outils de provisionnement et les bonnes pratiques.

Q7 : Terraform vs Ansible : quand utiliser chaque outil ?

Ces outils ont des philosophies et cas d'usage distincts.

hcl
# terraform-example.tf
# Terraform : Provisionnement d'infrastructure (déclaratif)
# Idéal pour : cloud resources, networking, état infrastructure

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  # État distant pour collaboration
  backend "s3" {
    bucket         = "terraform-state-prod"
    key            = "infrastructure/terraform.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

# Ressource déclarative : Terraform gère le cycle de vie
resource "aws_eks_cluster" "main" {
  name     = "production-cluster"
  role_arn = aws_iam_role.eks_cluster.arn
  version  = "1.29"

  vpc_config {
    subnet_ids              = module.vpc.private_subnets
    endpoint_private_access = true
    endpoint_public_access  = false
  }

  # Dépendances implicites gérées par Terraform
  depends_on = [
    aws_iam_role_policy_attachment.eks_cluster_policy
  ]
}

# Modules réutilisables pour la standardisation
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = "production-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  single_nat_gateway = false  # HA : un NAT par AZ
}
yaml
# ansible-example.yml
# Ansible : Configuration management (procédural/déclaratif)
# Idéal pour : configuration OS, déploiement apps, orchestration

---
- name: Configure application servers
  hosts: app_servers
  become: yes
  vars:
    app_version: "2.5.0"

  tasks:
    # Gestion des packages système
    - name: Install required packages
      ansible.builtin.apt:
        name:
          - nginx
          - python3-pip
          - supervisor
        state: present
        update_cache: yes

    # Configuration via templates Jinja2
    - name: Deploy nginx configuration
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/sites-available/app
        owner: root
        group: root
        mode: '0644'
      notify: Reload nginx

    # Déploiement applicatif
    - name: Deploy application
      ansible.builtin.git:
        repo: "https://github.com/org/app.git"
        dest: /opt/app
        version: "v{{ app_version }}"
      notify: Restart application

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded

    - name: Restart application
      ansible.builtin.supervisorctl:
        name: app
        state: restarted

En résumé : Terraform pour l'infrastructure (ce qui existe), Ansible pour la configuration (comment c'est configuré). Les deux outils sont souvent combinés dans un workflow complet.

Q8 : Comment structurer un projet Terraform pour une grande organisation ?

Une structure modulaire avec séparation des environnements facilite la maintenance et la collaboration.

bash
# terraform-project-structure
# Structure recommandée pour projets enterprise

terraform-infrastructure/
├── modules/                    # Modules réutilisables
│   ├── networking/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── README.md
│   ├── kubernetes/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   └── database/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
├── environments/               # Configuration par environnement
│   ├── dev/
│   │   ├── main.tf            # Appelle les modules
│   │   ├── variables.tf
│   │   ├── terraform.tfvars   # Valeurs dev
│   │   └── backend.tf         # State dev
│   ├── staging/
│   │   ├── main.tf
│   │   ├── terraform.tfvars
│   │   └── backend.tf
│   └── production/
│       ├── main.tf
│       ├── terraform.tfvars
│       └── backend.tf
├── shared/                     # Ressources partagées
│   ├── iam/
│   └── dns/
└── .github/
    └── workflows/
        └── terraform.yml      # CI/CD pipeline
hcl
# environments/production/main.tf
# Exemple d'utilisation des modules

module "networking" {
  source = "../../modules/networking"

  environment     = "production"
  vpc_cidr        = var.vpc_cidr
  azs             = var.availability_zones
  enable_flow_logs = true
}

module "kubernetes" {
  source = "../../modules/kubernetes"

  environment    = "production"
  cluster_name   = "prod-cluster"
  vpc_id         = module.networking.vpc_id
  subnet_ids     = module.networking.private_subnet_ids
  node_groups    = var.node_groups

  # Production : configuration HA
  cluster_version           = "1.29"
  enable_cluster_autoscaler = true
}

module "database" {
  source = "../../modules/database"

  environment        = "production"
  vpc_id             = module.networking.vpc_id
  subnet_ids         = module.networking.database_subnet_ids
  instance_class     = "db.r6g.xlarge"
  multi_az           = true  # HA en production
  backup_retention   = 30
}

Cette structure permet : versionning des modules, review des changements par environnement, et réutilisation du code.

Monitoring et observabilité

Les questions sur le monitoring évaluent la capacité à concevoir des systèmes observables.

Q9 : Quels sont les trois piliers de l'observabilité ?

L'observabilité repose sur trois types de données complémentaires qui permettent de comprendre l'état interne d'un système.

yaml
# observability-pillars.yaml
# Les trois piliers de l'observabilité

pillars:
  metrics:
    description: "Données numériques agrégées dans le temps"
    characteristics:
      - "Faible cardinalité"
      - "Stockage efficace"
      - "Idéal pour alerting"
    examples:
      - "request_count (counter)"
      - "response_time_seconds (histogram)"
      - "active_connections (gauge)"
    tools:
      - "Prometheus"
      - "Datadog"
      - "CloudWatch"
    use_cases:
      - "Dashboards temps réel"
      - "Alertes sur seuils"
      - "Capacity planning"

  logs:
    description: "Événements textuels horodatés"
    characteristics:
      - "Haute cardinalité"
      - "Contexte détaillé"
      - "Stockage volumineux"
    examples:
      - "Application errors"
      - "Audit events"
      - "Debug information"
    tools:
      - "Loki"
      - "Elasticsearch"
      - "CloudWatch Logs"
    use_cases:
      - "Debugging"
      - "Audit compliance"
      - "Root cause analysis"

  traces:
    description: "Suivi des requêtes à travers les services"
    characteristics:
      - "Vue end-to-end"
      - "Propagation de contexte"
      - "Identification des goulots"
    examples:
      - "Distributed transaction"
      - "Service dependencies"
      - "Latency breakdown"
    tools:
      - "Jaeger"
      - "Tempo"
      - "AWS X-Ray"
    use_cases:
      - "Performance optimization"
      - "Service dependencies"
      - "Error propagation"

Q10 : Comment configurer des alertes efficaces ?

Des alertes bien conçues réduisent la fatigue et permettent une réponse rapide aux incidents.

yaml
# prometheus-alerting-rules.yaml
# Règles d'alerte Prometheus avec bonnes pratiques

groups:
  - name: application-alerts
    rules:
      # Alerte sur symptôme, pas sur cause
      - alert: HighErrorRate
        # Taux d'erreurs > 1% sur 5 minutes
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m]))
          /
          sum(rate(http_requests_total[5m]))
          > 0.01
        for: 5m  # Éviter les faux positifs
        labels:
          severity: critical
          team: backend
        annotations:
          summary: "High error rate detected"
          description: |
            Error rate is {{ $value | humanizePercentage }}
            for the last 5 minutes.
          runbook_url: "https://wiki.example.com/runbooks/high-error-rate"

      # Alerte proactive sur saturation
      - alert: DiskSpaceRunningLow
        expr: |
          (node_filesystem_avail_bytes / node_filesystem_size_bytes)
          * 100 < 20
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "Disk space below 20%"
          description: |
            Node {{ $labels.instance }} has only
            {{ $value | humanize }}% disk space remaining.

      # SLO-based alerting
      - alert: SLOBudgetBurnRate
        # Budget d'erreur consommé trop rapidement
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[1h]))
            /
            sum(rate(http_requests_total[1h]))
          ) > (1 - 0.999) * 14.4
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "SLO budget burning too fast"
          description: |
            At current error rate, monthly SLO budget will be
            exhausted in less than 2 days.
yaml
# alertmanager-config.yaml
# Configuration AlertManager avec routing intelligent

global:
  resolve_timeout: 5m

route:
  receiver: default
  group_by: [alertname, cluster, service]
  group_wait: 30s       # Attendre pour grouper les alertes
  group_interval: 5m    # Intervalle entre notifications groupées
  repeat_interval: 4h   # Ré-alerter si non résolu

  routes:
    # Alertes critiques : notification immédiate
    - match:
        severity: critical
      receiver: pagerduty-critical
      continue: true  # Aussi notifier Slack

    # Alertes par équipe
    - match:
        team: backend
      receiver: slack-backend

    - match:
        team: infrastructure
      receiver: slack-infra

receivers:
  - name: pagerduty-critical
    pagerduty_configs:
      - service_key: <pagerduty-key>
        severity: critical

  - name: slack-backend
    slack_configs:
      - channel: '#alerts-backend'
        send_resolved: true
        title: '{{ .Status | toUpper }}: {{ .CommonAnnotations.summary }}'
        text: '{{ .CommonAnnotations.description }}'

Les principes clés : alerter sur les symptômes (impact utilisateur) plutôt que les causes, inclure des runbooks, et ajuster les seuils selon les SLOs.

Sécurité et compliance

Les questions de sécurité évaluent la compréhension des risques et des contre-mesures.

Q11 : Comment sécuriser un cluster Kubernetes ?

La sécurisation de Kubernetes couvre plusieurs couches : réseau, authentification, workloads et données.

yaml
# kubernetes-security-policies.yaml
# NetworkPolicy : isolation réseau entre namespaces

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  # Appliqué à tous les pods du namespace
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  # Aucun trafic autorisé par défaut
  ingress: []
  egress: []
---
# Autoriser uniquement le trafic nécessaire
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-network-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # Accepter uniquement depuis l'ingress controller
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080
  egress:
    # Autoriser vers la base de données
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    # Autoriser DNS
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
yaml
# pod-security-standards.yaml
# PodSecurity : restrictions sur les workloads

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    # Enforce : bloque les violations
    pod-security.kubernetes.io/enforce: restricted
    # Warn : avertit sans bloquer
    pod-security.kubernetes.io/warn: restricted
    # Audit : log les violations
    pod-security.kubernetes.io/audit: restricted
---
# Pod conforme aux standards "restricted"
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
  namespace: production
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: myapp:latest
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
      resources:
        limits:
          memory: "256Mi"
          cpu: "500m"
        requests:
          memory: "128Mi"
          cpu: "250m"
      volumeMounts:
        - name: tmp
          mountPath: /tmp
  volumes:
    - name: tmp
      emptyDir: {}
Defense in depth

La sécurité Kubernetes combine plusieurs couches : RBAC pour l'autorisation, NetworkPolicies pour l'isolation réseau, PodSecurity pour les restrictions workload, et le chiffrement des secrets au repos.

Q12 : Qu'est-ce que le principe du moindre privilège et comment l'appliquer ?

Ce principe stipule qu'un utilisateur ou système ne doit avoir que les permissions minimales nécessaires pour accomplir sa tâche.

yaml
# rbac-least-privilege.yaml
# RBAC Kubernetes avec permissions minimales

# Role : permissions dans un namespace spécifique
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: deployment-manager
rules:
  # Lecture des pods (pour monitoring)
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
  # Gestion des deployments uniquement
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "update", "patch"]
  # Pas de create/delete sur les deployments
  # Pas d'accès aux secrets ou configmaps sensibles
---
# RoleBinding : association Role <-> ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployment-manager-binding
  namespace: production
subjects:
  - kind: ServiceAccount
    name: ci-cd-deployer
    namespace: production
roleRef:
  kind: Role
  name: deployment-manager
  apiGroup: rbac.authorization.k8s.io
---
# ServiceAccount dédié pour le CI/CD
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-cd-deployer
  namespace: production
  annotations:
    # Expiration automatique des tokens
    kubernetes.io/enforce-mountable-secrets: "true"

Ce principe s'applique également à AWS IAM, aux bases de données, et aux accès réseau.

SRE et fiabilité

Les questions SRE évaluent la compréhension des pratiques de fiabilité et de gestion des incidents.

Q13 : Qu'est-ce qu'un SLO et comment le définir ?

Les Service Level Objectives (SLOs) quantifient la fiabilité attendue d'un service et guident les décisions d'ingénierie.

yaml
# slo-definitions.yaml
# Définition de SLOs pour un service API

service: payment-api
owner: payments-team

slos:
  - name: availability
    description: "Le service répond avec succès aux requêtes"
    sli:
      # SLI : métrique mesurée
      type: availability
      good_events: "http_requests_total{status=~'2..'}"
      total_events: "http_requests_total"
    target: 99.9%  # SLO : objectif
    window: 30d    # Fenêtre de mesure
    # Budget d'erreur : 0.1% = 43.2 minutes/mois
    error_budget:
      monthly_minutes: 43.2

  - name: latency
    description: "Temps de réponse sous le seuil"
    sli:
      type: latency
      good_events: "http_request_duration_seconds_bucket{le='0.3'}"
      total_events: "http_request_duration_seconds_count"
    target: 99%  # 99% des requêtes < 300ms
    window: 30d

  - name: throughput
    description: "Capacité à traiter les transactions"
    sli:
      type: throughput
      query: "sum(rate(transactions_processed_total[5m]))"
    target: ">= 1000 TPS"

# Actions basées sur le budget d'erreur
error_budget_policy:
  - condition: "remaining > 50%"
    actions:
      - "Feature development prioritized"
      - "Experimentation allowed"
  - condition: "remaining 20-50%"
    actions:
      - "Balance features and reliability"
      - "Increase testing coverage"
  - condition: "remaining < 20%"
    actions:
      - "Freeze non-critical deployments"
      - "Focus on reliability improvements"
  - condition: "exhausted"
    actions:
      - "Incident response mode"
      - "All hands on reliability"

Les SLOs permettent de prendre des décisions objectives : déployer une nouvelle feature vs renforcer la fiabilité.

Q14 : Comment mener un post-mortem efficace ?

Un post-mortem sans blâme favorise l'apprentissage et la prévention des incidents futurs.

yaml
# postmortem-template.yaml
# Template de post-mortem blameless

incident:
  id: "INC-2026-0042"
  title: "Indisponibilité du service de paiement"
  severity: SEV1
  duration: "45 minutes"
  date: "2026-01-15"

# Chronologie factuelle
timeline:
  - time: "14:32"
    event: "Alerting : error rate > 5% sur payment-api"
    actor: "PagerDuty"
  - time: "14:35"
    event: "Incident déclaré, équipe notifiée"
    actor: "On-call engineer"
  - time: "14:42"
    event: "Cause identifiée : connection pool exhausted"
    actor: "Backend team"
  - time: "14:55"
    event: "Mitigation : rollback du deployment"
    actor: "Backend team"
  - time: "15:17"
    event: "Service restauré, monitoring stable"
    actor: "Backend team"

# Impact mesurable
impact:
  users_affected: 12500
  transactions_failed: 847
  revenue_impact: "~15,000€"
  slo_budget_consumed: "2.3 days"

# Analyse des causes (5 Whys)
root_cause_analysis:
  - question: "Pourquoi le service était indisponible ?"
    answer: "Les connexions DB étaient épuisées"
  - question: "Pourquoi les connexions étaient épuisées ?"
    answer: "Une requête lente bloquait les connexions"
  - question: "Pourquoi y avait-il une requête lente ?"
    answer: "Index manquant sur une nouvelle table"
  - question: "Pourquoi l'index manquait-il ?"
    answer: "Migration incomplète déployée"
  - question: "Pourquoi la migration était-elle incomplète ?"
    answer: "Pas de validation du plan d'exécution en staging"

# Actions correctives
action_items:
  - id: "AI-001"
    type: "prevent"
    description: "Ajouter validation du plan d'exécution SQL en CI"
    owner: "DBA team"
    due_date: "2026-01-22"
    priority: P1

  - id: "AI-002"
    type: "detect"
    description: "Alerter sur connection pool usage > 80%"
    owner: "SRE team"
    due_date: "2026-01-18"
    priority: P1

  - id: "AI-003"
    type: "mitigate"
    description: "Implémenter circuit breaker sur les requêtes DB"
    owner: "Backend team"
    due_date: "2026-01-29"
    priority: P2

# Leçons apprises
lessons_learned:
  what_went_well:
    - "Détection rapide grâce à l'alerting (< 3 min)"
    - "Communication claire dans le channel incident"
    - "Rollback effectué en moins de 15 minutes"
  what_went_poorly:
    - "Pas de test de charge sur le nouveau endpoint"
    - "Staging ne reflétait pas le volume de données prod"
  lucky:
    - "Incident en journée avec équipe complète disponible"

L'objectif est d'améliorer le système, pas de trouver un coupable. Les actions se classent en trois catégories : prévention, détection et mitigation.

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

Conclusion

Les entretiens DevOps couvrent un spectre large de compétences, de la culture aux outils techniques. La clé du succès réside dans la capacité à démontrer une compréhension approfondie des concepts, illustrée par des exemples concrets d'implémentation.

Checklist de préparation

  • ✅ Maîtriser les concepts CI/CD et pouvoir concevoir un pipeline complet
  • ✅ Comprendre l'architecture Kubernetes et savoir déboguer des problèmes courants
  • ✅ Connaître les outils IaC (Terraform, Ansible) et leurs cas d'usage respectifs
  • ✅ Savoir configurer le monitoring et définir des alertes pertinentes
  • ✅ Appliquer les bonnes pratiques de sécurité (least privilege, defense in depth)
  • ✅ Expliquer les pratiques SRE (SLOs, error budgets, post-mortems)
  • ✅ Avoir des exemples concrets de résolution de problèmes
  • ✅ Pouvoir expliquer des concepts complexes simplement

Tags

#devops
#interview
#ci cd
#kubernetes
#infrastructure

Partager

Articles similaires