CGOA — GitOps Certified Associate
Removed from Git, gone from the cluster?
In one line
What you removed from Git is an intent to delete; whether it is actually deleted depends on the automated prune policy, per-object protection rules, and approval.
Why this was needed
You cleaned up unused configuration files in the deployment repository. In the review it shows up as a single file deleted. But if that file defined a Namespace or a link to persistent data, a small difference in the review becomes a large deletion in production. Continuous reconciliation, the strength of GitOps, does not apply only to creation and modification. Deletion is also an action that matches the desired state. Conversely, if you keep every object that has disappeared from Git forever, unused resources pile up and it becomes hard to tell who is responsible. What you need is not to turn deletion off entirely but a criterion for deciding what to delete automatically and what to delete after review.
This lab does not use real data. It reproduces the lifecycle with a ConfigMap holding a short value, disposable-exercise. It is a choice to learn the same decision structure as production without creating the cost of data loss. You must not interpret it as having tested the preservation and restoration of a real PVC. Being able to apply the YAML of the same name again and being able to recover the data are different things.
How it works
First, separate three targets. A Git directory holds the desired state, an Application specifies which directory is applied to which cluster, and a ConfigMap is the actual object created as a result. Prune, which removes objects from a Git path, and the resource cleanup that follows when an Application itself is deleted are different events.
Turning on automated sync does not also turn on automated deletion. The Application's automated.prune decides the automation of deletion. This lab sets that value to true and compares per-object options. The key to the following table is not to compress the different status columns into the single word "success."
| Object removed from Git | Actual object | sync.status | operationState.phase |
|---|---|---|---|
| A normal object with no separate protection | Deleted | Synced | Succeeded |
| A retained object with Prune=false | Remains | OutOfSync | May be Succeeded |
| A confirmed object with Prune=confirm, before approval | Remains | OutOfSync | Running |
| The confirmed object, after approval | Deleted | Synced | Succeeded |
Prune=false makes the deletion operation be skipped. The deletion that Argo CD originally intended remains, so the desired state and the actual state differ. That does not mean the reconciler is broken. In this case PruneSkipped is left on the corresponding object in syncResult. After you work out why the protected object remains, if you restore its definition in Git, it can become Synced again with the same UID. If you manually delete the actual object to get rid of OutOfSync, you break the very purpose of the protection rule. This restoration makes Git match the actual object that was already left in place, so a new sync operation may not be needed. So you check the current sync.revision, Synced, and the same UID, and do not require the creation of a new operation as a success condition.
Prune=confirm holds back a deletion that needs review. Here Running does not mean an endless failure; it may be waiting for approval. You check the cause of the waiting in operationState.message and the list of resources scheduled for deletion. Approval can also be given by recording a time in the Application's argocd.argoproj.io/deletion-approved annotation. The important point is that the approval mark attaches to the Application, not to a single ConfigMap. If other deletion targets beyond what you reviewed have appeared together, the earlier judgment cannot be applied as is.
Delete=false has a similar name, but it is an option about cleanup when an Application is deleted. It is not another name for prune, which removes resources from Git. When writing operations documents, attach a subject after the word "deletion." Only when you first distinguish what was removed from Git, whether the Application is being deleted, or whether the actual object is being deleted directly, do you pick the right option.
What it looks like in the field
When a team transfers configuration ownership to another repository, if you first remove the previous Application's Git definition, automated prune may delete the objects first. Copying a single protection option does not complete the transfer design. You must also decide the scope of the previous and new owners, the period during which two reconcilers manage the same object at once, and which source you return to if it fails. The two Applications in this unit manage different ConfigMaps so as not to create that kind of dual ownership.
When reading evidence, look at the name and the UID together. Because Kubernetes can create a new object with the same name, you cannot judge it preserved just because the name is the same. Conversely, a change in the Git commit does not mean the object was newly created too. A habit that helps is leaving the coordinates of the actual state and the desired state side by side, like this.
git -C /srv/cgoa-prune-safety rev-parse HEAD
kubectl -n argocd get application cgoa-prune-safety -o json
kubectl -n cgoa-prune-safety get configmaps -o json
What you read here are the commit SHA, source.path, destination.namespace, sync.revision, the list scheduled for deletion, and the UIDs. Pasting the whole output into a report without being able to explain what each one means is no substitute for verification.
What you will do in the next lab
You create and confirm a normal deletion, a deletion retained, a Git restoration, and a wait for approval yourself. In the approval step, you write in your answer the Application UID and the target ConfigMap UID from the earlier observation. The helper stops if they differ from the current target. This restriction is a device to prevent mistakes during learning against a wrong scope, and it is not a security guarantee that blocks every action by the administrator root.
Official documentation
- Argo CD sync options: Compare the events to which Prune and Delete apply.
- Kubernetes object names and UIDs: Distinguish name reuse from object identity.