Ordered steps to bring up the two clusters from this repo. Steps 1–2 and 6 are in-repo (commit them); the rest run against real clusters and need secret material you hold. Do not skip the pre-merge gate (step 5).
Clusters:
oci-lab— typecloud, bootstraps its own Cilium (CNI-none Talos).unraid-lab— typehomelab-kvm, no inline Cilium.
values/base/harbor.yaml uses harbor.wind-bearded.ts.net, the cluster's
Tailscale MagicDNS name. Update both the externalURL and ingress host together
if the tailnet domain changes.
unraid-lab (installs Argo CD + the layering ApplicationSet, which also covers
oci-lab); OCI gets a Cilium-only patch plus the argocd-manager service
account — no Argo CD on OCI:
mise run oci-lab:generate-manifests
mise run unraid:generate-manifests
git add omni/cluster-templates/patches/oci-lab-inline-manifests.yaml clusters/unraid-lab/omni/inline-manifests.yaml
git commit -m "chore: generate inline-manifests for deploy"Version pins live in omni/scripts/generate-manifests.sh (ARGOCD_VERSION,
CILIUM_VERSION) — override via env to bump.
Apply the Talos machine config with the generated patch through Omni.
unraid-lab: on first control-plane boot Talos applies the inline-manifests: Argo CD installs, then the seeded root Applications pull the rest of this repo:
argocd-apps— the layering ApplicationSet (chart-apps; unraid-lab AND oci-lab destinations).argocd-bootstrap— syncsbootstrap/(Tailscale operator).argocd-unraid-raw— syncsclusters/unraid-lab/apps/*/application.yaml(arc-runners, plus the oci-* lanes below).
oci-lab: first control-plane boot applies only Cilium + the
argocd-manager ServiceAccount/ClusterRole/Binding. There is no Argo CD on
oci-lab; unraid-lab's Argo reconciles it once registered (step 4b).
Apps stay Progressing until these exist. harbor-mirror-robot depends on
Harbor being up (step 7) — create it there, not here.
harbor-admin-password— nsharbor, keyHARBOR_ADMIN_PASSWORD.arc-gha-secret— nsarc-runners, the GitHub App credentials (github_app_id,github_app_installation_id,github_app_private_key).
Generate the App private key yourself; never commit any of these.
After the oci-lab cluster is up and reachable over the private path
(unraid-lab → tailnet → wrt-london → IPSec → vpn-subnet nodeIP:6443):
- Grab the kube CA + build the API URL from the oci-talos-cp-1 VPN-subnet IP
(
kubectl config view --rawon an admin kubeconfig, oromnictl cluster kubeconfig). - Mint a long-lived token for
argocd-manager(kube-system): create a Secret of typekubernetes.io/service-account-tokenannotatedkubernetes.io/service-account.name: argocd-manager, readtoken. - Store
server(thehttps://<ip>:6443URL),ca(base64 CA), andtokenin Bitwarden; put the entry's UUID intoclusters/unraid-lab/apps/oci-cluster-registration/manifests/external-secret.yaml(replaces the placeholder keys) and commit. - ESO materializes Secret
oci-lab-clusterin unraid's argocd ns; theargocd.argoproj.io/secret-type: clusterlabel registers the cluster. TheappsApplicationSet,oci-raw, andoci-bootstrapthen sync against it (they sit degraded until this step).
Never commit the token or CA; they travel only through Bitwarden.
For the remote OCI reconciliation path, the GitOps-owned argocd/omni-kubernetes-proxy
Service and its ProxyGroup egress manifest are a single transport unit. Keep
that owning egress manifest applied until Argo has a separately deployed,
verified replacement path; removing it first breaks Argo's DNS/reachability
path. Recovery order is: restore/reconcile the owner, verify proxy resolution
and the registered OCI cluster, then verify Application sync. Do not delete the
manifest as cleanup while OCI Applications still depend on this transport.
Do not merge #17 until both pass:
- unraid-lab: every Argo Application
Synced+Healthy(argocd app list), Harbor and arc-controller included. - OCI: re-sync is a no-op — the restructure must not churn a running
cluster.
argocd app diffshows no changes.
The layering ApplicationSet, validate.py, and the generate tooling land on
main together once the gate is green.
With Harbor reachable at its MagicDNS name:
- Create project
image-factory. - Create the push robot (Image Factory) and the mirror robot; store the mirror
robot creds as secret
harbor-mirror-robot(keysusername,password) in nsarc-runners— this is what step 4 deferred. - Wire OIDC (PocketID) per the image-factory-registry plan.
Detail: syscode-ai-internal-plans/projects/image-factory-registry/plans/2026-07-19-harbor-ghcr-mirror.md.
Apply the omni-on-unraid reconfig (points Image Factory at Harbor, drops the
GITHUB_TOKEN), confirm end-to-end, then revoke the GHCR PAT — last, only after
sign-off.
Detail: syscode-ai-internal-plans/projects/image-factory-registry/handoffs/2026-07-20-omni-image-factory-reconfig.md.
The provider token is secret zero. It must exist before External Secrets can
read any other Bitwarden value. The automatic path is
omni/scripts/apply-inline-manifests.sh unraid-lab --apply: it decrypts the
SOPS file from the sibling private homelab-secrets checkout, validates that it
is the expected external-secrets/bws-token Secret, and adds it to the same
Omni inline-manifest ConfigPatch as the Argo bootstrap. The decrypted value is
written only to a temporary file and the ConfigPatch is stored by Omni.
The default private-repository location is ../homelab-secrets relative to
this repository. Override it with HOMELAB_SECRETS_ROOT when the checkouts are
elsewhere. The encrypted source remains:
homelab-secrets/unraid-lab/bws-token.enc.yaml.
After the cluster starts, Argo installs ESO and the Bitwarden SDK server. ESO
then uses bws-token to create the remaining secrets, including the Argo
cluster-registration Secret and Tailscale OAuth Secret. Re-running the command
is safe because the ConfigPatch and Kubernetes Secret are applied
idempotently.
For recovery or verification only, the equivalent manual command is:
sops -d /path/to/homelab-secrets/unraid-lab/bws-token.enc.yaml | \
kubectl --context omni-unraid-lab -n external-secrets apply -f -Never commit the decrypted file or paste the token into a terminal transcript.
OCI runs the same vendored ESO chart and Bitwarden SDK-server plugin as
unraid-lab. Restore its existing machine-account token as
oci-pivot-system/bw-auth-token (key token) before ESO can reconcile the
bitwarden-oci ClusterSecretStore. The token is secret zero and stays outside
this repository; the OCI pivot compartment ID then arrives through its
ExternalSecret.
These actions repaired resources that were already stuck outside the intended GitOps reconciliation path. They must not be treated as regular deployment steps.
- Removed finalizers from
argocd/unraid-lab-arc-controller,argocd/arc-runner-scale-sets, andargocd/unraid-lab-arc-runners-containerafter deleting ARC from unraid-lab left their Argo deletion operations stuck. - Labeled OCI worker
ampere-vnic-2-960682withimp/enabled=trueto enrol one node for the Imp agent and runtime DaemonSets. This label must be moved into the OCI machine's declared configuration before rebuilding or replacing the node.