Free Ebook cover Azure Fundamentals for Web Hosting: From App Service to Virtual Machines

Azure Fundamentals for Web Hosting: From App Service to Virtual Machines

New course

12 pages

Azure Fundamentals for Web Hosting: Container Apps for web workloads (images, revisions, and scaling)

Capítulo 6

Estimated reading time: 9 minutes

+ Exercise

What Azure Container Apps is (and what you manage)

Azure Container Apps is a managed service for running containerized web workloads (HTTP APIs, web frontends, background workers) without operating Kubernetes yourself. You provide container images and configuration; Azure handles the underlying cluster, scheduling, HTTPS ingress integration, and autoscaling.

In practice, you focus on: container images (what runs), configuration (environment variables and secrets), ingress (how HTTP reaches your app), revisions (how releases are rolled out), and scaling rules (how many replicas run).

Lifecycle view: image → configuration → ingress → revisions → scaling

1) Build or pull a container image

Container Apps runs OCI-compatible images (commonly Docker images). You can either build locally/CI and push to a registry, or pull a public image. For web workloads, ensure your container listens on a known port and stays in the foreground (the main process must keep running).

  • Pick a listening port: many frameworks default to 80, 3000, 5000, 8080, etc. Container Apps needs to know the target port for ingress routing.
  • Health and startup behavior: keep startup time reasonable; slow startups can delay scaling and revision activation.
  • Stateless by default: assume replicas can be added/removed at any time; store state externally (database, cache, storage) rather than on the container filesystem.

Example Dockerfile for a simple Node.js web API:

FROM node:20-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-alpine WORKDIR /app ENV NODE_ENV=production COPY --from=build /app . EXPOSE 8080 CMD ["node", "dist/server.js"]

When you deploy, you’ll reference the image by registry path and tag, for example: myregistry.azurecr.io/myapi:1.4.0.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

2) Choose a container registry (and plan for safe updates)

You need a place to store images that Container Apps can pull from. Common options:

  • Azure Container Registry (ACR): best default for production on Azure; private registry, integrates well with Azure identity and networking options.
  • Docker Hub or other public registries: convenient for demos; be mindful of rate limits and public exposure.
  • GitHub Container Registry (GHCR): good if your CI/CD is GitHub-centric; can be private with fine-grained permissions.

Practical guidance for safe image updates:

  • Prefer immutable references: use version tags (e.g., 1.4.0) or, even better, image digests (e.g., @sha256:...) so a “release” always points to the same bits.
  • Avoid relying on latest: it makes rollbacks and debugging harder because the tag can change without a configuration change.
  • Keep a release trail: align image tags with your release version and keep changelogs; this pairs naturally with Container Apps revisions.

Step-by-step: push an image to ACR (conceptual flow):

  • Create or use an existing ACR instance.
  • Authenticate your build pipeline to ACR.
  • Build the image and tag it with a version: myapi:1.4.0.
  • Push to ACR: myregistry.azurecr.io/myapi:1.4.0.
  • Deploy Container App referencing that tag (or digest).

3) Configure environment variables and secrets

Most web apps need configuration: connection strings, API keys, feature flags, and environment-specific settings. In Container Apps you typically use:

  • Environment variables for non-sensitive settings (e.g., ASPNETCORE_ENVIRONMENT, LOG_LEVEL, PUBLIC_BASE_URL).
  • Secrets for sensitive values (e.g., database passwords, JWT signing keys). Secrets can be referenced by environment variables so your app reads them normally.

Practical pattern: define a secret and map it to an env var:

  • Create secret: DB_PASSWORD (stored securely by the service).
  • Set env var: DATABASE_URL = postgres://user:${DB_PASSWORD}@host:5432/db (or store the full connection string as a secret if you prefer).

Operational tips:

  • Rotate secrets safely: update the secret, create a new revision, shift traffic gradually (see revisions below).
  • Separate config per environment: dev/test/prod should have different values; keep production secrets out of developer machines.
  • Don’t bake secrets into images: images are portable artifacts; treat them as non-secret.

4) Expose HTTP ingress for web APIs and frontends

For web workloads, you typically enable HTTP ingress so the Container App receives requests from the internet (or from internal callers, depending on your setup). Key concepts:

  • Target port: the port your container listens on (e.g., 8080). Ingress routes HTTP traffic to that port.
  • Transport: HTTP is most common for web apps; gRPC is also supported for certain scenarios.
  • External vs internal ingress: external is reachable publicly; internal is reachable only within the environment (useful for internal APIs).

Step-by-step checklist to get a web container reachable:

  • Confirm your app listens on the configured port (e.g., PORT=8080 or framework-specific setting).
  • Enable ingress and set the target port to match.
  • Deploy and verify the generated application URL responds (e.g., /health endpoint).
  • If you have multiple containers (sidecars), ensure the correct container is the ingress target.

5) Manage revisions for releases (safe rollout and rollback)

Container Apps uses revisions to represent versions of your app configuration and image. A new revision is created when you change things like the image tag/digest, environment variables, secrets references, or scaling settings.

Two common revision modes:

  • Single revision mode: only one active revision at a time. Simple and cost-effective; good for straightforward deployments.
  • Multiple revision mode: multiple revisions can be active simultaneously with traffic splitting. This enables canary releases and quick rollbacks.

