AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Container Apps Deployment

skill-microsoft-agentic-journeys-container-apps-deployment · by microsoft

|

— No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add skill-microsoft-agentic-journeys-container-apps-deployment

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ● Shell / process execution Used
  • ● Environment & secrets Used
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-microsoft-agentic-journeys-container-apps-deployment)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Container Apps Deployment? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Container Apps Deployment Patterns

Supplements the official azure-prepare plugin skill with additional gotchas for Container Apps deployments — zone redundancy, azure.yaml, and SPA frontend patterns.

> 📖 ACR authentication: Use a deterministic two-phase pattern with separate deployment modules. The bootstrap module provisions each Container App with a public placeholder image and system-assigned identity but no configuration.registries entry. Grant that principal AcrPull, then make a later module depend on the role assignment and update the same app with the ACR login server and identity: 'system' before deploying private images. A single module that declares both a new system identity and registry is not two-phase and can fail with an ACR token-exchange 401. Some azd versions call az containerapp registry set automatically and some do not. Never assume that implicit step occurred; verify the registry configuration before the first private-image deployment.

Region-Specific Gotchas

Container Apps Environment zoneRedundant

The AVM module br/public:avm/res/app/managed-environment may default zoneRedundant to true. Several regions (including westus) don't support it.

module cae 'br/public:avm/res/app/managed-environment:0.8.1' = {
  params: {
    // ...
    zoneRedundant: false  // Required for westus and other regions without zone support
  }
}

Without this: azd up fails with "Zone redundancy is not currently supported in this region".

azure.yaml Configuration

Docker services require language field

azd requires either language or image on each service, even when docker.path is specified:

services:
  api:
    host: containerapp
    language: ts                  # REQUIRED — azd won't infer from Dockerfile
    docker:
      path: api/Dockerfile
      context: api
      remoteBuild: true

Declare each service whose image azd owns this way. AIMarket declares only api; Bicep creates its web Container App and the project postdeploy hook owns the storefront ACR build and update. Without language: azd up fails with "must specify language or image". Without remoteBuild: true: azd can require a local Docker daemon.

Cross-platform hooks

This repository requires azd 1.28.0 or later and Node.js LTS or later. Use JavaScript or TypeScript hooks referenced directly from azure.yaml; azd detects the language from the extension. Do not generate Bash-only .sh or PowerShell-only .ps1 lifecycle hooks.

hooks:
  postprovision:
    run: infra/hooks/postprovision.js
  postdeploy:
    run: infra/hooks/postdeploy.js

Use postprovision for steps that need infrastructure outputs, such as setting WEBHOOK_URL. Use postdeploy for steps that need deployed services, such as rebuilding a frontend with its API URL. Hook code must invoke az and azd through argument arrays, never interpolated shell command strings. On Mac and Linux, call the CLI executable directly. On Windows, .cmd shims cannot be launched with execFileSync() or spawnSync() alone. Invoke a static, non-interpolated powershell.exe runner and pass the command plus arguments as a JSON environment payload, then use PowerShell's call operator with array splatting. This supports both the Azure CLI shim and the azd.exe installation without exposing arguments to shell parsing. Build deployment images in Azure Container Registry so the host does not need Docker or Buildx.

SPA Frontend Deployment (React/Vite)

The VITEAPIURL Problem

When deploying a React/Vite frontend and API as separate Container Apps, the frontend needs the API's URL baked in at build time. But the API URL isn't known until after provisioning.

Symptoms:

  • Frontend shows Unexpected token '/api.
  1. Update the web Container App to use the cloud-built image.
  2. Wait until the expected revision is healthy and provisioned, then verify the storefront can load products. When minReplicas is 0, accept both Running and ScaledToZero; requiring only Running causes a false timeout before the verification request can activate the revision.

Call external tools with execFileSync() or spawnSync() and argument arrays. Do not concatenate a shell command, use chmod, or depend on Bash, cut, grep, or date. The static Windows PowerShell launcher described above is the only platform-specific exception; all CLI arguments must travel in the JSON environment payload. Windows PowerShell cannot losslessly pass a literal double quote inside a native argument, so reject it for every Windows target. For .cmd/.bat, also reject &, |, `, ^, %, !, (, ), and CR/LF. Rewrite unsafe arguments or use attached files; native .exe` targets preserve the remaining metacharacters. Use JavaScript for path handling, timestamps, retries, and JSON parsing.

For a storefront-only rebuild, run node infra/hooks/postdeploy.js explicitly and verify production product loading. In the AIMarket pattern the web Container App is not an azd service, so azd deploy web is not a valid command.

After the first green deploy, explain why the hook exists. Don't make the learner discover a blank product grid first.

Frontend Dockerfile Requirements

FROM node:24-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Keys: ARG + ENV must appear before RUN npm run build so Vite picks up the URL. The postdeploy hook sends this Dockerfile to an ACR linux/amd64 cloud build.

nginx.conf — SPA Only

server {
    listen 80;
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }
}

Do NOT add an /api/ proxy block. The frontend calls the API directly via VITE_API_URL. Adding a proxy to an internal hostname will fail because Container Apps don't resolve each other by name without VNet.

Frontend API Client Pattern

const API_BASE = import.meta.env.VITE_API_URL || '/api';

export async function getProducts() {
  const res = await fetch(`${API_BASE}/products`);
  return res.json();
}

In dev: VITE_API_URL is unset → falls back to /api → Vite proxy handles it. In prod: VITE_API_URL is https://ca-api-xxx.azurecontainerapps.io/api → calls API directly.

.dockerignore Requirements

Every build context sent to ACR needs a .dockerignore that excludes dependency directories (node_modules/), build output, local database files, .env files, and Git metadata (.git/). Keep the files the in-container build itself needs — for the default Node.js stack, do not exclude tsconfig.json or package*.json, or the container's TypeScript build fails. An unfiltered context can also overwhelm the ACR build upload.

ARM64 Host Cross-Compilation

Azure Container Apps runs Linux AMD64. This applies to Apple Silicon, Windows ARM64, and Linux ARM64 hosts.

Require ACR cloud builds targeting linux/amd64. Do not require Docker, Buildx, AMD64 emulation, or privileged QEMU/binfmt handlers on the host.

Without an AMD64 target, the container can crash with exec format error. ACR builds remove that host-architecture dependency.

Bicep uniqueString() Length Contracts

Azure's uniqueString() always returns 13 characters. When passing that value into a module, declare the module parameter with both @minLength(13) and @maxLength(13). Otherwise Bicep can emit false BCP334 warnings when the parameter is used in constrained resource names.

Bicep Output Naming Convention

Outputs must use SCREAMINGSNAKECASE for azd to pick them up:

output API_URL string = 'https://${apiApp.outputs.fqdn}'
output WEB_URL string = 'https://${webApp.outputs.fqdn}'
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = acr.outputs.loginServer
output RESOURCE_GROUP_NAME string = rg.name

Wrong naming → azd env get-value returns "key not found".

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.