Study Guides/AI-200/Develop Containerized Solutions on Azure
20-25% of exam

Develop Containerized Solutions on Azure

Build and store images with Container Registry, host containers on App Service, and deploy and scale them with Container Apps and AKS.

Azure Container Registry: building, storing, and versioning images

Azure Container Registry (ACR) is the private registry almost every containerized AI workload on Azure pulls from — it stores the images your Container Apps, AKS, and App Service deployments run, alongside Helm charts and other OCI artifacts.

Repositories and tags

  • An image is identified by `<registry>.azurecr.io/<repository>:<tag>`, for example `myregistry.azurecr.io/inference-api:1.4.0`.
  • Tags aren't guaranteed unique over time unless you enforce it — enabling the `Immutable` tag setting on a repository prevents an existing tag from being overwritten, which matters once a tag is referenced from a production deployment.
  • ACR supports geo-replication, letting a single registry serve multiple regions with local pull latency and one set of image names to manage.

ACR Tasks: building images without a local Docker daemon

  • A *quick task* (`az acr build`) uploads your source and Dockerfile, builds the image in Azure, and pushes it to the registry on success — no local Docker installation required.
  • A scheduled or triggered task automates that same build: on a Git commit, on a base image update (so a patched base image ripples into every dependent application image automatically), or on a timer.
  • A *multi-step task* is defined in YAML and can chain several build/run/test/push operations — for example: build an image, run it, run a separate test container against it, and only push if the tests pass. Each step runs inside its own container, giving you composable, dependency-aware build pipelines entirely offloaded to Azure compute.

Common confusion

  • ACR Tasks is a build and automation service; it doesn't run your production workload continuously. Once an image lands in ACR, orchestration and hosting are separate concerns handled by App Service, Container Apps, or AKS.

Deploying containers to Azure App Service

App Service can run a single container or a small multi-container app directly from a registry, which is a lighter-weight option than Container Apps or AKS when you don't need event-driven scaling or Kubernetes-native features.

Container-specific configuration

  • The App Service plan still determines compute size and scaling limits, exactly as it does for code-based deployments — containers don't bypass the underlying plan.
  • `WEBSITES_PORT` (or the port your container exposes via `EXPOSE`) tells App Service which port to route traffic to inside the container.
  • Continuous deployment can be wired to ACR so that pushing a new tag (or updating the `latest` tag, when webhooks are enabled) triggers an automatic restart with the new image.

Environment variables and secrets

  • App settings are injected into the container as environment variables at startup — the same mechanism used for non-containerized App Service apps.
  • Secrets shouldn't be pasted directly into app settings in plaintext for anything sensitive; a Key Vault reference (`@Microsoft.KeyVault(...)`) in an app setting lets App Service resolve the actual secret value from Key Vault at runtime using its managed identity, without the secret ever being stored in the App Service configuration itself.
  • Deployment slots work the same way for containers as for code: a staging slot can run the new image and be validated before a slot swap promotes it to production with no downtime.

Common confusion

  • Changing an app setting on a container-based App Service app restarts the container (since environment variables are read at process startup) — there's no way to hot-reload a changed setting into a running container process.

Azure Container Apps: environments, revisions, and event-driven scaling

Container Apps is the serverless, Kubernetes-based hosting option built for microservices and event-driven AI workloads — it gives you scaling behavior similar to AKS without requiring you to manage the cluster.

Environments and revisions

  • A Container Apps *environment* is the security and networking boundary around one or more container apps — apps in the same environment share a virtual network and can communicate directly.
  • Every update to a container app's template (image, scale rules, or configuration such as CPU/memory) creates a new *revision*, an immutable snapshot. Revision mode can be single (only the latest revision serves traffic) or multiple (several revisions serve traffic simultaneously, useful for gradual rollout or A/B testing with traffic-splitting weights).
  • Not every change creates a revision — updating a secret's value, for example, applies to existing revisions in place, while changing the container image always creates a new one.

