Files

106 lines
5.0 KiB
Markdown

# Homelab GitOps
Argo CD is the only component that deploys resources from this repository. Application repositories publish
immutable images and/or Helm charts, then commit the exact chart version selected by the corresponding Argo
`Application`. CI never receives Kubernetes credentials.
## Ownership boundary
- An application repository owns its image, reusable Kubernetes behavior, probes, services, ingress capability,
persistence capability, monitoring capability, tests, and Helm chart.
- This repository owns only Argo Applications, exact chart selections, cluster values such as domains, addresses,
storage classes and sizes, existing PVC names, resource sizing, and sealed credentials.
- A maintained chart records the upstream or custom application release in `appVersion`.
- One independently releasable workload has one chart and one Argo Application. The 13 Artcraft applications are
separate charts and Applications but all target the shared `artcraft` namespace.
- Upstream charts are referenced directly. GitOps-local dependency wrappers are forbidden.
- Secrets are either references to existing Secrets or `SealedSecret` ciphertext. Plaintext never belongs here.
See [docs/chart-ownership.md](docs/chart-ownership.md) for the complete chart versioning and promotion contract.
## Layout
- `bootstrap/` contains AppProjects and Applications.
- `root-application.yaml` is the app-of-apps entry point that continuously
reconciles `bootstrap/`; this is what makes CI commits to Application
`targetRevision` fields take effect without kubectl.
- `apps/<name>/values.yaml` contains only this cluster's values for that chart.
- `apps/<name>/resources/` is allowed only for genuinely cluster-owned resources, such as a MetalLB address pool or
an ImmichFrame `SealedSecret`.
- `scripts/update-chart-version.sh` is the common CI promotion interface.
## Version and promotion flow
Maintained chart repositories tag releases with `vMAJOR.MINOR.PATCH` (or `<chart>-vMAJOR.MINOR.PATCH` in the shared
chart repository). `git describe --tags --long` is canonical:
- tag `v1.0.0` packages chart `1.0.0`;
- the next commit packages `1.0.0-1-g41627ab`;
- the Git hash is retained to prevent two histories from producing the same immutable package version;
- dirty trees are rejected.
After publishing succeeds, CI checks out this repository with `GITOPS_TOKEN`, runs:
```sh
./scripts/update-chart-version.sh APPLICATION CHART_VERSION
```
and commits `bootstrap/APPLICATION.yaml`. Argo CD observes that Git commit, renders the published chart with the
cluster values, and reconciles Kubernetes.
Upstream chart upgrades have no repository under our control, so their exact `targetRevision` is updated here
manually or by a dependency updater. They do not need a fake promotion repository.
## Gitea credentials
Prefer owner- or organization-level Actions secrets so every maintained chart repository receives the same narrowly
scoped credentials:
- `PACKAGE_USERNAME` and `PACKAGE_TOKEN`: upload-only credentials for the `feedc0de` Helm package repository;
- `GITOPS_TOKEN`: a token with `write:repository` access to only `feedc0de/homelab-gitops`;
- `QUAY_USERNAME` and `QUAY_TOKEN`: required only by repositories that publish container images.
The workflow commits as the normal `feedc0de` Git identity. The token determines authorization; the commit name is
not a separate Gitea account. A dedicated promoter account is still preferable if a one-repository permission scope
is desired.
## Bootstrap and recovery
The expected kubectl context is `kubernetes-admin@kubernetes`.
```sh
./bootstrap/install-argocd.sh
./bootstrap/install.sh
```
Argo CD manages its own upstream chart after recovery. The repo-server is given cluster-local host aliases for
`code.brunner.ninja` and `brunner.ninja`, routed through the Traefik ClusterIP, because this cluster cannot hairpin to
the public WAN address. The canonical alias configuration is in `apps/argocd/values.yaml`.
Before adopting a stateful workload, record its PVC UID and volume, render and dry-run the new chart, then verify the
same values after synchronization:
```sh
kubectl get pvc -A -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,UID:.metadata.uid,VOLUME:.spec.volumeName'
kubectl --namespace argocd get applications \
-o custom-columns='NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status'
```
Automatic sync, pruning, and self-healing mean direct live edits are temporary. Change Git and observe Argo return
the Application to `Synced` and `Healthy`.
## Sealed Secrets
Argo CD installs the official Sealed Secrets chart. Public Git stores only `SealedSecret` ciphertext; the controller's
private sealing key must be backed up to encrypted offline storage and never committed.
```sh
kubectl --namespace default create secret generic example \
--from-literal=token='replace-me' \
--dry-run=client --output=yaml \
| kubeseal \
--controller-name sealed-secrets-controller \
--controller-namespace sealed-secrets \
--format yaml > example-sealed-secret.yaml
```