Trust is earned, not given

A different perspective

2018-11-06 · Projects

DevOps on Azure, part 2: Compute — App Service, AKS, Container Apps, Functions

Part 2from the DevOps on Azure series · 6 parts in all

Part 2 of the Azure series: where code runs. Azure's compute lineup is the most opinionated of the three clouds — App Service in particular does so much for you that knowing its limits is a skill in itself.

App Service: the PaaS baseline

Push a repository or container; App Service handles the runtime, patching, TLS, load balancing, and autoscale. MapleCart's storefront lives here:

# Create the plan and web app (CLI; in prod this is the Terraform in part 6)
az appservice plan create -g maplecart-rg -n maplecart-plan \
  --is-linux --sku P1v3 --number-of-workers 2        # Premium: autoscale + slots
az webapp create -g maplecart-rg -p maplecart-plan -n maplecart-web \
  --container-image maplecart.azurecr.io/web:v42

# Deployment slots: staging exists alongside production
az webapp deployment slot create -g maplecart-rg -n maplecart-web --slot staging
az webapp deployment slot swap  -g maplecart-rg -n maplecart-web --slot staging \
  --target-name production        # warm swap: zero-downtime, one operation

# Auto-scale on CPU between 2 and 6 instances
az monitor autoscale create -g maplecart-rg --resource maplecart-plan \
  --name cpu-scale --min-count 2 --max-count 6 --count 2
az monitor autoscale rule create -g maplecart-rg --autoscale-name cpu-scale \
  --condition "Percentage CPU > 70 avg 10m" --scale out 2
az monitor autoscale rule create -g maplecart-rg --autoscale-name cpu-scale \
  --condition "Percentage CPU < 30 avg 15m" --scale in 1

The slot swap deserves emphasis: deploy to staging, run smoke tests against the real staging URL, then swap — App Service warms the new instances before they receive traffic. It is the best zero-downtime story on any cloud, and it's why MapleCart picks App Service over Kubernetes it doesn't need.

AKS and Container Apps: when you need Kubernetes — and when you don't

FleetView runs a dozen microservices with per-service scaling and sidecars: that's AKS (managed Kubernetes) territory, or its lighter cousin Container Apps (Kubernetes features — scale-to-zero, KEDA event scaling — without owning a cluster):

az aks create -g fleetview-rg -n fleetview-aks \
  --node-count 3 --node-vm-size Standard_D4s_v5 \
  --enable-managed-identity --network-plugin azure \
  --enable-oidc-issuer --enable-workload-identity   # pods get Entra identities

az containerapp create -g fleetview-rg -n ingest-api --environment fleetview-env \
  --image fleetview.azurecr.io/ingest:v9 \
  --scale-rule-name queue --scale-rule-type azure-servicebus \  # scale on queue depth
  --min-replicas 0 --max-replicas 30               # scale to zero overnight

Functions: the event-driven tier

NewsGrid's API and image pipeline are Azure Functions on the Consumption plan — billed per execution, zero when idle:

# FunctionApp (Python, isolated model). The trigger is the whole deployment story.
import azure.functions as func

app = func.FunctionApp()

@app.function_name(name="ResizeImage")
@app.blob_trigger(arg_name="blob", path="uploads/{name}",
                  connection="NewsGridStorage")
def resize_image(blob: func.InputStream):
    from PIL import Image; import os
    if not blob.name.lower().endswith((".jpg", ".png")):
        return                                    # guard first
    im = Image.open(blob)                         # stream from storage
    im.thumbnail((800, 800))
    out = os.path.join("/tmp", os.path.basename(blob.name))
    im.save(out, optimize=True)
    # connection string comes from app settings fed by managed identity

The decision table

App ServiceAKS / Container AppsFunctions
You managecodemanifests (or cluster)function
Idle costplan priceper-pod / zero (CA)zero
Slots/blue-greenbuilt-in (best in class)rolloutsslots (premium)
Fitweb apps, APIsmicroservice fleetsevents, spiky

Next: the data layer — Azure SQL, Cosmos DB, Blob Storage — and how each company's data shape dictates its choice.