KEDA-based event-driven scaling

  • Container Apps scaling is powered by KEDA (Kubernetes Event-Driven Autoscaling) under the hood. Scale rules fall into three categories: HTTP (concurrent request count), TCP (concurrent connections), and custom — CPU/memory or an event source such as Azure Service Bus, Event Hubs, Kafka, or Redis.
  • A custom scale rule maps directly to a KEDA *scaler* specification (for example, `type: azure-servicebus` with a `queueName` and `messageCount` threshold) — this is exactly the mechanism you'd use to scale a queue-consuming AI inference worker out as messages pile up, and back to zero when the queue is empty.
  • Multiple scale rules can be defined on one app; the app scales as soon as *any* rule's condition is met. Scaling to zero (min replicas = 0) means the app costs nothing while idle, at the expense of a cold start on the next request.

Common confusion

  • KEDA scale rules control how many replicas run; they don't change compute size per replica (CPU/memory), which is set separately in the container app's resource configuration.

Deploying and managing applications on AKS with manifest files

AKS gives you a fully managed Kubernetes control plane — you manage the worker nodes and workloads, Azure manages the API server, etcd, and control-plane upgrades. Compared to Container Apps, AKS trades some operational simplicity for full Kubernetes API access and ecosystem compatibility.

Manifest-based deployment

  • Workloads are described declaratively in YAML manifests applied with `kubectl apply -f`. A typical AI service needs at least a `Deployment` (desired pod count, container image, resource requests/limits) and a `Service` (stable network endpoint routing traffic to the pods, whether ClusterIP, NodePort, or LoadBalancer).
  • Deployments manage rolling updates automatically: updating the image reference in a Deployment manifest and re-applying it replaces pods gradually according to the rollout strategy, rather than taking the whole app down at once.
  • Namespaces let you partition a single cluster (for example, separating a dev environment from production, or isolating tenants) with independent RBAC and resource quotas.
  • ACR integrates with AKS through `az aks update --attach-acr`, which grants the cluster's managed identity pull access to the registry without embedding registry credentials in a Kubernetes secret.

Common confusion

  • A Deployment ensures pods exist and restarts them on failure, but a Service is what makes them reachable at a stable address — deleting a Deployment's Service doesn't stop the pods, and creating pods without a Service leaves them unreachable from outside the cluster.

Monitoring and troubleshooting AKS and Container Apps

Diagnosing a failing containerized deployment means correlating three signal types: logs (what the app said), events (what the platform did), and connectivity (whether traffic can actually reach the workload).

Container Apps

  • The Log Stream and the `az containerapp logs show` command tail console output (stdout/stderr) from a running revision in near real time — the first stop for a crashing or misbehaving container.
  • System logs (revision provisioning, scaling events, restarts) are separate from application console logs and are what tells you *why* a revision failed to become active, as opposed to what the app printed.
  • Provisioning and health probe failures (a container failing its readiness or liveness probe) show up as revision-level status, distinct from an app that started fine but is returning errors to callers.

AKS

  • `kubectl get events --sort-by=.lastTimestamp` surfaces scheduling failures, image pull errors, and probe failures at the cluster level, often revealing the root cause before you ever look at application logs.
  • `kubectl logs <pod> [-c <container>] [--previous]` retrieves a container's logs, with `--previous` critical for a pod that already crashed and restarted (`CrashLoopBackOff`) — the current container's logs may be empty while the previous attempt's logs hold the actual error.
  • `kubectl describe pod <pod>` shows recent events for a specific pod, including why a container was restarted or why scheduling failed (for example, insufficient CPU/memory on any node).
  • End-to-end connectivity issues (a pod that starts but can't reach a dependency) are diagnosed by checking Service selectors match pod labels, network policies, and DNS resolution inside the cluster (`kubectl exec` into a pod to test with `curl` or `nslookup`).

Common confusion

  • A pod stuck in `Pending` is a scheduling problem (no node has room, or a required resource isn't available); a pod stuck in `CrashLoopBackOff` is a runtime problem (the container starts and then exits) — the two point troubleshooting in very different directions.