Git, CI/CD & GitOpsLXXX · GitOps PruningGitOpsPruning
Incident — a prune deleted production — the recovery procedure
What you'll learn
- Trace a production prune incident from chart change to cluster deletion
- Diagnose the incident with kubectl, the controller, and the Git log
- Recover the deleted resource as a Git commit, not a kubectl apply
- Apply the post-incident prevention that closes the gap
Prerequisites
Practice
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
The incident begins with a chart typo and ends with a Git commit that restores the deleted resource. The chain — typo, merge, automated sync, deletion, consumer failure — is the canonical production prune failure. The recovery is canonical too: classify the deletion, restore the resource as a Git commit, let the next sync apply it. The GitOps promise is preserved because the recovery is itself a Git commit.
The incident timeline
flowchart LR
A["Typo in chart removes a manifest"] --> B["PR merged with single reviewer"]
B --> C["Automated sync triggers"]
C --> D["Controller deletes resource"]
D --> E["Consumer fails"]
E --> F["Alert fires"]
F --> G["On-call investigates"]
The timestamps tell the story:
- T0: a developer opens a PR that renames a ConfigMap from
payments-configtopayments-cfg. - T+12m: a reviewer approves. The PR is merged to
main. - T+13m: the automated sync runs. The diff between the previous
render and the new render contains a delete
(
payments-config) and a create (payments-cfg). - T+13m 4s: the controller executes both actions. The ConfigMap is gone from the cluster.
- T+14m: a downstream Deployment that mounts
payments-configfails its readiness probe. The pods restart in a crash loop. - T+18m: an alert fires on the readiness probe failure rate. The on-call engineer is paged.
The total elapsed time from PR merge to alert is six minutes. The total elapsed time from the deletion to consumer failure is less than ninety seconds.
The diagnostic steps
The on-call engineer’s first three commands:
argocd app manifests "$APP_NAME" | grep payments
kubectl get configmap -n "$NAMESPACE" payments-config
kubectl get configmap -n "$NAMESPACE" payments-cfg
The first command shows the controller’s view: only
payments-cfg is in the manifest. The second command shows the
cluster’s view: payments-config is gone. The third command shows
the new name exists. The diff is exactly the prune-and-create pair
the chart produced.
The second set of commands trace the deletion to a sync:
kubectl get events -n "$NAMESPACE" \
--field-selector involvedObject.name=payments-config
argocd app history "$APP_NAME"
The events show the delete action with the controller’s service account as the actor. The history shows the sync at T+13m, the revision it applied, and the diff it executed. The audit trail is intact: the Git commit, the PR, the reviewer, the sync, and the deletion are all visible.
The GitOps-native recovery
The recovery procedure:
- Restore the manifest as a Git commit. Add the missing
ConfigMap back to the chart. The contents can be the same as
the deleted version (recovered from the previous commit) or
the contents of the new
payments-cfgConfigMap (if a rename was the intent). - Push and let the sync apply the recreation. The next automated sync sees the manifest in the render, diffs against the cluster, and creates the resource. The audit trail records the recreation as a commit.
- Verify the consumer recovers. The Deployment’s readiness probe passes when the ConfigMap is mounted. The alert clears.
- Investigate why the rename reached production. A rename that touched a consumer’s mount path was a delete-and-create from the consumer’s point of view. The next lesson (the decision framework) is the prevention.
The recovery is auditable because every step is a Git operation. The recreation is reproducible because the Git commit is the source of truth.
The post-incident prevention
Three changes close the gap:
- Add a namespace backup before re-enabling prune. A Velero or equivalent backup is the recovery path for the next unintended delete.
- Require a second reviewer on any PR that removes a manifest. The deletion is destructive; the review is the prevention.
- Treat rename PRs as migration PRs. A two-step migration
- add the new resource, migrate the consumer, remove the old resource only after the consumer is updated - prevents the prune-driven deletion of a resource that is still in use.
Cross-course references
- Git, CI/CD & GitOps for Infrastructure Engineers - Part LXXX-04 (Prune safety mechanisms) is the procedure the incident reveals; Part LXIV (Deploy evidence) is the audit trail.
- Kubernetes for Production Sysadmins - Part XXI (Disaster Recovery) covers Velero and the namespace backup pattern; Part XXII (Postmortem) is the formal incident analysis.
Quiz
Knowledge check · 4 questions
Q1. An on-call engineer finds that a ConfigMap has been deleted by a prune-enabled sync. What is the correct first step?
Q2. A resource deleted by a prune incident can often be reconstructed from Git even when no namespace backup exists.
Q3. Name the three diagnostic commands the on-call engineer runs first to classify a prune incident, and what each tells them.
Q4. Walk through the timeline of a production prune incident and recommend the GitOps-native recovery.
A team runs an Application with prune enabled. A developer opens a PR that renames a ConfigMap from `payment-config` to `payments-config`. The PR is merged through a single reviewer. The next automated sync deletes `payment-config` and creates `payments-config`. A downstream Deployment mounts `payment-config` and crashes. The alert fires 90 seconds after the deletion. The team has no namespace backup. Walk through the timeline, the diagnosis, the GitOps-native recovery, and the post-incident prevention.
Passing score: 75%. Answers are checked in this browser.