Add gitops-argo-cd agent skill
Consolidates the five cogarchhubgitops-* source skills into one skill with scope routing: ArgoCD Applications, Copier templates, Helm values, environment answer files, and the end-to-end resource-addition walkthrough. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# ArgoCD Application Manifests
|
||||
|
||||
Everything under `cluster/argocd/`: the root app-of-apps, numbered child applications, sync
|
||||
policies, finalizers, and destinations.
|
||||
|
||||
Read this when creating a child `Application`, changing sync behaviour, moving a destination
|
||||
namespace, or debugging an app that will not sync.
|
||||
|
||||
---
|
||||
|
||||
## 1. Template anatomy
|
||||
|
||||
Every `cluster/argocd/**/application.yaml.jinja` follows this shape:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: <NNN-name>
|
||||
namespace: openshift-gitops
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: {{ gitops.repo_url }}
|
||||
targetRevision: {{ gitops.branch }}
|
||||
path: cluster/resources/<NNN-name>
|
||||
helm:
|
||||
valueFiles:
|
||||
- values.yaml
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: <target-namespace>
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
| Field | Rule |
|
||||
|---|---|
|
||||
| `metadata.name` | Exactly equal to the parent directory name (`210-eso-operator-group`) |
|
||||
| `metadata.namespace` | Always the ArgoCD install namespace — `openshift-gitops` on OpenShift GitOps |
|
||||
| `metadata.finalizers` | Must include `resources-finalizer.argocd.argoproj.io` |
|
||||
| `spec.project` | `default` unless the cluster defines scoped AppProjects |
|
||||
| `spec.source.repoURL` | Always `{{ gitops.repo_url }}` — never a literal URL |
|
||||
| `spec.source.targetRevision` | Always `{{ gitops.branch }}` — never a literal branch |
|
||||
| `spec.source.path` | Exactly the mirrored `cluster/resources/` path |
|
||||
| `spec.source.helm.valueFiles` | Usually `values.yaml`, the rendered `values.yaml.jinja` |
|
||||
| `spec.destination.server` | `https://kubernetes.default.svc` for in-cluster |
|
||||
| `spec.destination.namespace` | The workload's target namespace |
|
||||
|
||||
Note the asymmetry in `spec.source.path`: the **path value** is the plain rendered directory
|
||||
name (`cluster/resources/210-eso-operator-group`), while the **directory on disk** is the
|
||||
Jinja2 conditional expression. Copier renders the expression away, so the two agree in the
|
||||
output — but only if the literal you type in `path` matches what the expression evaluates to.
|
||||
|
||||
---
|
||||
|
||||
## 2. Sync policy rules
|
||||
|
||||
- `automated.prune: true` — removes resources no longer present in Git. Required; without it
|
||||
a disabled feature flag leaves its resources running in the cluster forever.
|
||||
- `automated.selfHeal: true` — reverts manual cluster changes. Required; disabling it means
|
||||
`kubectl edit` silently wins over Git, which defeats the whole contract.
|
||||
- Any exception to either must be justified in a YAML comment directly above `syncPolicy`.
|
||||
- `syncOptions: [CreateNamespace=true]` — set for any app whose destination namespace is not
|
||||
guaranteed to pre-exist. Harmless when the namespace already exists.
|
||||
- Retry settings are optional; add `syncPolicy.retry` only for apps with known flaky
|
||||
dependencies, and document the reason.
|
||||
|
||||
---
|
||||
|
||||
## 3. Naming rules
|
||||
|
||||
- Three-digit prefix from the correct band (see `SKILL.md` §4), next free number.
|
||||
- Descriptive part in lowercase kebab-case: `210-eso-operator-group`.
|
||||
- `metadata.name` == directory name == the value inside the conditional expression.
|
||||
- Wrap the directory in `{{ 'NNN-name' if <feature_flag> }}` — no exceptions; an
|
||||
unconditional directory renders in every environment whether or not it is wanted.
|
||||
|
||||
---
|
||||
|
||||
## 4. Adding a child application
|
||||
|
||||
1. Choose the band and the next free number in it.
|
||||
2. Create the conditional directory:
|
||||
|
||||
```text
|
||||
cluster/argocd/{{ '<NNN-name>' if <feature_flag> }}/application.yaml.jinja
|
||||
```
|
||||
|
||||
3. Create the mirror:
|
||||
|
||||
```text
|
||||
cluster/resources/{{ '<NNN-name>' if <feature_flag> }}/values.yaml.jinja
|
||||
```
|
||||
|
||||
4. Write the manifest from the anatomy in section 1.
|
||||
5. Declare `<feature_flag>` in `copier.yaml` with `type: bool`, `default: false`.
|
||||
6. Add the resource's configuration variables alongside the flag.
|
||||
7. Render and validate (`SKILL.md` §8).
|
||||
|
||||
No edit to the root `application.yaml.jinja` is needed — the app-of-apps discovers the new
|
||||
child automatically.
|
||||
|
||||
---
|
||||
|
||||
## 5. Troubleshooting
|
||||
|
||||
| Symptom | Likely cause |
|
||||
|---|---|
|
||||
| App missing entirely from ArgoCD | Feature flag false in that environment's answer file, or the conditional directory expression is malformed and evaluated falsy |
|
||||
| `path does not exist` / ComparisonError | `spec.source.path` does not match the rendered `cluster/resources/` directory, or the mirror directory's conditional expression differs from the argocd one |
|
||||
| Literal `{{ gitops.repo_url }}` in the live manifest | File was committed as `application.yaml` instead of `application.yaml.jinja`, so Copier copied it through unrendered |
|
||||
| Permanently `OutOfSync` after a manual cluster edit | `selfHeal` disabled — the cluster and Git disagree and nothing reconciles them |
|
||||
| Resources survive after deleting the app | Missing `resources-finalizer.argocd.argoproj.io` |
|
||||
| Resources vanish after a rename | Renaming a directory prunes the old app; expected — confirm the new app synced before assuming breakage |
|
||||
| Sync fails on namespace not found | Missing `CreateNamespace=true` in `syncOptions` |
|
||||
|
||||
Inspect the live state:
|
||||
|
||||
```bash
|
||||
argocd app list
|
||||
argocd app get <NNN-name>
|
||||
argocd app diff <NNN-name>
|
||||
kubectl -n openshift-gitops get applications.argoproj.io
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Mistakes to avoid
|
||||
|
||||
- Hardcoding `repoURL` or `targetRevision` instead of the Jinja2 variables.
|
||||
- Omitting the finalizer.
|
||||
- Creating the argocd side without the mirrored resources side.
|
||||
- Reusing a numeric prefix across domains (a `3xx` number for a database app).
|
||||
- Writing `application.yaml` without the `.jinja` extension.
|
||||
- Disabling `selfHeal` or `prune` silently.
|
||||
- Letting `metadata.name` drift from the directory name after a rename.
|
||||
Reference in New Issue
Block a user