Bump almalinux9 image tags to 20260606 Reviewed-on: #188 Co-authored-by: Ben Vincent <ben@unkin.net> Co-committed-by: Ben Vincent <ben@unkin.net>
7.8 KiB
AGENTS.md
Project Overview
This is an ArgoCD GitOps repository that manages Kubernetes applications for the au-syd1 cluster using a Kustomize + Helm pattern. Applications are deployed via ArgoCD ApplicationSets that watch directory patterns in this repo.
The migration pattern for this repo is: Terragrunt/Terraform → ArgoCD (see migration.md for full guide).
Essential Commands
# Build and render manifests for a path (outputs to manifests/<path>/)
make build apps/overlays/au-syd1/<app-name>
make build clusters/au-syd1/bootstrap
# Validate all apps and clusters with kubeconform
make kubeconform
# Clean generated manifests
make clean
# Quick build + inspect without persisting output
kustomize build --enable-helm apps/overlays/au-syd1/<app-name>
# Check all resource kinds produced by an overlay
kustomize build --enable-helm apps/overlays/au-syd1/<app-name> | grep "^kind:" | sort | uniq -c
# Run pre-commit checks against all files
uvx pre-commit run --all-files
Directory Structure
argocd-apps/
├── argocd/
│ ├── applicationsets/ # ArgoCD ApplicationSet definitions (platform.yaml, storage.yaml)
│ └── projects/ # ArgoCD AppProject definitions (platform.yaml, storage.yaml)
├── apps/
│ ├── base/ # Base Kustomize resources per app (no cluster-specific config)
│ │ └── <app-name>/
│ │ ├── kustomization.yaml
│ │ ├── namespace.yaml
│ │ ├── vaultauth.yaml # (if Vault-managed secrets)
│ │ └── vaultstaticsecret.yaml
│ └── overlays/
│ └── au-syd1/ # Cluster-specific overlays
│ └── <app-name>/
│ ├── kustomization.yaml # references base + helmCharts
│ └── values.yaml # Helm values for this cluster
├── clusters/
│ └── au-syd1/
│ ├── apps/ # Entry point: references apps/base (ArgoCD app-of-apps)
│ └── bootstrap/ # ArgoCD install + initial Application manifest
├── ci/
│ ├── validate-apps.sh # kubeconform over apps/overlays/*/kustomization.yaml
│ ├── validate-clusters.sh # kubeconform over clusters/*/kustomization.yaml
│ └── validate-no-secrets.sh # pre-commit hook: blocks plain Kubernetes Secrets
└── sources/ # Reference sources (Terraform configs, upstream charts, etc.)
└── terraform-k8s/ # Original Terraform configs — reference when migrating
Adding a New Application
Follow these 10 steps (detailed in migration.md):
1. Create base resources
apps/base/<app-name>/
├── kustomization.yaml
├── namespace.yaml
├── vaultauth.yaml # if needed
└── vaultstaticsecret.yaml # if needed
2. Create cluster overlay
apps/overlays/au-syd1/<app-name>/
├── kustomization.yaml
└── values.yaml
Overlay kustomization.yaml pattern:
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../../base/<app-name>
helmCharts:
- name: <chart-name>
repo: <helm-repo-url>
version: "<version>"
releaseName: <release-name>
namespace: <namespace>
valuesFile: values.yaml
3. Register in ApplicationSet
Add a directory entry to argocd/applicationsets/platform.yaml (or storage.yaml for csi-* apps):
- path: apps/overlays/*/<app-name>
4. Update AppProject
In argocd/projects/platform.yaml (or storage.yaml):
- Add the Helm repo URL to
sourceRepos - Add the namespace to
destinations - Add any required cluster-scoped resource types to
clusterResourceWhitelist
5. Validate
kustomize build --enable-helm apps/overlays/au-syd1/<app-name>
make kubeconform
Secret Management
Plain Kubernetes Secret objects are blocked by the pre-commit hook. Use Vault Operator CRDs instead:
VaultAuth template
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: default
namespace: <namespace>
spec:
method: kubernetes
mount: k8s/au/syd1
vaultConnectionRef: vso-system/default
allowedNamespaces:
- <namespace>
kubernetes:
role: <role>
serviceAccount: <service-account>
audiences:
- vault
tokenExpirationSeconds: 600
VaultStaticSecret template
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: <secret-name>
namespace: <namespace>
spec:
vaultAuthRef: default
mount: kv
type: kv-v2
path: kubernetes/namespace/<namespace>/default/<secret-name>
refreshAfter: 5m
destination:
name: <k8s-secret-name>
create: true
overwrite: true
hmacSecretData: true
YAML Conventions
- 2-space indentation (enforced by yamllint)
- All files must end with a newline (
end-of-file-fixer) - No trailing whitespace
- YAML linting uses relaxed rules with
line-length: disable(long base64/URLs are fine) - yamllint ignores
chartdirectories (vendored Helm charts) ---document separator at top of every YAML file- Multiple documents in one file are allowed (e.g.,
vaultstaticsecret.yamloften contains multiple secrets)
Kubernetes Labels Pattern
Use standard app.kubernetes.io/* labels consistently:
labels:
app.kubernetes.io/component: <component>
app.kubernetes.io/instance: <release-name>
app.kubernetes.io/name: <app-name>
app.kubernetes.io/version: <version>
Resource Naming Conventions
Files in apps/base/<app-name>/ follow the pattern:
<kind>_<name>.yaml
Examples:
deployment_puppetserver-master.yamlcronjob_g10k-code.yamlconfigmap_puppetboard-config.yamlhorizontalpodautoscaler_puppetserver-compilers-autoscaler.yamlservice_puppet-headless.yaml
Helm Chart Vendoring
Some overlays vendor Helm charts locally under apps/overlays/au-syd1/<app-name>/charts/<chart-name>/. When a chart is vendored, the overlay's kustomization.yaml references the local path. When not vendored, it references the OCI or HTTP repo directly.
Current Kubernetes target version: 1.33.7 (used by kubeconform in CI).
Project Boundaries
| Project | ApplicationSet | App pattern |
|---|---|---|
platform |
argocd/applicationsets/platform.yaml |
Named apps (cert-manager, puppet, woodpecker, etc.) |
storage |
argocd/applicationsets/storage.yaml |
csi-* apps |
The clusters/au-syd1/apps/ entry-point is deployed as a standalone ArgoCD Application (not an ApplicationSet) called au-syd1-apps.
CI / Pre-commit Hooks
Runs on every PR via Woodpecker CI (.woodpecker/):
| Check | Tool | Trigger |
|---|---|---|
| YAML lint + general file checks | pre-commit (yamllint + pre-commit-hooks) |
PR |
| No plain Secrets | ci/validate-no-secrets.sh |
PR (staged files) |
| Kubernetes manifest validation | kubeconform via make kubeconform |
PR |
kubeconform skips: CustomResourceDefinition, GpuDevicePlugin (for apps validation).
Git Workflow
- Branch naming:
benvin/<app-name>(user prefix) - Never
git add .— add only relevant files explicitly - If pre-commit modifies files,
git add -uthengit commit --amend --no-edit - Use
git push --force-with-leaseafter amending
Security Policies
reloader.stakater.com/auto: "true"annotation triggers rolling restarts on ConfigMap/Secret changes- Security contexts follow least-privilege:
drop: [all]then add only required capabilities fsGroup: 999on pod security context for Puppet workloadsrunAsUser: 0is used only for init containers that need to set file permissions, then regular containers run as non-root