deploy-agent-aca-dev
Skill12 starsChanged 7 months agoMITView on GitHub
AI-led deployment of the local-LLM sample agent (Ollama + Microsoft Entra Agent ID sidecar) to Azure Container Apps. Use when the user wants to deploy sidecar/dev to ACA, run the agent on Azure without AWS/GCP, host Ollama on Container Apps, promote the docker-compose local-dev stack from ClientSecret to SignedAssertionFromManagedIdentity (secretless), or debug AADSTS65001/AADSTS50011/ImagePullBackOff/Ollama OOM errors in this specific deployment. NOT for AWS Bedrock (use deploy-agent-aca-aws) and NOT for local docker-compose on a laptop (use sidecar/dev directly). Chains to entra-agent-id-setup for the Blueprint + Agent Identity + Client SPA objects.
In this repository7 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- n8n/.github/copilot-instructions.mdCopilot instructions
- deploy-agent-aca-awsSkill
- entra-agent-id-setupSkill
- teardown-agent-aca-awsSkill
- teardown-agent-aca-devSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 44
Before running any az command that provisions resources, confirm each SKU choice with the user.
- Very specific: line 62
Ask the user to confirm: tenant ID, subscription ID, resource group name, location, SKU choices (including OLLAMA_CPU / OLLAMA_MEMORY — …
- Very specific: line 112
No Docker Desktop needed. Works for llm-agent and weather-api only.
- Very specific: line 125
If OLLAMA_IMAGE_STRATEGY=baked (Option A only):
- Distinctive: line 169
If all prerequisites are in place and SKU variables are confirmed:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Deploy Local-LLM Agent to Azure Container Apps (AI-Led)
End-to-end, secretless deployment of sidecar/dev (Ollama + Entra Agent ID sidecar) to Azure Container Apps. One federation chain (MI → Entra Blueprint), no second cloud.
Canonical tutorial: sidecar/dev/deploy-local-llm-agent-sidecar-container-apps.md. This skill is the automated, fast-path counterpart.
When to Use
- User says: "deploy dev to ACA", "deploy the local LLM agent to Azure", "Ollama on Container Apps", "ship sidecar/dev to Azure"
- User wants a self-contained demo in a tenant where AWS/GCP aren't options (airgapped, regulated, customer-owned)
- User hits
AADSTS65001on OBO sign-in — see references/post-deploy-manual-steps.md - User hits
AADSTS50011: redirect URI mismatch— same reference - User hits Ollama
out of memoryorImagePullBackOff— see references/ollama-on-aca.md - User asks "can I run this without Bedrock / Vertex?"
Do NOT Use When
- AWS Bedrock deployment — use
deploy-agent-aca-aws - GCP Vertex AI deployment — pending skill
deploy-agent-aca-gcp - Local laptop docker-compose — use
sidecar/dev/directly withdocker compose up, no federation needed
Prerequisites (verify BEFORE running anything)
- Entra role on signing-in user — one of:
Global Administrator,Agent ID Administrator,Agent ID Developer. See entra-agent-id-setup. - Tooling:
az≥ 2.60,pwsh7.4+,Microsoft.Graph.*2.35+ (install:Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Beta.Applications -Scope CurrentUser), and one of:docker buildxforlinux/amd64ORaz acr build(no local Docker needed — see Step 4). - Tenant-confirmed preflight — ALWAYS confirm tenant ID + subscription ID with the user before any
azcommand that mutates resources. - Entra Agent ID base objects exist — Blueprint, Agent Identity, Client SPA. If not, run the entra-agent-id-setup skill first.
[!NOTE] Windows / PowerShell users: This skill's scripts and orchestrator are bash. If running from PowerShell without WSL or Git Bash:
source file→. fileor set$env:VARindividuallyenvsubst→ PowerShell-replaceoperators or(Get-Content template) -replace '\$\{VAR\}', $valuebash script.sh→ translate eachaz/pwshcommand into the PowerShell session directlydocker buildx build --push→az acr buildforllm-agentandweather-api(but not for baked Ollama — see Step 4)az ad app update --set spa='{...}'may fail with JSON escaping — useaz rest --method PATCHinstead (see Step 6)
SKU decisions — ask the user first
Before running any az command that provisions resources, confirm each SKU choice with the user. Do not silently default to the cheapest tier. The orchestrator requires each SKU variable to be set and fails hard if any is missing. Full tradeoff matrix: references/sku-sizing.md.
| Variable | Ask | Demo default | Silent-failure mode if chosen wrong |
ACR_SKU | Basic / Standard / Premium | Basic | Ollama image ~1 GB; Basic fills up with 10 variants |
ACA_WORKLOAD_PROFILE | Consumption / Dedicated-D4 / GPU | Consumption | 1.5B model on Consumption CPU = 5–20 s per answer |
LOGS_DESTINATION | none / log-analytics | log-analytics | none hides Ollama OOM crashes and sidecar auth errors |
MIN_REPLICAS / MAX_REPLICAS | counts | 1 / 1 | min=0 = model reloads into RAM on every cold start |
OLLAMA_MODEL | qwen2.5:1.5b / qwen2.5:7b / llama3.2:1b | qwen2.5:1.5b | 7B model on Consumption times out ACA ingress |
OLLAMA_IMAGE_STRATEGY | baked / runtime-pull | baked | runtime-pull = 30 s first-request delay |
OLLAMA_CPU / OLLAMA_MEMORY | see model-to-sizing table | 0.75 / 1.5Gi | Undersized memory → Ollama OOM. qwen2.5:3b needs 2.5 Gi (requires Dedicated-D4+). See sku-sizing.md §7. |
When invoking this skill, explicitly state the defaults to the user and ask them to confirm or override — do not assume.
Procedure
Step 0 — Confirm account and populate variables
Ask the user to confirm: tenant ID, subscription ID, resource group name, location, SKU choices (including OLLAMA_CPU / OLLAMA_MEMORY — match to model), Ollama model. Then:
cp .claude/skills/deploy-agent-aca-dev/scripts/deploy-vars.sh.template /tmp/deploy-vars.sh
# edit /tmp/deploy-vars.sh with confirmed values
source /tmp/deploy-vars.sh
az login --tenant "$TENANT_ID" && az account set --subscription "$SUBSCRIPTION_ID"Step 1 — Create Entra objects (Blueprint, Agent, Client SPA)
Delegate to entra-agent-id-setup. Capture BLUEPRINT_APP_ID, AGENT_CLIENT_ID, CLIENT_SPA_APP_ID into /tmp/deploy-vars.sh.
[!WARNING] Run
Connect-MgGraphin an interactive pwsh session, not viapwsh -Command "Connect-MgGraph ..."subshell. The WAM authentication popup hides behind other windows in a subshell and silently times out.
Configure the Blueprint for OBO using the ACA-compatible PowerShell script:
pwsh -NoProfile -File .claude/skills/deploy-agent-aca-dev/scripts/setup-obo-blueprint-for-aca.ps1 \
-BlueprintAppId "$BLUEPRINT_APP_ID" \
-ClientSpaAppId "$CLIENT_SPA_APP_ID" \
-AgentAppId "$AGENT_CLIENT_ID" \
-TenantId "$TENANT_ID"Step 2 — Azure infrastructure (RG, ACR, env, container app skeleton)
See tutorial §6. Uses SKU variables. Capture MI_OBJECT_ID and APP_FQDN, append to /tmp/deploy-vars.sh. Grant AcrPull to the MI.
[!NOTE] Adding a Dedicated-D4 workload profile can take 20+ minutes to provision. This is normal — do not cancel. If Azure Policy enforces tags on resource groups (e.g.,
Owner,MonthlyCost), add them duringaz group createor use a pre-existing RG.
Step 3 — Federate MI to Blueprint (only federation chain)
Single Graph call — see tutorial §7. Subject = $MI_OBJECT_ID, audience = api://AzureADTokenExchange.
Unlike the AWS skill, there is no Step 4 (AWS federation). The local LLM needs no external cloud.
Step 4 — Build and push images
Tutorial §8. Three images: llm-agent, weather-api, ollama (baked) — or two if using runtime-pull.
Option A — Local Docker (docker buildx):
Requires Docker Desktop running. Works for all images including baked Ollama.
Option B — Remote build (az acr build):
No Docker Desktop needed. Works for llm-agent and weather-api only.
az acr build --registry "$ACR_NAME" --image agent-id-dev/llm-agent:1.0.0 --platform linux/amd64 sidecar/dev/
az acr build --registry "$ACR_NAME" --image agent-id-dev/weather-api:1.0.0 --platform linux/amd64 sidecar/weather-api/[!NOTE]
UnicodeEncodeError: 'charmap' codec can't encode charactersfromaz acr buildon Windows is cosmetic (colorama/cp1252 encoding). The build succeeds — ignore the error.
[!IMPORTANT] Baked Ollama images cannot be built via
az acr build— theRUN ollama serve & ollama pull ...step requires a running Docker daemon that ACR Build does not provide. The image silently fails to appear in ACR. If Docker Desktop is unavailable, switch toOLLAMA_IMAGE_STRATEGY=runtime-pull.
If OLLAMA_IMAGE_STRATEGY=baked (Option A only):
bash .claude/skills/deploy-agent-aca-dev/scripts/build-ollama-image.shStep 5 — Deploy the multi-container app
envsubst < .claude/skills/deploy-agent-aca-dev/scripts/containerapp.yaml.template > /tmp/containerapp.yaml
az containerapp update -g "$RG" -n "$APP_NAME" --yaml /tmp/containerapp.yamlStep 6 — Post-deploy wiring (REQUIRED — execute immediately after Step 5)
[!IMPORTANT] The AI agent MUST execute both sub-steps below. Do NOT skip or leave for the user. These are automatable —
APP_FQDNis known from Step 2, and all app IDs are known from Step 1.
Two things that cannot be done before deploy:
Add deployed SPA redirect URI —
bash .claude/skills/deploy-agent-aca-dev/scripts/add-spa-redirect-uri.sh[!WARNING] On PowerShell,
az ad app update --set spa='{...}'fails withProperty spa in payload has a value that does not match schemadue to JSON escaping. Use this workaround instead:$body = @{ spa = @{ redirectUris = @("http://localhost:3003", "https://$env:APP_FQDN/") } } | ConvertTo-Json -Depth 3 az rest --method PATCH --url "https://graph.microsoft.com/v1.0/applications(appId='$env:CLIENT_SPA_APP_ID')" --body $body --headers "Content-Type=application/json"Grant Agent → Graph delegated
User.Read(fixesAADSTS65001):pwsh -NoProfile -File .claude/skills/deploy-agent-aca-dev/scripts/grant-agent-obo-consent.ps1 \ -AgentAppId "$AGENT_CLIENT_ID" -TenantId "$TENANT_ID"
Full rationale: references/post-deploy-manual-steps.md.
Step 7 — Verify
Tutorial §11. ollama_available: true in status; autonomous flow returns Qwen-generated answer; OBO works via MSAL popup.
One-Shot Orchestrator
If all prerequisites are in place and SKU variables are confirmed:
bash .claude/skills/deploy-agent-aca-dev/scripts/deploy-aca-dev.shIdempotent. Invokes steps 2–5 in order. Steps 0, 1, 6 require human decisions and remain manual.
Key Artifacts
Persisted in /tmp/deploy-vars.sh:
| Variable | Source |
TENANT_ID, SUBSCRIPTION_ID | User |
ACR_SKU, ACA_WORKLOAD_PROFILE, LOGS_DESTINATION, MIN_REPLICAS, MAX_REPLICAS | User (SKU decisions) |
OLLAMA_MODEL, OLLAMA_IMAGE_STRATEGY | User |
OLLAMA_CPU, OLLAMA_MEMORY | User (match to model — see sku-sizing.md §7) |
BLUEPRINT_APP_ID, AGENT_CLIENT_ID, CLIENT_SPA_APP_ID | Step 1 |
MI_OBJECT_ID, APP_FQDN | Step 2 |
No client secrets, no external-cloud credentials anywhere.
References
- Architecture summary
- SKU and sizing decisions
- Ollama on Azure Container Apps
- Post-deploy manual steps (SPA URI + OBO consent)
- Troubleshooting matrix
- Full tutorial
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

