A Quiet Week of Dual-Target Deploys
Published:
A Quiet Week of Dual-Target Deploys
Not every productive week produces a demo you can fly through. This one was infrastructure: I took a batch of my private apps and gave them a second home on Azure Container Apps, alongside the VPS they already run on — dual-target, same image, two destinations. The interesting part was doing it without a single long-lived secret anywhere in the pipeline.
The pattern I converged on, repeated across every service:
build image ─▶ push ACR ─▶ deploy Container App (Bicep)
Container App ──(user-assigned managed identity + AcrPull)──▶ ACR # no admin creds
0.75 vCPU / 1.5 GiB · scale-to-zero · /healthz probe
Two things earn their keep here. OIDC federated identity means the CI job exchanges a short-lived GitHub token for an Azure one at run time — there is no client secret to leak or rotate. And the running container pulls its own image from the registry via a user-assigned managed identity with just the AcrPull role, so there are no registry admin credentials in the loop either. Bicep describes the whole thing declaratively; scale-to-zero keeps idle cost near nothing.
It was not all clean. I hit an RBAC propagation race (the deploy runs before the role assignment is visible, so it needs a retry), an ARM read-lag when fetching the live URL, and — embarrassingly — a version-bump script that opened a file for writing before reading it and truncated a pyproject.toml. Caught and restored, then noted so I never do it again. Secrets, of course, never live in these repos: they come from my private vault and are injected at deploy time as container-app secrets.
