Deploying on Azure¶
This page shows how to run a task on Azure Container Apps with one command. It is for anyone with an Azure subscription. Azure Container Apps is proven: the proving ground runs its workloads there and gets the same data as local Spark.
The problem: you want a task to run on Azure, on a schedule or on demand, with no Spark cluster to manage. When to use it: any task that fits on one machine. The job runs Spark in local mode inside one container. The command:
ubunye deploy container-apps -u shop -p orders -t clean \
--image myacr.azurecr.io/ubunye-jobs:1 -g my-rg --environment my-env \
--registry-server myacr.azurecr.io \
--registry-identity /subscriptions/<sub id>/resourceGroups/my-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/pull \
--record-out aca.json
Azure Container Apps runs containers for you. A Container Apps job is a container that runs to the end and stops, rather than a web app that stays up.
Before you start¶
- The Azure CLI, signed in:
az login. The command callsaz containerappandaz monitor log-analytics. Add the Container Apps extension once:az extension add --name containerapp. - Docker, to build the image.
-
In Azure:
You need Why a resource group ( -g)holds the job a Container Apps environment ( --environment) with a Log Analytics workspacethe job runs in it; its logs are where the run record is read back from a container registry, such as Azure Container Registry ( --registry-server)holds your image a user-assigned managed identity with the AcrPullrole on that registry (--registry-identity)lets the job pull the image with no password Your own sign-in needs rights to create and start Container Apps jobs in the resource group, and to query the Log Analytics workspace.
-
Where the data goes. The container's disk is gone when the job ends. Several tasks in one launch can share it (see Several tasks in one launch), but anything you want to keep must go to storage that outlives the container. Point your task's outputs there, for example with
--env.
1. Build and push the image¶
This target builds its image with the engine's own ubunye deploy dockerfile
(not the companion repo's Dockerfiles). Run it in the folder that holds your
pipelines/ folder:
ubunye deploy dockerfile container --pipelines pipelines --out Dockerfile
docker build -t myacr.azurecr.io/ubunye-jobs:1 .
az acr login -n myacr
docker push myacr.azurecr.io/ubunye-jobs:1
The first command prints [OK] wrote Dockerfile and ubunye_entry.py. The
image carries Java 17, Spark 3.5 in local mode, Delta, the engine and your
pipelines, copied to /app/pipelines. That is why container-apps takes no
-d: the pipelines are already inside. Rebuild and push the image when a task
changes.
2. Preview with --dry-run¶
ubunye deploy container-apps -u shop -p orders -t clean \
--image myacr.azurecr.io/ubunye-jobs:1 -g my-rg --environment my-env \
--registry-server myacr.azurecr.io \
--registry-identity /subscriptions/0000/resourceGroups/my-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/pull \
--dry-run
Real output, with the launcher script cut to ...:
{
"platform": "container-apps",
"job": "ubunye-clean",
"uploads": [],
"commands": [
[
"python",
"-c",
"...create or update the job, start it, wait, read the logs...",
"{\"job\": \"ubunye-clean\", \"resource_group\": \"my-rg\", \"environment\": \"my-env\", \"image\": \"myacr.azurecr.io/ubunye-jobs:1\", \"cpu\": \"2\", \"memory\": \"4Gi\", \"timeout\": 1800, \"registry_server\": \"myacr.azurecr.io\", \"registry_identity\": \"/subscriptions/0000/resourceGroups/my-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/pull\", \"env\": [\"UBUNYE_ENTRY_ARGS=[\\\"--task\\\", \\\"shop/orders/clean\\\", \\\"--mode\\\", \\\"PROD\\\"]\"], \"wait\": true}"
]
]
}
[DRY RUN] container-apps plan for 'ubunye-clean'. Nothing ran.
3. Run it¶
Drop --dry-run and add --record-out aca.json. The command:
- creates the job the first time (manual trigger, no retries, one replica), or updates its image, size and environment after that;
- starts one run and prints
execution <name>; - with
--wait(the default), prints the run state every 20 seconds until it ends; - reads the job's output from Log Analytics. Output reaches Log Analytics a few minutes after the job ends, so the command keeps asking for up to about 13 minutes, until the whole run record is there.
| Flag | Default | What it does |
|---|---|---|
--job |
from the task name | the Container Apps job name |
--cpu |
2 |
CPU for the replica |
--memory |
4Gi |
memory for the replica |
--timeout |
1800 |
seconds a replica may run, for all tasks together |
--no-wait |
start the run and return |
Plus the shared flags -m, -dt, --env, --var, --record-out and
--dry-run: see One command to the cloud and the
CLI reference.
What success looks like¶
The last lines name the task and each output, with its row count and data hash:
[OK] container-apps run success: shop/orders/clean
<output name>: <rows> rows, <data hash>
run record: aca.json
aca.json is a normal run record. Compare it with a local run, or another
cloud, to check the data is the same:
In the Azure portal the job is under your resource group, named
ubunye-clean; Execution history lists each run and links to its logs.
If the run fails, the line says [FAIL] and the command exits with a non-zero
code.
A rare first-create failure
Once, creating the job failed with "unable to pull image using Managed
identity", and the same command passed when run again. If you see it,
check the identity has AcrPull on the registry, then run the command
again.
Scheduling¶
ubunye deploy container-apps creates a job with a manual trigger: it runs
when this command (or someone in Azure) starts it. Running it again updates
the job and starts a new run. To run on a schedule, start the command from a
scheduler you already use, such as a CI workflow on a timer. The engine does
not set a schedule on the Azure job.