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.
