🧼 Popeye Install & Quick Reference

Popeye install and cheat sheet / survival guide

Video: Popeye Install & Quick Reference (DevOps video)
Prefer to watch? This short video runs this page's main commands in a real lab, with on-screen captions and no voiceover. Click to play, or watch it on YouTube.
popeye [flags]
popeye -n my-namespace

Popeye is a read-only scanner for Kubernetes clusters. It looks at what is actually
deployed and reports misconfigurations, risky settings and leftover clutter: missing
probes, images tagged "latest", pods without resource limits, unused ConfigMaps, services
that point at nothing, and more. It then gives your cluster a score from 0 to 100 and a
letter grade. Popeye never changes anything in the cluster. It only reads.
It comes from the same author as k9s (github.com/derailed/popeye).

Install

brew install derailed/popeye/popeye        # macOS and Linux (Homebrew)
go install github.com/derailed/popeye@latest   # from source (needs Go)
Or download a release binary from github.com/derailed/popeye/releases, unpack it,
and put it on your PATH:
tar -xzf popeye_Linux_x86_64.tar.gz
sudo mv popeye /usr/local/bin/
Run it as a container (no install):
docker run --rm -it -v $HOME/.kube:/root/.kube derailed/popeye popeye
(The image name and tag can change; check the project's README for the current one.)
Check it works:
popeye version
Popeye uses your kubeconfig, like kubectl, and can only see what your account may read.
Test the connection first: kubectl get nodes

Run your first scan

popeye                                     # scan the current context and namespace, all sections
popeye -A                                  # all namespaces (--all-namespaces)
popeye -n kube-system                      # one namespace
popeye --context prod-cluster              # a specific context
popeye --kubeconfig ~/.kube/other          # a specific kubeconfig
popeye --help                              # every option in your version
The scan takes seconds to a minute, then prints a report and a score.

Choose what to scan (sections)

popeye -s pods                             # only pods
popeye -s pods,deployments,services        # several sections (comma separated)
popeye -s nodes                            # cluster nodes: capacity, conditions, utilization
popeye -s namespaces
popeye -s pods -n default                  # a section in a namespace
Sections (linters) include: clusterroles, clusterrolebindings, configmaps, cronjobs, daemonsets,
deployments, horizontalpodautoscalers, ingresses, jobs, namespaces, networkpolicies, nodes,
persistentvolumes, persistentvolumeclaims, poddisruptionbudgets, pods, replicasets, roles,
rolebindings, secrets, serviceaccounts, services, statefulsets.
List what your version supports: popeye --help

Output formats

popeye -o standard                         # the default colorful report
popeye -o jurassic                         # plain text, no colors or emoji
popeye -o yaml
popeye -o json
popeye -o html                             # a web page report
popeye -o junit                            # for CI test dashboards
popeye -o score                            # just the score number
popeye -o prometheus                       # metrics format
popeye -o json --save                      # save the report to a file
popeye -o html --save --output-file report.html   # choose the file name
popeye -o json | jq '.popeye.score'        # pull a value out in a script

Filter by severity (lint level)

popeye -l ok                               # show everything, including passing checks
popeye -l info                             # informational and up
popeye -l warn                             # warnings and errors only
popeye -l error                            # errors only
Combine with a section: popeye -s pods -l warn

Read the report

GENERAL [POPEYE]
  ...
PODS (12 SCANNED)   💥 1   😱 3   🔊 2   ✅ 6   88%
  · default/nginx-7f4c...............................................😱
    🔊 [POP-206] No PodDisruptionBudget defined.
    😱 [POP-102] No probes defined.
    😱 [POP-106] No resources requests/limits defined.
  · default/api-5d9b................................................✅
SUMMARY
  Your cluster score: 88 -- B
Symbols and levels
✅  OK            Passed the check
🔊  Info          A suggestion worth reading
😱  Warning       Should be fixed
💥  Error         Needs attention now
The percent next to a section is its score. The final letter runs from A (best) down to F.
Each finding has a code like POP-102. The code tells you exactly which check fired.

Common findings and what to do

POP-100  Untagged image           Give the image an explicit tag
POP-101  Image tagged "latest"    Pin a version so deployments and rollbacks are repeatable
POP-102  No probes defined        Add liveness and readiness probes
POP-106  No resource requests/limits   Set requests and limits so one pod cannot starve the node
Unused ConfigMap / Secret / ServiceAccount   Delete it, or find why nothing references it
Service with no endpoints         The selector matches no pods, or the pods are not ready
Pod using the "default" ServiceAccount   Create a dedicated ServiceAccount with least privilege
Container running as root / allows privilege escalation   Set a securityContext
Pod uses far more or less CPU/memory than requested   Right-size the requests and limits
Node under pressure or near capacity      Add capacity or move workloads
PVC not bound / volume unused             Check the storage class, or clean it up
Missing NetworkPolicy             Add one if you need to restrict pod traffic
Missing PodDisruptionBudget       Add one for important replicated apps
Check the docs for the full code list. Codes and checks change between Popeye versions.

Resource usage checks

Popeye compares what pods request with what they actually use. That needs metrics-server
running in the cluster (kubectl top pods must work). Without it, utilization checks are skipped.

Configuration file (the "spinach" file)
Popeye's checks can be tuned. Save a file, for example spinach.yml, and pass it with -f:
popeye -f spinach.yml
popeye -f spinach.yml -A -o html --save
Example spinach.yml:
popeye:
  excludes:
    global:
      fqns:
        - rx:^kube-system/               # ignore everything in kube-system
    linters:
      pods:
        instances:
          - fqns:
              - rx:^default/legacy-      # ignore matching pods
            codes:
              - 102                      # ...only for this check
      configmaps:
        instances:
          - fqns:
              - rx:^default/ignore-me
Rules: fqns are "namespace/name" strings; the rx: prefix means regular expression.
Exclude things you have consciously accepted, so the report only shows what needs action.
Run popeye --help to see the exact config file option for your version, and read the
sample spinach file in the project's README for thresholds and node settings.

Use it in CI or on a schedule

popeye -A -o junit --save --output-file popeye.xml     # publish as a test report
popeye -A -o json --save --output-file popeye.json
popeye -A --min-score 80                               # exit with an error if the score is below 80
popeye -A --force-exit-zero                            # always exit 0 (report only, never fail the job)
A simple nightly job in your pipeline:
popeye -A -o html --save --output-file popeye-$(date +%F).html
It can also run inside the cluster as a CronJob, with a ServiceAccount that has read-only access
(get/list/watch on the resources it scans), and push results to S3 or Prometheus. Check the
project docs for the current manifests.

Practical one-liners

# The whole cluster, colorful report
popeye -A

# Only warnings and errors, so it is easy to read
popeye -A -l warn

# Just the pods in one namespace
popeye -s pods -n production

# Quick health number
popeye -A -o score

# Save an HTML report to share
popeye -A -o html --save --output-file cluster-report.html

# Compare two contexts
popeye --context staging -A -o score
popeye --context prod -A -o score

# List failing pods only (JSON + jq)
popeye -s pods -A -o json | jq '.popeye.sanitizers[].tally'

# Get a plain-text report with no colors for a log file
popeye -A -o jurassic > popeye.txt

# Check a namespace before and after a change
popeye -n app -o score

# Everything except system namespaces (use an exclude in the spinach file)
popeye -A -f spinach.yml

Popeye vs other tools

popeye         Finds bad configuration and clutter in a running cluster (read-only)
k9s            Live terminal dashboard; also has a :popeye view
kubectl        The exact, scriptable commands to inspect and change things
kube-score     Checks manifests (YAML files) BEFORE deployment
kubeconform    Validates manifests against the Kubernetes schemas
kube-bench     Checks nodes against the CIS Kubernetes security benchmark
kubescape / trivy   Security and vulnerability scanning
Used together: kube-score/kubeconform in CI, Popeye on the live cluster.

Common problems

"Unable to connect" / "connection refused"   Fix your kubeconfig or VPN. Test with kubectl get nodes
"Forbidden" / permission errors      Your account cannot read that resource (RBAC). Ask for read access
Empty report or few resources        Wrong namespace: add -A, or set -n
No CPU or memory checks              metrics-server is not installed or not working
Score seems too harsh                Exclude accepted findings in the spinach file, or lower the noise with -l warn
Results differ from a colleague      Different context, namespace, or Popeye version. Compare popeye version
Emoji look broken                    Use a UTF-8 terminal, or use -o jurassic for plain text
CI job always fails                  Popeye returns an error on problems. Use --force-exit-zero, or set a --min-score
Flag not recognized                  Options change between versions. Run popeye --help

Tips

    Run Popeye regularly (weekly or nightly) and watch the score trend, not just one number.

    Start with popeye -A -l warn. It hides the passing checks and shows what needs work.

    Fix the cheap wins first: missing probes, "latest" tags, and missing resource requests and limits.

    Use a spinach file to exclude things you accept, so the report stays useful.

    Popeye is read-only. It is safe to run against production, but it still needs read access to many resources.

    Pair it with kube-score in CI: kube-score checks manifests before deploy, Popeye checks what actually runs.

    Install metrics-server so the utilization checks work.

    Save HTML or JSON reports (--save) to compare before and after a cleanup.

    In k9s you can run :popeye for the same report inside the dashboard.

    Popeye's options and check codes change between versions. Run popeye --help and read the project README for your version.