Practical release workflow using multiple revisions (canary):

  • Deploy revision A (current stable) running myapi:1.4.0.
  • Deploy revision B (new) running myapi:1.5.0 with any config changes.
  • Split traffic: send 5% to revision B, 95% to revision A.
  • Monitor error rate/latency and application logs.
  • Increase traffic gradually (25% → 50% → 100%).
  • If issues occur, set traffic back to 100% on revision A (rollback without redeploying).

Safe image update practices with revisions:

  • Use a new tag per release so the revision clearly maps to a version.
  • Prefer digest pinning for high assurance: the revision always pulls the exact image you tested.
  • Keep old revisions available briefly (in multiple revision mode) to enable fast rollback during a release window.

Scaling basics in Container Apps

Container Apps scales by adjusting the number of replicas (instances of your container). Scaling is driven by demand signals such as HTTP requests and concurrency, and it can scale down to zero when idle (if configured).

Scale to zero

With min replicas = 0, the app can scale down to zero replicas when there is no traffic. This can reduce cost for spiky or low-traffic APIs. Trade-off: the first request after idle may experience a cold start while a replica starts.

  • Good for: dev/test, internal tools, bursty APIs.
  • Considerations: cold start latency; ensure startup is fast and dependencies are reachable.

Min/max replicas

You can set:

  • Min replicas: the baseline number of replicas always running (e.g., 1 or 2 for production to reduce cold starts and improve availability).
  • Max replicas: an upper bound to control cost and protect downstream systems (e.g., database) from overload.

Example reasoning: set min=2 for a public API to avoid cold starts and allow one replica to be recycled without downtime; set max=10 to cap burst scaling until you validate database capacity.

Concurrency-based scaling (HTTP)

For HTTP workloads, a key scaling concept is concurrency: how many simultaneous requests a single replica should handle before scaling out. If each replica can comfortably handle 50 concurrent requests, you can set a concurrency target around that value so the platform adds replicas as concurrency rises.

  • Lower concurrency target: more replicas sooner (better latency, higher cost).
  • Higher concurrency target: fewer replicas (lower cost, risk of higher latency under load).

Practical tuning approach:

  • Start with a conservative concurrency target (e.g., 20–50) for typical web APIs.
  • Load test and observe CPU/memory and response times.
  • Adjust concurrency and max replicas together to balance performance and cost.

How scaling differs from App Service and Virtual Machines

Compared to App Service

  • Unit of deployment: App Service typically deploys code or a container within an App Service Plan; Container Apps deploys containers with revision-based releases.
  • Scaling behavior: App Service scales instances of the plan/app (often with fixed minimums); Container Apps can scale to zero and scale based on request-driven signals like concurrency.
  • Release strategy: App Service uses deployment slots; Container Apps uses revisions and traffic splitting (canary-style) as a first-class concept.

Compared to Virtual Machines

  • What you manage: on VMs you manage OS, patching, runtime, and process supervision; Container Apps focuses on the container and app configuration.
  • Scaling: VMs scale via VM Scale Sets or manual changes and typically don’t scale to zero for web endpoints; Container Apps can scale replicas dynamically and down to zero.
  • Release safety: on VMs you often implement your own blue/green or rolling deployments; Container Apps revisions provide built-in mechanisms for gradual rollout and rollback.

Practical step-by-step: deploy and update a web API with safe image handling

Step 1: Prepare the image and registry strategy

  • Decide on a registry: ACR for production on Azure is a common choice.
  • Adopt a tagging policy: major.minor.patch (e.g., 1.5.0) and optionally also store the digest used for production.
  • Ensure the container listens on a known port (e.g., 8080) and has a /health endpoint.

Step 2: Create the Container App and enable ingress

  • Set the container image to myregistry.azurecr.io/myapi:1.4.0 (or digest).
  • Configure ingress as external (public) for a public API or internal for private services.
  • Set target port to the port your container listens on (e.g., 8080).

Step 3: Add configuration and secrets

  • Add non-sensitive env vars: LOG_LEVEL=info, FEATURE_X=false.
  • Add secrets: DB_PASSWORD, JWT_SIGNING_KEY.
  • Reference secrets via env vars so the app reads them like normal configuration.

Step 4: Configure scaling

  • For production web APIs: set min replicas to 1 or 2 to reduce cold starts.
  • Set max replicas to a safe upper bound based on downstream capacity.
  • Set an initial concurrency target and adjust after observing real traffic.

Step 5: Release a new version using revisions

  • Build and push myapi:1.5.0 to your registry.
  • Update the Container App image to myapi:1.5.0 (creates a new revision).
  • If using multiple revisions: route 5–10% traffic to the new revision first.
  • Monitor logs/metrics; if stable, increase traffic to 100%.
  • If problems appear: shift traffic back to the previous revision immediately.

Step 6: Handle image updates safely over time

  • Pin production to digests when you need strict immutability (e.g., regulated environments).
  • Keep old images in the registry long enough to support rollback during the release window.
  • Automate vulnerability scanning in your CI/CD and rebuild images regularly to pick up base image security fixes.
  • Document the mapping of revision → image tag/digest → change request so troubleshooting is fast.

Now answer the exercise about the content:

When rolling out a new version of a web API in Azure Container Apps using multiple revisions, which approach best supports a safe canary release and quick rollback?

You are right! Congratulations, now go to the next page

You missed! Try again.

Multiple revision mode supports traffic splitting between revisions, enabling a canary rollout. Using versioned tags or digests makes updates predictable, and shifting traffic back to the prior revision provides fast rollback without redeploying.

Next chapter

Azure Fundamentals for Web Hosting: Custom domains and DNS configuration on Azure

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.