# Home Services This repository manages home-lab services through two delivery paths: existing host Compose stacks and a Talos Kubernetes cluster reconciled by Argo CD. ## Repository layout ```text compose-services/ media_nas1/ compose.yaml media_rhel1/ compose.yaml terraform/ bootstrap/applicationsets/ infrastructure/ services/ vaultwarden/ composectl.py update_containers.sh .gitea/ workflows/ deploy.yaml ``` - `compose-services/` contains host-specific Compose stacks managed by Gitea Actions. - `infrastructure/` and `services/` contain Helm charts discovered by Argo CD ApplicationSets. - `terraform/` bootstraps Talos and installs the Argo CD engine; it does not manage day-two workloads. - `composectl.py` infers Compose stack names and paths from `compose-services/`. - `update_containers.sh` is a compatibility shim that delegates to the Python tool. ## Runtime support The CLI detects and uses whichever runtime is available: - `docker compose ...` - `podman compose ...` This means the same service directories can be managed from either backend without changing the compose files. ## Common commands From the repository root: ```bash python3 composectl.py --help python3 composectl.py --dry-run --stack media_nas1 refresh python3 composectl.py --dry-run --stack media_rhel1 refresh python3 composectl.py --stack media_nas1 pull python3 composectl.py --stack media_rhel1 status ``` The shell entrypoint delegates to the Python tool: ```bash bash update_containers.sh --dry-run --stack media_rhel1 refresh ``` ## Refresh flow The refresh flow validates and updates one stack: 1. `compose config` 2. `pull` 3. `up -d --remove-orphans` 4. optionally `image prune -f` when `--prune` is supplied The `up` operation avoids an unnecessary `down`, reducing downtime during normal updates. ## GitOps bootstrap The Kubernetes path targets the two-node Talos cluster with control plane `10.0.0.99` and worker `10.0.0.246`. The endpoint, Kubernetes version, storage device, Cilium interface, and load-balancer address pool remain explicit inputs because they are site-specific. 1. Copy `terraform/terraform.tfvars.example` to a local `.tfvars` file and fill in the supported Kubernetes version and stable control-plane endpoint. 2. Run `terraform init`, `terraform fmt`, and `terraform validate` from `terraform/`. 3. Apply Terraform to generate Talos configuration, bootstrap the control plane, join the worker, and install Argo CD. 4. Supply the Gitea credential through Terraform variables or create the Argo CD repository Secret out-of-band. Never commit tokens or private keys. 5. Apply both manifests with `kubectl apply -f bootstrap/applicationsets/`. 6. Confirm Argo CD discovers `infrastructure/cilium`, `infrastructure/longhorn`, and `services/vaultwarden`. Talos uses its default CNI during bootstrap so Argo CD can start. Cilium is then reconciled as the first infrastructure application. Confirm the LAN interface and address pool before enabling production LoadBalancer services. Longhorn also requires a validated disk or mount on the storage node. ## Secrets SOPS with age is the intended secret boundary. The repository policy is in `.sops.yaml`; age private keys and plaintext secret files are ignored. Provision the age private key to the cluster through a protected bootstrap process, then commit only files matching the repository's encrypted-file policy. Vaultwarden expects an existing Secret named `vaultwarden-secrets`. ## Gitea Actions deployment The workflow in `.gitea/workflows/deploy.yaml` deploys each host-specific stack to its matching self-hosted runner: - runner label `nas1` deploys `media_nas1` with Docker - runner label `rhel1` deploys `media_rhel1` with Podman Install and register one persistent Gitea Actions runner on each server. The runner should use a dedicated service account and should only execute trusted changes from the protected `main` branch. Deployments run on: - pushes to `main` - manual workflow dispatch - the first Friday of each month at `03:00` using a fixed UTC-6 offset (`09:00 UTC`) The scheduled trigger evaluates every Friday and skips dates after the seventh day, leaving only the first Friday eligible. The host jobs always target their own stack; they do not use `--all`. To roll back, dispatch the workflow from a known-good commit or revert the change on `main` and redeploy.