Backend / Cloud: Azure / 02_compute_app_service_and_functions.md

Azure compute: App Service, Functions, Container Apps

Updated 5 interview angles 4 min read source
On this page6
  1. The three options
  2. App Service, in practice
  3. Functions, and the trap
  4. Where the Python detail bites
  5. Related
  6. Interview angle

Azure compute: App Service, Functions, Container Apps

Three ways to run a Python service on Azure, and the interview question is always which one and why.

The three options

Service Runs
App Service A long-lived web app on managed VMs
Functions Event-triggered handlers, scale to zero
Container Apps Containers on managed Kubernetes

App Service is the closest thing to “deploy my web app and stop thinking”. It hosts a Python ASGI or WSGI app, terminates TLS, manages certificates, and gives you deployment slots. The AWS analogue is Elastic Beanstalk or App Runner; the mental model is a managed VM you do not log into.

Azure Functions is the serverless option: a handler bound to a trigger, billed per execution, scaling to zero.

Container Apps runs containers on a managed Kubernetes underneath (KEDA for scaling, Dapr optionally) without exposing the cluster. It is where a containerised service goes when App Service is too restrictive and AKS is too much operational surface.

Choosing

  • One web app, standard HTTP, no container requirement: App Service.
  • Event-driven, spiky, or glue between services: Functions.
  • Containerised, needs scale-to-zero or multiple revisions: Container Apps.
  • You genuinely need cluster primitives - operators, CRDs, custom networking: AKS, and accept running it.

App Service, in practice

A Python app on App Service runs behind a front end that expects your process to bind the port it supplies.

bash
# Azure sets PORT; bind it or the container is
# marked unhealthy and restarted.
gunicorn app:app \
  -k uvicorn.workers.UvicornWorker \
  --bind 0.0.0.0:$PORT

The two features that matter beyond hosting:

Deployment slots. A slot is a full parallel instance with its own hostname. Deploy to staging, warm it, then swap. The swap is a routing change, so rollback is swapping back rather than redeploying.

bash
az webapp deployment slot swap \
  --slot staging --target-slot production

Settings marked as slot settings stay with the slot rather than travelling with the swap, which is how the staging database URL does not follow the app into production. Getting that wrong is the classic slot incident.

Always On. Without it the app is unloaded when idle and the next request pays a cold start. On any production tier, turn it on.

Functions, and the trap

The Python model is a handler plus a trigger binding:

python
import azure.functions as func

app = func.FunctionApp()

@app.timer_trigger(schedule="0 */5 * * * *",
                   arg_name="timer")
def sync(timer: func.TimerRequest) -> None:
    run_sync()

Triggers cover HTTP, timers, queues, blobs and Event Hubs, and the binding model means the queue plumbing is configuration rather than code.

The trap is the hosting plan, which decides behaviour more than the code:

Plan Cold starts
Consumption Yes; scales to zero, cheapest
Premium No; pre-warmed instances, VNet
Dedicated No; runs on an App Service plan

On Consumption, a Python function that imports a large ML library can cold start in seconds. If latency matters, that is a Premium plan decision, not something to optimise in code. And Consumption caps execution duration, so long-running work belongs in a queue-triggered function or a container, not an HTTP handler.

Where the Python detail bites

Azure builds Python apps with Oryx, which installs from requirements.txt. Packages needing system libraries frequently fail there, and the fix is to deploy a container instead of source - which is the practical reason many teams land on Container Apps.

For anything with native dependencies, ship an image. See Multi-stage builds.

Interview angle 5

  • “App Service, Functions or Container Apps?” - App Service for a standard long-lived web app, Functions for event-driven or spiky work that should scale to zero, Container Apps for containerised services needing scale-to-zero or revision management without operating a cluster. AKS only when you actually need cluster primitives.
  • “What is a deployment slot and why use one?” - a parallel instance with its own hostname that you deploy to, warm, and then swap into production. The swap is a routing change, so rollback is an instant swap back rather than a redeploy.
  • “What breaks during a slot swap?” - configuration that should have been marked as a slot setting travelling with the app, so production picks up staging’s database or keys. Slot-specific settings must be pinned to the slot.
  • “Why is your Azure Function slow on the first request?” - Consumption plan cold start, made much worse in Python by heavy imports. It is a hosting-plan decision: Premium keeps instances pre-warmed. Consumption also caps execution time, so long work belongs on a queue trigger.
  • “Why would you containerise instead of deploying source?” - the Oryx source build installs from requirements.txt and fails on packages needing system libraries. An image makes the environment explicit and portable, which is also what pushes teams toward Container Apps.