Skip to content

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

  1. Azure CLI installed, logged in, with the containerapp extension
  2. Docker installed
  3. An Azure Container Registry, and a resource group for the app
  4. Docker logged in to the registry
Terminal window
# Install and log in
brew install azure-cli
az login
az extension add --name containerapp --upgrade
# Log Docker in to the registry
az acr login --name myregistry

Service Configuration

name: orders-api
type: azure-container-apps
project: my-resource-group # Azure resource group
region: eastus
registry_name: myregistry # ACR name without .azurecr.io
template: 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: true

The Dockerfile is _templates/go.dockerfile at the project root. See Build Configuration.

Required Fields

FieldDescription
nameContainer App name
projectAzure resource group name
regionAzure region, e.g. eastus. Currently not passed to az; see Current Limitations.
registry_nameACR name without the .azurecr.io suffix, e.g. myregistry
templateDockerfile 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.

FieldTypeDefaultDescription
container_app.environmentstring""Container Apps environment name
container_app.min_replicasint0Minimum replicas (0 for scale to zero)
container_app.max_replicasint10Maximum replicas
container_app.cpustring0.25CPU cores per replica, e.g. 0.25, 0.5, 1
container_app.memorystring0.5GiMemory per replica, e.g. 0.5Gi, 1Gi
container_app.ingress_portint8080Container port for ingress
container_app.ingress_externalbooltruetrue 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_vars and secrets are not passed to Azure. Top-level env_vars only reach docker build as a --build-arg; secrets are 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-url

    Pilum’s later deploys don’t send env vars, so they don’t remove values set this way.

  • Ingress flags are sent only when ingress_port is set. Without it, ingress_external has no effect and Pilum sends no --target-port or --ingress.

  • Recipe defaults are not applied. With no container_app block, the deploy is only az containerapp up --name --resource-group --image.

  • region is not passed to az. The app’s location comes from Azure CLI’s own behaviour for az containerapp up (for example, the resource group or environment).

  • No rollback. pilum rollback supports GCP targets only.

Deployment Steps

  1. build binary — Runs build.cmd in the service directory (skipped when cmd is empty)
  2. build docker image — docker build -f ./_templates/<template> from the project root
  3. publish to registry — docker push to ACR
  4. deploy to container app — az containerapp up, followed by az containerapp update when any scaling or resource key is set

Example Commands

Terminal window
# Build, push and deploy
pilum deploy orders-api --tag v1.2.0
# Preview the commands
pilum dry-run orders-api --tag v1.2.0
# Build and push only
pilum publish orders-api --tag v1.2.0
# Check the app and read its console logs
pilum status orders-api
pilum logs orders-api
pilum logs orders-api --follow

Generated Deploy Command

For the configuration above, pilum deploy orders-api --tag v1.2.0 runs:

Terminal window
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 required

Log Docker in to the registry, then retry:

Terminal window
az acr login --name myregistry

Image 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:

Terminal window
az containerapp registry set --name orders-api --resource-group my-resource-group \
--server myregistry.azurecr.io --identity system

App 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:

Terminal window
az extension add --name containerapp --upgrade

Next Steps