Promote php-homepage 1.0.0-1-g7d1db6f
This commit is contained in:
@@ -1,141 +1,95 @@
|
||||
# Homelab GitOps
|
||||
|
||||
Argo CD is the only component that deploys the resources in this repository. Application CI publishes immutable
|
||||
container images and then commits the selected image tag here; it never receives Kubernetes credentials.
|
||||
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.
|
||||
|
||||
## Repository layout
|
||||
## Ownership boundary
|
||||
|
||||
- `apps/immich-sync/` is the desired Kubernetes state for Immich Share Sync.
|
||||
- `apps/immichframe/` wraps the reusable ImmichFrame chart with this cluster's
|
||||
hostname, album selection, resources, and encrypted API credential.
|
||||
- `apps/metallb/` pins the upstream native MetalLB installation and owns this
|
||||
cluster's L2 address pool.
|
||||
- `apps/argocd/` wraps the pinned upstream Argo CD chart with this cluster's
|
||||
ingress, Authentik OIDC, RBAC, and secret-reference configuration.
|
||||
- `apps/brgkepler-com/`, `apps/gschissenes-equipment/`,
|
||||
`apps/immich-crack/`, `apps/pfostendynamics-com/`, and
|
||||
`apps/watschn-studio/` pin the shared PHP homepage chart and reference their
|
||||
existing CephFS content claims.
|
||||
- `apps/brunner-ninja/`, `apps/flaresolverr/`, `apps/ombi/`,
|
||||
`apps/tautulli/`, `apps/uptime-kuma/`, and `apps/wiki-js/` pin their existing
|
||||
upstream chart releases and cluster values.
|
||||
- `apps/mosquitto/` and `apps/visual-studio-code/` preserve their small local
|
||||
manifest contracts; `apps/artcraft/` and `apps/coturn/` use local adapter
|
||||
charts for their repeated or multi-resource third-party integrations.
|
||||
- `bootstrap/` contains Argo CD projects and Applications, including the
|
||||
upstream Sealed Secrets controller and the five PHP sites above.
|
||||
- `scripts/update-immich-sync-image.sh` is the single image-promotion interface used by CI.
|
||||
- `scripts/update-immichframe-chart.sh` is the chart-promotion interface used
|
||||
by ImmichFrame chart CI.
|
||||
- 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.
|
||||
|
||||
The only canonical Immich Share Sync image version is `images[0].newTag` in
|
||||
`apps/immich-sync/kustomization.yaml`. The resource manifest deliberately omits a tag, and Kustomize supplies the
|
||||
immutable full Git SHA while rendering.
|
||||
See [docs/chart-ownership.md](docs/chart-ownership.md) for the complete chart versioning and promotion contract.
|
||||
|
||||
The only canonical ImmichFrame chart version is the `immichframe` dependency
|
||||
in `apps/immichframe/Chart.yaml`. Chart CI publishes a unique immutable version
|
||||
and commits that dependency update here. The chart owns the reusable workload
|
||||
shape; `apps/immichframe/values.yaml` owns only this cluster's choices.
|
||||
## Layout
|
||||
|
||||
## First-time setup
|
||||
- `bootstrap/` contains AppProjects and Applications.
|
||||
- `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.
|
||||
|
||||
The cluster already runs Argo CD in the `argocd` namespace and exposes its UI at <https://cd.brunner.ninja>.
|
||||
## Version and promotion flow
|
||||
|
||||
Argo CD manages its own chart after bootstrap. If the controller does not
|
||||
exist, recover it first from the same canonical chart dependency and values,
|
||||
then recreate the AppProjects and Applications:
|
||||
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
|
||||
```
|
||||
|
||||
The recovery installer preserves `argocd-secret`, `argocd-oidc`,
|
||||
`argocd-notifications-secret`, and `argocd-redis`. Back up or provision those
|
||||
Secrets separately; none of their values belongs in this public repository.
|
||||
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`.
|
||||
|
||||
1. Push this repository so Argo CD can read its public HTTPS URL.
|
||||
2. Configure the `immich-sync` repository's cross-repository token as described below.
|
||||
3. Review the rendered workload:
|
||||
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 kustomize apps/immich-sync
|
||||
```
|
||||
```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'
|
||||
```
|
||||
|
||||
4. Record the existing persistent volume before the first synchronization:
|
||||
|
||||
```sh
|
||||
kubectl --namespace default get pvc immich-sync-stats \
|
||||
-o jsonpath='{.metadata.uid}{"|"}{.spec.volumeName}{"\n"}'
|
||||
```
|
||||
|
||||
5. Bootstrap the Argo CD resources:
|
||||
|
||||
```sh
|
||||
./bootstrap/install.sh
|
||||
```
|
||||
|
||||
6. Inspect the result in the UI or CLI:
|
||||
|
||||
```sh
|
||||
argocd app get immich-sync
|
||||
argocd app diff immich-sync
|
||||
kubectl --namespace default rollout status deployment/immich-sync
|
||||
kubectl --namespace default get deployment immich-sync \
|
||||
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
|
||||
```
|
||||
|
||||
7. Confirm that the PVC UID and volume name are unchanged. Only after Argo CD reports the application `Synced` and
|
||||
`Healthy`, remove the obsolete CI deployer and delete the old `KUBE_CONFIG_BASE64` secret from Gitea:
|
||||
|
||||
```sh
|
||||
kubectl --namespace default delete rolebinding/immich-sync-deployer \
|
||||
role/immich-sync-deployer serviceaccount/immich-sync-deployer \
|
||||
secret/immich-sync-deployer-token
|
||||
```
|
||||
|
||||
The bootstrap Application enables automatic synchronization, pruning, and self-healing. Consequently, direct edits
|
||||
to its managed Kubernetes resources are reverted to Git. Change Git when experimenting, observe `OutOfSync`, and then
|
||||
watch Argo CD return the application to `Synced` and `Healthy`.
|
||||
|
||||
## Give Immich Share Sync CI permission to promote images
|
||||
|
||||
The built-in Gitea Actions job token cannot write to another repository. Create a dedicated bot account, for example
|
||||
`gitops-promoter`, add it to `feedc0de/homelab-gitops` with repository **Write** permission, and create a personal
|
||||
access token for that account with only the `write:repository` scope.
|
||||
|
||||
In `feedc0de/immich-sync`, open **Settings → Actions → Secrets** and create `GITOPS_TOKEN` containing that token. The
|
||||
workflow passes it directly to `actions/checkout` while checking out this repository; the checkout action configures
|
||||
authenticated HTTPS for the final `git push` without placing the token in a committed URL.
|
||||
|
||||
The main-branch workflow now performs this sequence:
|
||||
|
||||
1. Build and push `registry.brunner.ninja/feedc0de/immich-sync:<source SHA>`.
|
||||
2. Verify that the completed build still belongs to the current `main` commit.
|
||||
3. Update `apps/immich-sync/kustomization.yaml` with that SHA.
|
||||
4. Commit and push the promotion to this repository.
|
||||
5. Let Argo CD detect and synchronize the Git commit.
|
||||
|
||||
For a personal token owned by `feedc0de`, `write:repository` also applies to other repositories that account can
|
||||
write. A dedicated bot restricted to this one repository therefore gives the token a meaningfully smaller blast
|
||||
radius.
|
||||
|
||||
## Manual recovery path
|
||||
|
||||
Argo CD is the normal deployment mechanism. If it is unavailable, `apps/immich-sync/install.sh` renders, performs a
|
||||
server-side dry-run, applies the same Kustomize source, and waits for the Deployment rollout. A later Argo CD refresh
|
||||
will see the same desired resources.
|
||||
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 pinned in
|
||||
`bootstrap/sealed-secrets.yaml`. Public Git stores only `SealedSecret`
|
||||
ciphertext. The controller decrypts that ciphertext into namespace-scoped
|
||||
Kubernetes Secrets; the private sealing key never belongs in this repository.
|
||||
|
||||
Install the matching `kubeseal` client, then seal a Secret for its final name
|
||||
and namespace. The default strict scope prevents ciphertext from being moved to
|
||||
another name or namespace:
|
||||
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 \
|
||||
@@ -146,9 +100,3 @@ kubectl --namespace default create secret generic example \
|
||||
--controller-namespace sealed-secrets \
|
||||
--format yaml > example-sealed-secret.yaml
|
||||
```
|
||||
|
||||
The controller's generated private key is the disaster-recovery key for every
|
||||
sealed value. Back up the Secrets labelled
|
||||
`sealedsecrets.bitnami.com/sealed-secrets-key=active` from namespace
|
||||
`sealed-secrets` to an encrypted offline store. Do not commit that backup. A
|
||||
cluster rebuilt without one of those keys cannot decrypt existing ciphertext.
|
||||
|
||||
@@ -9,7 +9,10 @@ Each independently versioned application has one chart and one Argo CD
|
||||
Application. This includes each Artcraft application: WordCraft, GridCraft,
|
||||
DeckCraft, PhotoCraft, LightCraft, VectorCraft, FilmCraft, EffectCraft,
|
||||
DesignCraft, FigCraft, PdfCraft, SoundCraft, and CADCraft are separate releases,
|
||||
not one suite chart.
|
||||
not one suite chart. They share the `artcraft` namespace but do not share
|
||||
Kubernetes resource ownership. Their static upstream release bundles and nginx
|
||||
configuration are baked into distinct immutable images; pods never download
|
||||
application code at startup.
|
||||
|
||||
Maintained chart repositories set `Chart.yaml.appVersion` to the tested
|
||||
application/image version. CI derives the chart package version from Git:
|
||||
@@ -18,6 +21,9 @@ application/image version. CI derives the chart package version from Git:
|
||||
- the next commit produces a unique version such as
|
||||
`1.0.0-1-g41627abcdef`.
|
||||
|
||||
The shared chart repository uses per-chart tags such as
|
||||
`wordcraft-v1.0.0`; a single-chart repository uses `v1.0.0`.
|
||||
|
||||
The hash is retained to prevent package-version collisions. CI publishes to
|
||||
`https://brunner.ninja/charts`, then uses `GITOPS_TOKEN` to update only the
|
||||
matching Argo Application's exact Helm `targetRevision`. Argo CD performs the
|
||||
|
||||
Reference in New Issue
Block a user