
Popeye scanne votre cluster Kubernetes en temps réel et génère un rapport de santé avec un score de 0 à 100. L’outil détecte les mauvaises configurations courantes : images taguées latest, absence de limites CPU/mémoire, pods sans probes, conteneurs root, secrets inutilisés. En 30 secondes, vous savez ce qui doit être corrigé.
Ce guide vous montre comment :
- Installer Popeye via mise, Homebrew ou binaire
- Lancer un scan et interpréter les résultats
- Filtrer l’analyse par namespace ou type de ressource
- Personnaliser les règles avec spinach.yaml
- Intégrer dans une CI/CD avec seuil de score minimal
Pourquoi auditer son cluster avec Popeye
Section intitulée « Pourquoi auditer son cluster avec Popeye »Kubernetes accepte de déployer des manifestes même s’ils violent les bonnes pratiques. Un Deployment sans limites de ressources ? Accepté. Une image nginx:latest ? Déployée. Un pod qui tourne en root ? Aucune erreur.
Ces configurations fonctionnent… jusqu’au jour où :
- Un pod consomme toute la mémoire du node et fait crasher les autres
- Une mise à jour automatique de
latestcasse l’application - Une vulnérabilité exploite les privilèges root du conteneur
Popeye détecte ces problèmes avant qu’ils ne surviennent en analysant ce qui tourne réellement dans le cluster (pas les fichiers YAML sur disque).
| Ce que Popeye vérifie | Exemple de problème détecté |
|---|---|
| Images | Tag latest, image sans tag |
| Ressources | Pas de requests/limits CPU/mémoire |
| Probes | Pas de liveness/readiness probe |
| Sécurité | Container root, pas de NetworkPolicy |
| RBAC | ClusterRoles/Roles inutilisés |
| Ressources orphelines | ConfigMaps, Secrets non référencés |
Installation
Section intitulée « Installation »Avec mise (recommandé)
Section intitulée « Avec mise (recommandé) »mise install popeye@latestmise use popeye@latestAvec Homebrew
Section intitulée « Avec Homebrew »brew install derailed/popeye/popeyeBinaire précompilé
Section intitulée « Binaire précompilé »# Télécharger depuis GitHubcurl -LO https://github.com/derailed/popeye/releases/download/v0.22.1/popeye_linux_amd64.tar.gztar -xzf popeye_linux_amd64.tar.gzsudo mv popeye /usr/local/bin/Vérification :
popeye versionVersion: 0.22.1Commit: 35b554961dcdabfa7aba6bd070673c6c24c70884Date: 2025-01-28T15:31:22ZPremier scan
Section intitulée « Premier scan »Popeye utilise votre kubeconfig actif (comme kubectl). Lancez un scan complet :
popeyeRésultat sur un cluster Kind fraîchement créé :
GENERAL [KIND-POPEYE-TEST]┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ · Connectivity.............................✅ · MetricServer.............................💥
CLUSTER (1 SCANNED) 💥 0 😱 0 🔊 0 ✅ 1 100٪┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ · Version..................................✅ ✅ [POP-406] K8s version OK.
DEPLOYMENTS (2 SCANNED) 💥 0 😱 1 🔊 1 ✅ 0 50٪┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ · demo/nginx-bad...........................😱 🐳 nginx 😱 [POP-101] Image tagged "latest" in use. 😱 [POP-106] No resources requests/limits defined. · demo/nginx-good..........................🔊 🐳 nginx 🔊 [POP-108] Unnamed port 8080.
SUMMARY┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅Your cluster score: A (91)Comprendre le rapport
Section intitulée « Comprendre le rapport »Niveaux de sévérité
Section intitulée « Niveaux de sévérité »| Icône | Niveau | Signification | Action |
|---|---|---|---|
| ✅ | OK | Ressource conforme | Rien à faire |
| 🔊 | Info | Recommandation | Amélioration optionnelle |
| 😱 | Warn | Problème potentiel | À corriger |
| 💥 | Error | Problème critique | Action immédiate requise |
Codes d’erreur courants
Section intitulée « Codes d’erreur courants »| Code | Message | Explication | Solution |
|---|---|---|---|
| POP-101 | Image tagged “latest” | L’image peut changer sans préavis | Spécifier une version : nginx:1.27.0 |
| POP-102 | No probes defined | Kubernetes ne sait pas si l’app est saine | Ajouter liveness/readiness probes |
| POP-106 | No resources requests/limits | Le pod peut consommer toutes les ressources | Définir requests et limits |
| POP-107 | No resource limits | Limits absentes (requests présentes) | Ajouter limits CPU/memory |
| POP-300 | Uses “default” ServiceAccount | Risque de permissions excessives | Créer un ServiceAccount dédié |
| POP-302 | Pod running as root | Risque de sécurité | Ajouter runAsNonRoot: true |
| POP-400 | Unable to locate reference | ConfigMap/Secret inutilisé | Supprimer ou utiliser la ressource |
| POP-1204 | Not secured by NetworkPolicy | Trafic non filtré | Ajouter une NetworkPolicy |
Calcul du score
Section intitulée « Calcul du score »Le score (0-100) est calculé par type de ressource, puis agrégé. Chaque problème réduit le score selon sa sévérité :
- Error : forte pénalité
- Warn : pénalité moyenne
- Info : faible impact
Un cluster de production devrait viser 80+ (note B minimum).
| Score | Note | Interprétation |
|---|---|---|
| 90-100 | A | Excellent, peu de corrections |
| 80-89 | B | Bon, quelques améliorations |
| 70-79 | C | Acceptable, corrections recommandées |
| 60-69 | D | Insuffisant, action requise |
| 0-59 | F | Critique, problèmes majeurs |
Filtrer l’analyse
Section intitulée « Filtrer l’analyse »Par namespace
Section intitulée « Par namespace »# Un seul namespacepopeye -n demo
# Tous les namespacespopeye -APar type de ressource
Section intitulée « Par type de ressource »Utilisez l’option -s (sections) avec les alias de ressources :
# Pods et Deployments uniquementpopeye -n demo -s po,deploy| Ressource | Alias |
|---|---|
| Pod | po |
| Deployment | dp, deploy |
| Service | svc |
| ConfigMap | cm |
| Secret | sec |
| ServiceAccount | sa |
| Ingress | ing |
| StatefulSet | sts |
| DaemonSet | ds |
| Job | job |
| CronJob | cj |
| PersistentVolumeClaim | pvc |
| NetworkPolicy | np |
| HorizontalPodAutoscaler | hpa |
Par niveau de sévérité
Section intitulée « Par niveau de sévérité »Afficher uniquement les problèmes warn et plus :
popeye -l warnValeurs possibles : ok, info, warn, error
Formats de sortie
Section intitulée « Formats de sortie »Console (défaut)
Section intitulée « Console (défaut) »popeyeJSON (pour traitement automatisé)
Section intitulée « JSON (pour traitement automatisé) »popeye -o json > rapport.jsonHTML (pour partage)
Section intitulée « HTML (pour partage) »POPEYE_REPORT_DIR=\$(pwd) popeye --save --out html --output-file rapport.htmlScore seul (pour CI/CD)
Section intitulée « Score seul (pour CI/CD) »popeye -o score# Retourne uniquement le chiffre, ex: 91Autres formats
Section intitulée « Autres formats »yaml: rapport YAMLjunit: format JUnit pour intégration CIjurassic: texte sans couleurs ni icônesprometheus: métriques Prometheus
Personnaliser les règles avec spinach.yaml
Section intitulée « Personnaliser les règles avec spinach.yaml »Créez un fichier spinach.yaml pour adapter les règles à votre contexte :
# Configuration Popeyepopeye: # Seuils d'utilisation des ressources allocations: cpu: underPercUtilization: 200 # Alerte si CPU sous-utilisé > 200% overPercUtilization: 50 # Alerte si CPU sur-utilisé > 50% memory: underPercUtilization: 200 overPercUtilization: 50
# Exclusions excludes: # Exclusions globales (tous les linters) global: fqns: [rx:^kube-] # Ignorer kube-system, kube-public... codes: ["300"] # Ignorer le code POP-300
# Exclusions par linter linters: pods: instances: - fqns: [kube-system/coredns] codes: ["302"] # Ignorer "running as root" pour CoreDNS
namespaces: codes: ["100"] # Ignorer namespace inactif
# Seuils pour les pods resources: pod: restarts: 5 # Alerte si > 5 restarts limits: cpu: 80 memory: 75
# Registries autorisés (tout autre registre = erreur) registries: - docker.io - ghcr.io - quay.io - registry.k8s.io
# Modifier la sévérité d'un code overrides: - code: "206" # PodDisruptionBudget manquant severity: 1 # Réduire à Info (1=info, 2=warn, 3=error)Lancez Popeye avec ce fichier :
popeye -f spinach.yamlIntégration CI/CD
Section intitulée « Intégration CI/CD »GitHub Actions
Section intitulée « GitHub Actions »name: Kubernetes Lint
on: push: branches: [main] schedule: - cron: '0 6 * * *' # Tous les jours à 6h
jobs: popeye: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Setup kubeconfig run: | mkdir -p ~/.kube echo "\${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config
- name: Install Popeye run: | curl -LO https://github.com/derailed/popeye/releases/download/v0.22.1/popeye_linux_amd64.tar.gz tar -xzf popeye_linux_amd64.tar.gz sudo mv popeye /usr/local/bin/
- name: Run Popeye run: | popeye -A --min-score 80 -o json > popeye-report.json
- name: Upload Report uses: actions/upload-artifact@v4 with: name: popeye-report path: popeye-report.jsonL’option --min-score 80 fait échouer le job si le score est inférieur à 80.
GitLab CI
Section intitulée « GitLab CI »popeye: stage: validate image: quay.io/derailed/popeye:v0.22.1 script: - popeye -A --min-score 75 --force-exit-zero -o yaml rules: - if: \$CI_PIPELINE_SOURCE == "schedule"Exécution dans le cluster
Section intitulée « Exécution dans le cluster »Popeye peut tourner directement dans Kubernetes via un CronJob :
apiVersion: v1kind: Namespacemetadata: name: popeye---apiVersion: v1kind: ServiceAccountmetadata: name: popeye namespace: popeye---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: popeyerules: - apiGroups: [""] resources: [configmaps, endpoints, namespaces, nodes, persistentvolumes, persistentvolumeclaims, pods, secrets, serviceaccounts, services] verbs: [get, list] - apiGroups: [apps] resources: [daemonsets, deployments, statefulsets, replicasets] verbs: [get, list] - apiGroups: [networking.k8s.io] resources: [ingresses, networkpolicies] verbs: [get, list] - apiGroups: [autoscaling] resources: [horizontalpodautoscalers] verbs: [get, list] - apiGroups: [policy] resources: [poddisruptionbudgets] verbs: [get, list] - apiGroups: [rbac.authorization.k8s.io] resources: [clusterroles, clusterrolebindings, roles, rolebindings] verbs: [get, list] - apiGroups: [metrics.k8s.io] resources: [pods, nodes] verbs: [get, list]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: popeyesubjects: - kind: ServiceAccount name: popeye namespace: popeyeroleRef: kind: ClusterRole name: popeye apiGroup: rbac.authorization.k8s.io---apiVersion: batch/v1kind: CronJobmetadata: name: popeye namespace: popeyespec: schedule: "0 */6 * * *" # Toutes les 6 heures concurrencyPolicy: Forbid jobTemplate: spec: template: spec: serviceAccountName: popeye restartPolicy: Never containers: - name: popeye image: quay.io/derailed/popeye:v0.22.1 args: - -A - -o - yaml - --force-exit-zero resources: limits: cpu: 500m memory: 256Mikubectl apply -f popeye-cronjob.yamlBonnes pratiques
Section intitulée « Bonnes pratiques »Exécuter régulièrement
Section intitulée « Exécuter régulièrement »Planifiez un scan quotidien ou après chaque déploiement majeur. Les problèmes s’accumulent vite.
Commencer par un namespace
Section intitulée « Commencer par un namespace »Sur un grand cluster, analysez d’abord un namespace critique :
popeye -n production -l warnDocumenter les exclusions
Section intitulée « Documenter les exclusions »Si vous excluez des règles dans spinach.yaml, documentez pourquoi :
excludes: linters: pods: instances: # CoreDNS tourne en root par design (upstream) # Voir: https://github.com/coredns/coredns/issues/... - fqns: [kube-system/coredns] codes: ["302"]Surveiller le score dans le temps
Section intitulée « Surveiller le score dans le temps »Exportez les rapports JSON et suivez l’évolution du score. Un score qui baisse indique une dette technique croissante.
Dépannage
Section intitulée « Dépannage »| Problème | Cause probable | Solution |
|---|---|---|
MetricServer 💥 | metrics-server non installé | Installer metrics-server ou ignorer |
| Timeout sur grand cluster | Trop de ressources à scanner | Filtrer par namespace -n |
| Permissions insuffisantes | RBAC manquant | Vérifier les droits get/list |
| Score très bas sur kube-system | Composants système non optimisés | Exclure via spinach.yaml |
À retenir
Section intitulée « À retenir »- Popeye analyse le cluster en temps réel (pas les fichiers YAML)
- Le score de 0 à 100 donne une vue d’ensemble rapide
- Les codes POP-xxx identifient précisément chaque problème
- spinach.yaml permet d’adapter les règles à votre contexte
- Intégrez dans la CI/CD avec
--min-scorepour bloquer les régressions - Popeye est en lecture seule : il ne modifie jamais vos ressources