Production deployment via the Ansible/IaC repo; Iris builds and publishes only #104
Labels
No labels
area/ai
area/backend
area/frontend
area/infra
area/scheduler
area/wled
good-first-issue
priority/high
priority/low
priority/medium
type/bug
type/chore
type/ci-cd
type/docs
type/feature
type/qa
v1.0.0
v1.1.0
v1.2.0
v2.0.0
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Iris-WLED#104
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Deploy Iris to production the same way the rest of the fleet is deployed: this repo builds and publishes a container image; the Ansible/IaC repo deploys it. The container registry is the boundary between them.
There is currently no production deployment at all — only the dev host (10.1.1.14), which runs
:mainfromdocker-compose.registry.yml(#65).Split of responsibilities
Iris-WLED — builds and publishes, never deploys
main(ci.yml):main,:sha-<short>v*tag (release.yml):X.Y.Z,:X.Y,:latestAnsible/IaC repo (cloned at
/home/ryan/ansibleon the control node) — owns everything runtime.envand secrets:SESSION_SECRET,OIDC_CLIENT_SECRET,OIDC_*,AI_API_KEY,CALENDARIFIC_KEY,LATITUDE/LONGITUDE,WLED_HOSTdata/— SQLite DB anddata/backups/, which the 04:00daily_backupjob writes to (#57). This is the one piece whose loss is unrecoverable.OIDC_REDIRECT_URIthat must match itPutting the secrets in the IaC repo is a strict improvement on today: on the dev host they are hand-edited, which is how
LATITUDE/LONGITUDE/WLED_HOSTsat blank until 2026-08-31.Changes needed in this repo
Small — the build half is nearly done.
docs/setup.md§6 reframed: it currently reads as the deployment path. It should be dev-host / self-hoster guidance, with a note that production is deployed from the IaC repo.docker-compose.registry.yml— keep it, label it clearly as the dev/self-host path so nobody assumes it is what prod runs.git.rhoving.com/rbrooks/iris-wledrequires authentication. The dev host pulls fine, but it may simply already be logged in — if auth is required, prod needs a read-only pull token, distinct fromREGISTRY_TOKEN(which carrieswrite:package).Recommendations
Pin to an immutable tag — never
:latest.:latestmoves, so two Ansible runs with no change to the IaC repo can produce different running containers. That defeats the purpose of IaC and makes rollback guesswork.IRIS_TAGalready exists as the seam; prod should set:X.Y.Z(or a:sha-<short>/ digest), and a deploy becomes "change one variable, re-run the play."Health check the deploy. The container exposes
GET /api/v1/health, already used as a CI gate — the play should wait on it rather than assumingdocker compose up -dsucceeded.Back up before upgrading. Iris takes its own pre-bulk-op and daily backups, but an image rollback with a migrated DB is not automatically reversible. The play should snapshot
data/before pulling a new tag.Blocked on
#4 must actually work first. IaC would consume
:X.Y.Z, and onlyrelease.ymlproduces those tags — the workflow that has never run once. Proving the release pipeline is a prerequisite, not a parallel task. #3'slatest/version-tag criterion is the same dependency.Acceptance criteria
:X.Y.Zin the registry plus a Forgejo releasedata/persists across a redeploy, and backups survive/api/v1/healthbefore reporting successdocs/setup.mddistinguishes the dev/self-host path from productionRelated: #3, #4, #10, #65, #7.
The IaC repo is
Rhoving/iac-repo— note it's under theRhovingorg, notrbrooks. The issue body above refers to it by its control-node path (/home/ryan/ansible) because I couldn't reach the control node from here to read the remote; that path is where it's checked out, andRhoving/iac-repois the canonical name.One consequence worth recording, since it crosses a repo boundary: the deploy role lives in
Rhoving/iac-repo, so the acceptance criteria here split across two repos. The Iris-side items (docs, the registry-path labelling, confirming pull auth) can be done here; the role, secrets and volume management land there. If a matching issue is opened onRhoving/iac-repo, cross-linking it makes the trail readable from both ends — this issue is the Iris half.The three in-repo items are done in #139. Leaving this open — the substance is elsewhere and blocked.
Done
docs/setup.md§7 anddocker-compose.registry.ymlnow say plainly that they are the dev-host and self-hoster path, not the production runbook, with a pointer that production is deployed from the IaC repo and the registry is the boundary.The registry question is answered by asking it, not assuming:
No authentication is required. The 401 is the standard registry challenge, not a refusal — an anonymous client gets a token that grants
pull, because the repo is public. So prod needs no pull secret and no read-only token, which removes one secret from the IaC side entirely.docker loginis optional rather than the required step §7 presented it as.That holds only while the repository stays public. Written down beside the finding, with the transcript, so the next person re-checks rather than re-derives.
Not done, and why
Everything else is an Ansible/IaC repo change, and this issue is explicit that it's blocked:
So the remaining criteria — a tag producing
:X.Y.Zplus a Forgejo release, a role deploying to a prod host,data/surviving a redeploy, the play waiting on/api/v1/health, rollback as one variable — are all downstream of #4 and outside this repository. I could write an Ansible role speculatively, but it would consume tags that don't exist and couldn't be run, which is worse than not writing it.Suggested order: verify #4 by cutting a real tag and confirming
:X.Y.Zlands in the registry with a Forgejo release beside it. Everything here unblocks the moment that's true.Reopened — merging #139 auto-closed this, which it should not have. The PR said so explicitly ("Does not close it"), so Forgejo picked the reference up from somewhere else, probably the branch name
docs/104-deploy-boundaryor the(#104, partial)in the squash commit subject.Nothing has changed about the state: the three in-repo items are done, and everything that gives this issue its title — an IaC role deploying a pinned tag to a prod host, with its own secrets, a persistent
data/volume and a health-checked rollout — is still outstanding, still in the Ansible repo, and still blocked on #4.Worth remembering for the next partial: reference the issue in prose only, or Forgejo will close it out from under you.
No longer blocked — the "Blocked on #4" section in the body above is stale
That section says
release.yml"has never run once". It has. #4 was proven by av0.0.1-rc1dry run on 2026-09-01 and closed, and the realv1.0.0release has since exercised the parts the RC could not. Verified against the registry and the release API just now, not read off the workflow:I repeated the "blocked on #4" claim in an earlier comment here, taking it from this issue's body rather than checking. That was wrong, and it is the reason this note exists — the stale text has now misled at least once.
What that changes
:X.Y.Zexists today. An IaC role can pingit.rhoving.com/rbrooks/iris-wled:1.0.0immediately; there is nothing left to wait for on the build side. The recommendation in the body — pin an immutable tag, never:latest— is directly actionable, and:latestnow genuinely moves, so the warning is live rather than theoretical.No pull secret is needed. From #139: the registry issues an anonymous token granting
pullon this repository, and the manifest fetch returns 200. That removes a secret from the IaC side entirely, and holds as long as the repo stays public.Remaining work, unchanged in substance
Everything else is in the Ansible repo and is the real content of this issue:
.envand secrets managed there —SESSION_SECRET,OIDC_*,AI_API_KEY,CALENDARIFIC_KEY,LATITUDE/LONGITUDE,WLED_HOSTdata/, covering the SQLite DB anddata/backups/— the one piece whose loss is unrecoverableGET /api/v1/healthrather than assumingdocker compose up -dworkeddata/before pulling a new tag, since an image rollback across a migration is not automatically reversibleThe three in-repo items are done (#139). This stays open for the IaC half.
One choice worth making before writing the role: whether prod pins
1.0.0— which is what exists and is 23 issues behindmain— or waits for av1.1.0tag covering the milestone that just completed. Pinning1.0.0now and bumping later is the lower-risk order, and it exercises the role against a tag that is already known good.