Azure Container Apps
The azure-container-apps recipe builds a Docker image, pushes it to Azure Container Registry (ACR), and deploys it to Azure Container Apps with az containerapp up.
Prerequisites
- Azure CLI installed, logged in, with the
containerappextension - Docker installed
- An Azure Container Registry, and a resource group for the app
- Docker logged in to the registry
# Install and log inbrew install azure-cliaz loginaz extension add --name containerapp --upgrade
# Log Docker in to the registryaz acr login --name myregistryService Configuration
name: orders-apitype: azure-container-appsproject: my-resource-group # Azure resource groupregion: eastusregistry_name: myregistry # ACR name without .azurecr.iotemplate: go.dockerfile
build: language: go cmd: "CGO_ENABLED=0 go build -o ./dist/app ."
container_app: environment: my-containerapps-env min_replicas: 0 max_replicas: 5 cpu: "0.5" memory: 1Gi ingress_port: 8080 ingress_external: trueThe Dockerfile is _templates/go.dockerfile at the project root. See Build Configuration.
Required Fields
| Field | Description |
|---|---|
name | Container App name |
project | Azure resource group name |
region | Azure region, e.g. eastus. Currently not passed to az; see Current Limitations. |
registry_name | ACR name without the .azurecr.io suffix, e.g. myregistry |
template | Dockerfile template name, relative to _templates/ |
Optional Fields
Container App Configuration
The Default column shows the recipe’s documented default. Pilum does not apply these defaults itself: a key you leave unset is not sent, so the app keeps its current value, or Azure’s default when it is created.
| Field | Type | Default | Description |
|---|---|---|---|
container_app.environment | string | "" | Container Apps environment name |
container_app.min_replicas | int | 0 | Minimum replicas (0 for scale to zero) |
container_app.max_replicas | int | 10 | Maximum replicas |
container_app.cpu | string | 0.25 | CPU cores per replica, e.g. 0.25, 0.5, 1 |
container_app.memory | string | 0.5Gi | Memory per replica, e.g. 0.5Gi, 1Gi |
container_app.ingress_port | int | 8080 | Container port for ingress |
container_app.ingress_external | bool | true | true for external ingress, false for internal. Only used when ingress_port is set. |
Registry Configuration
The image is pushed to:
<registry_name>.azurecr.io/<image_name or name>:<tag>The tag comes from --tag, then version: in pilum.yaml, then latest. A pasted full login server (myregistry.azurecr.io) also works, but the bare name is preferred.
Current Limitations
These reflect the current code. Check them against your needs before deploying production workloads with this recipe.
-
env_varsandsecretsare not passed to Azure. Top-levelenv_varsonly reachdocker buildas a--build-arg;secretsare ignored. Set them on the app yourself:Terminal window az containerapp secret set --name orders-api --resource-group my-resource-group \--secrets db-url=<value>az containerapp update --name orders-api --resource-group my-resource-group \--set-env-vars LOG_LEVEL=info DATABASE_URL=secretref:db-urlPilum’s later deploys don’t send env vars, so they don’t remove values set this way.
-
Ingress flags are sent only when
ingress_portis set. Without it,ingress_externalhas no effect and Pilum sends no--target-portor--ingress. -
Recipe defaults are not applied. With no
container_appblock, the deploy is onlyaz containerapp up --name --resource-group --image. -
regionis not passed toaz. The app’s location comes from Azure CLI’s own behaviour foraz containerapp up(for example, the resource group or environment). -
No rollback.
pilum rollbacksupports GCP targets only.
Deployment Steps
- build binary — Runs
build.cmdin the service directory (skipped whencmdis empty) - build docker image —
docker build -f ./_templates/<template>from the project root - publish to registry —
docker pushto ACR - deploy to container app —
az containerapp up, followed byaz containerapp updatewhen any scaling or resource key is set
Example Commands
# Build, push and deploypilum deploy orders-api --tag v1.2.0
# Preview the commandspilum dry-run orders-api --tag v1.2.0
# Build and push onlypilum publish orders-api --tag v1.2.0
# Check the app and read its console logspilum status orders-apipilum logs orders-apipilum logs orders-api --followGenerated Deploy Command
For the configuration above, pilum deploy orders-api --tag v1.2.0 runs:
az containerapp up --name 'orders-api' --resource-group 'my-resource-group' \ --image 'myregistry.azurecr.io/orders-api:v1.2.0' \ --environment 'my-containerapps-env' \ --target-port 8080 --ingress external \&& az containerapp update --name 'orders-api' --resource-group 'my-resource-group' \ --min-replicas=0 --max-replicas=5 --cpu '0.5' --memory '1Gi'pilum status runs az containerapp show --name <name> --resource-group <project> --output json, and pilum logs runs az containerapp logs show --name <name> --resource-group <project> --type console.
Troubleshooting
Push Unauthorized
unauthorized: authentication requiredLog Docker in to the registry, then retry:
az acr login --name myregistryImage Pull Fails in the Container App
The Container App needs permission to pull from ACR. Give the app a managed identity with the AcrPull role on the registry, or configure registry credentials:
az containerapp registry set --name orders-api --resource-group my-resource-group \ --server myregistry.azurecr.io --identity systemApp Has No Public URL
Ingress is configured only when container_app.ingress_port is set. Add it, with ingress_external: true for a public endpoint.
Environment Variables Missing at Runtime
env_vars and secrets in pilum.yaml are not sent to Azure. Set them with az containerapp update --set-env-vars and az containerapp secret set, as shown in Current Limitations.
containerapp Command Not Found
Install the Azure CLI extension:
az extension add --name containerapp --upgradeNext Steps
- Service Configuration — Full
pilum.yamlreference - Build Configuration — Host builds and Dockerfile templates
- Rollback and Status — Status and logs across providers
- Adding a Provider — Extend or customise recipes