Container Apps solved the availability engine with very little effort, and that is the best news in the previous lesson. But there is a different front at Contoso Airlines: the flight operations platform, twelve microservices that coordinate gate assignment, crew rotation, fuel loading and delays, written by three teams, with one component that demands high-memory nodes and another that needs affinity between pods. That system calls for fine-grained control of scheduling, network policies between services and third-party operators. There, yes: Kubernetes.

This lesson teaches Azure Kubernetes Service honestly: what it gives you, what remains your work, what it really costs and in which cases adopting it is over-engineering. Contoso adopts it for flight operations, not for the whole platform, and that decision is the first lesson.

Contents

  1. When Kubernetes is justified and when it is not
  2. Kubernetes concepts, the essentials
  3. What AKS manages and what remains yours
  4. Creating aks-contoso-operaciones and choosing the network model
  5. Identity: Entra ID, RBAC and workload identity
  6. Deploying the application with manifests and kubectl
  7. Managed ingress and certificates
  8. Scaling, requests and limits
  9. Upgrades, disruptions and maintenance
  10. Persistent storage, observability, Helm and realistic cost
  11. Common Mistakes and Tips
  12. Exercises
  13. Conclusion

  1. When Kubernetes is justified and when it is not

Signal Kubernetes?
A handful of stateless APIs with uneven load No: Container Apps, cheaper
Twelve or more services with dependencies between them Yes
You need operators, service meshes or CRDs, or per-workload hardware (GPU) Yes
Real portability between clouds or your own data center Yes
"It's what everyone uses now", or nobody knows how to operate a cluster No, and those are the two most frequent reasons

The hidden cost of Kubernetes is not the node bill, it is the team's time: quarterly upgrades, API versions being retired, network debugging, certificate management. If nobody is going to spend time on that, a cluster ages until it becomes a risk. Contoso takes it on only where the return justifies it.

  1. Kubernetes concepts, the essentials

graph TD
  subgraph CP["Control plane (managed by AKS, free)"]
    API[API server] --- ETCD[(etcd)]
    API --- SCHED[Scheduler] --- CTRL[Controllers]
  end
  subgraph NODES["Node pools (your virtual machines, you pay)"]
    N1["Node 1: gates pod + crew pod"]
    N2["Node 2: gates pod + fuel pod"]
  end
  API --> N1
  API --> N2
  ING[Ingress: operaciones.contosoairlines.example] --> SVC[Service: gates]
  SVC --> N1
  SVC --> N2
  • Control plane: the brain. The API server receives every instruction, etcd stores the desired state, the scheduler decides which node each pod fits on and the controllers endlessly correct the difference between what exists and what should exist. That reconciliation loop is the central idea of Kubernetes: you declare the destination, the system takes care of the route.
  • Node: a virtual machine that runs pods, grouped with others into node pools. And pod: the smallest schedulable unit, one or more containers that share networking and storage. It is ephemeral: if it dies, it does not come back; another one is born with a different IP address.
  • Deployment and ReplicaSet: the deployment declares "I want N replicas of this pod with this image"; the ReplicaSet keeps the count and orchestrates rolling updates.
  • Service and ingress: the service gives a stable IP and DNS name in front of a changing set of pods — it solves the fact that pods have no fixed address — while the ingress routes incoming HTTP traffic by host name and path, with TLS, through a single entry point for many services.
  • Namespace: a logical partition of the cluster with its own quotas and permissions; Contoso uses operaciones-vuelo, integracion and monitorizacion. And ConfigMap and Secret: configuration and sensitive data injected as environment variables or files. Careful: a Kubernetes Secret is only base64-encoded, not encrypted, which is why Contoso pulls them from kv-contoso-pro.

  1. What AKS manages and what remains yours

Responsibility AKS You
Control plane (API, etcd, scheduler) Yes, and it is free —
etcd backups Yes —
Nodes: virtual machines and disks Provisions them You pay for them
OS patching and Kubernetes version Publishes images and versions Deciding and launching the upgrade
Manifests, limits, network policies, alerts Integrations Yours

Say it plainly, because it generates a lot of surprise bills: the AKS control plane is free on the Free tier; what you pay for are the nodes, which are ordinary virtual machines with their compute price and their disks. An "empty" cluster with three nodes costs the same as three virtual machines left running. The Standard tier adds an SLA with a per-cluster hourly cost, and that is what is appropriate in production.

  1. Creating aks-contoso-operaciones and choosing the network model

az aks create \
  --resource-group rg-contoso-reservas-pro --name aks-contoso-operaciones \
  --location westeurope --tier standard --kubernetes-version 1.30.4 \
  --nodepool-name sistema --node-count 3 --node-vm-size Standard_D4s_v5 --zones 1 2 3 \
  --enable-cluster-autoscaler --min-count 3 --max-count 6 \
  --network-plugin azure --network-plugin-mode overlay --network-policy cilium \
  --vnet-subnet-id $(az network vnet subnet show -g rg-contoso-red-pro \
      --vnet-name vnet-contoso-pro -n snet-app --query id -o tsv) \
  --enable-aad --enable-azure-rbac --enable-managed-identity \
  --enable-oidc-issuer --enable-workload-identity \
  --attach-acr acrcontosopro --enable-addons monitoring \
  --workspace-resource-id $(az monitor log-analytics workspace show \
      -g rg-contoso-seguridad-pro -n log-contoso-pro --query id -o tsv) \
  --tags entorno=produccion proyecto=contoso-reservas \
         centro-coste=CC-1042 [email protected]

And straight after it the user node pool, because mixing system and application workloads in the same pool is a classic mistake:

az aks nodepool add \
  --resource-group rg-contoso-reservas-pro --cluster-name aks-contoso-operaciones \
  --name aplicaciones --mode User \
  --node-vm-size Standard_D8s_v5 --node-count 2 --zones 1 2 3 \
  --enable-cluster-autoscaler --min-count 2 --max-count 12

The decisions behind all this:

  • --nodepool-name sistema with --mode System (implicit in create): it hosts CoreDNS, metrics-server and the add-ons. If a runaway application workload eats its memory, DNS goes down for the entire cluster. Separate them.
  • --zones 1 2 3 spreads the nodes across availability zones — without this, a zone incident takes the cluster with it — and --enable-cluster-autoscaler adds and removes nodes according to the pods that do not fit, which is different from pod scaling (section 8).
  • --attach-acr acrcontosopro assigns the AcrPull role to the cluster's kubelet identity for you; without it, pods fail with ImagePullBackOff and the error is opaque. And --enable-workload-identity plus --enable-oidc-issuer is the foundation of section 5.

Networking: kubenet, Azure CNI and CNI Overlay

kubenet Azure CNI Azure CNI Overlay
Pod IP Internal overlay network From the virtual network subnet Managed overlay network
Subnet IP consumption Very low Very high Very low
Direct connectivity to the pod No, with hops Yes Not direct
Performance and status Lower; being retired Maximum; current Almost like CNI; recommended

The most expensive design mistake in AKS is choosing Azure CNI without doing the arithmetic: each node reserves in advance as many IPs as the maximum number of pods it can host (30 by default), so 20 nodes consume 600 addresses and a /24 runs out before you have even started. Contoso uses CNI Overlay over snet-app (10.20.2.0/24): the nodes take IPs from the subnet, the pods from an overlay space, and the subnet copes with growth. Network policy (Cilium) is added so that a pod can be explicitly forbidden from talking to another; without it, inside the cluster everything talks to everything.

  1. Identity: Entra ID, RBAC and workload identity

With --enable-aad --enable-azure-rbac, who gets into the cluster is decided by Microsoft Entra ID and what they can do is decided by Azure RBAC, using the same groups from module 4:

CLUSTER_ID=$(az aks show -g rg-contoso-reservas-pro -n aks-contoso-operaciones --query id -o tsv)

# Infrastructure: full cluster administration
az role assignment create --role "Azure Kubernetes Service RBAC Cluster Admin" \
  --assignee-object-id $(az ad group show -g Contoso-Infraestructura --query id -o tsv) \
  --assignee-principal-type Group --scope $CLUSTER_ID

# Development: write access only inside THEIR namespace
az role assignment create --role "Azure Kubernetes Service RBAC Writer" \
  --assignee-object-id $(az ad group show -g Contoso-Desarrollo --query id -o tsv) \
  --assignee-principal-type Group --scope "$CLUSTER_ID/namespaces/operaciones-vuelo"

Workload identity is the piece that removes secrets from inside the cluster. A Kubernetes service account is federated with id-contoso-api-pro: the pod receives a token signed by the cluster's OIDC issuer, exchanges it for an Entra ID token and reaches kv-contoso-pro and db-reservas with DefaultAzureCredential, the same code as in 04-02, with no key at all.

# Federate the namespace's service account with the managed identity
az identity federated-credential create \
  --name fed-operaciones --identity-name id-contoso-api-pro \
  --resource-group rg-contoso-seguridad-pro \
  --issuer $(az aks show -g rg-contoso-reservas-pro -n aks-contoso-operaciones \
      --query oidcIssuerProfile.issuerUrl -o tsv) \
  --subject system:serviceaccount:operaciones-vuelo:sa-operaciones \
  --audience api://AzureADTokenExchange

  1. Deploying the application with manifests and kubectl

Before the deployment you need the sa-operaciones service account in the operaciones-vuelo namespace, annotated with azure.workload.identity/client-id pointing at the client ID of id-contoso-api-pro. It is the in-cluster counterpart of the federated credential above.

apiVersion: apps/v1
kind: Deployment
metadata: { name: panel-operaciones, namespace: operaciones-vuelo }
spec:
  replicas: 3
  selector: { matchLabels: { app: panel-operaciones } }
  template:
    metadata:
      labels:
        app: panel-operaciones
        azure.workload.identity/use: "true"   # injects the federated token
    spec:
      serviceAccountName: sa-operaciones
      containers:
        - name: panel
          image: acrcontosopro.azurecr.io/panel-operaciones:4821
          ports: [ { containerPort: 8080 } ]
          resources:                          # section 8 explains why
            requests: { cpu: "250m", memory: "256Mi" }
            limits:   { cpu: "1000m", memory: "512Mi" }
          readinessProbe: { httpGet: { path: /salud, port: 8080 } }  # ready for traffic
          livenessProbe:  { httpGet: { path: /salud, port: 8080 } }  # alive; if not, restart
      topologySpreadConstraints:              # spreads the 3 replicas across the 3 zones
        - { maxSkew: 1, topologyKey: topology.kubernetes.io/zone,
            whenUnsatisfiable: DoNotSchedule,
            labelSelector: { matchLabels: { app: panel-operaciones } } }
---
apiVersion: v1
kind: Service
metadata: { name: svc-panel-operaciones, namespace: operaciones-vuelo }
spec:
  type: ClusterIP          # internal; the ingress is what publishes it
  selector: { app: panel-operaciones }
  ports: [ { port: 80, targetPort: 8080 } ]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: ing-operaciones, namespace: operaciones-vuelo }
spec:
  ingressClassName: webapprouting.kubernetes.azure.com
  rules:
    - host: operaciones.contosoairlines.example
      http:
        paths:
          - { path: /, pathType: Prefix,
              backend: { service: { name: svc-panel-operaciones, port: { number: 80 } } } }
  tls:
    - hosts: [ operaciones.contosoairlines.example ]
      secretName: tls-operaciones      # certificate synchronized from Key Vault

Field by field, what is not obvious:

  • The deployment's selector.matchLabels and the template's labels must match: that is the link between the deployment and its pods, and misaligning them leaves the deployment with no replicas. serviceAccountName plus the azure.workload.identity/use label are what activate the federation from section 5.
  • The image carries the tag 4821, the build identifier from the pipeline (05-03), never latest.
  • readinessProbe versus livenessProbe: the first controls whether the pod enters the load balancing; the second whether it gets restarted. Confusing them produces cascading restarts under load. And topologySpreadConstraints forces the three replicas to be spread across the three zones: without it, the scheduler can put all three on the same node.
  • type: ClusterIP: the service does not publish itself. Using LoadBalancer per service creates a public IP for each one and multiplies both cost and exposed surface.

Essential kubectl: kubectl apply -f manifiestos/ applies; kubectl get pods -n operaciones-vuelo -o wide lists with node and IP; kubectl describe pod <name> gives you the events, which is always where the cause of the failure is; kubectl logs -f <pod> follows the logs; kubectl rollout status deploy/panel-operaciones waits for the rollout and kubectl rollout undo reverts it; kubectl top pods shows real consumption, essential for tuning section 8.

  1. Managed ingress and certificates

Installing and maintaining an ingress controller by hand is recurring work. The application routing add-on deploys a managed NGINX and integrates it with DNS and Key Vault:

az aks approuting enable -g rg-contoso-reservas-pro -n aks-contoso-operaciones \
  --enable-kv --attach-kv $(az keyvault show -n kv-contoso-pro --query id -o tsv)

With that, the certificate for operaciones.contosoairlines.example lives in kv-contoso-pro, is synchronized as a Kubernetes Secret and renews itself without intervention. The certificate is never copied into a repository or a manifest.

  1. Scaling, requests and limits

Three scalers that are constantly confused:

Scaler What it does Signal
Horizontal pod autoscaler (HPA) Adds or removes replicas CPU, memory or a custom metric
Cluster autoscaler Adds or removes nodes Pending pods that do not fit
Virtual nodes Schedules pods on ACI, with no node Immediate bursts, without starting machines
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: hpa-panel, namespace: operaciones-vuelo }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: panel-operaciones }
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - { type: Resource,
        resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } } }

The first two scalers work as a chain: the HPA asks for more replicas, they do not fit, they stay pending and the cluster autoscaler starts nodes. And here is the key point of the whole lesson: the HPA calculates the usage percentage against the request (requests), and the scheduler decides where a pod fits by looking at its request. With no requests there is no percentage to calculate and no information to schedule with.

Requests and limits are the number one cause of unstable clusters. With no requests, the scheduler thinks the pod consumes nothing and piles pods onto a node until it is exhausted. With no memory limits, a leak in one pod eats the node's memory and the kernel starts killing processes: healthy pods with nothing to do with the problem go down. With CPU limits set too low, the pod is throttled and latency shoots up without CPU looking high at all.

The practical rule: set requests at the 50th-percentile consumption measured with kubectl top, and limits at around double that. Back it up with ResourceQuota and LimitRange in the namespace so that no manifest without limits ever gets applied.

  1. Upgrades, disruptions and maintenance

Kubernetes ships versions at a good pace and AKS supports only a few of them. Upgrading is not optional; it is a calendar task.

az aks get-upgrades -g rg-contoso-reservas-pro -n aks-contoso-operaciones -o table
az aks upgrade -g rg-contoso-reservas-pro -n aks-contoso-operaciones \
  --kubernetes-version 1.31.1 --control-plane-only          # the plane first
az aks nodepool upgrade -g rg-contoso-reservas-pro --cluster-name aks-contoso-operaciones \
  -n aplicaciones --kubernetes-version 1.31.1               # then each pool

Always upgrade the control plane first and the node pools afterwards, one at a time, and from one minor version to the next, with no jumps. Nodes are replaced by cordoning and draining, and that is where the pod disruption budget comes in, preventing the drain from taking a service below a minimum:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: pdb-panel, namespace: operaciones-vuelo }
spec:
  minAvailable: 2                       # the drain never leaves fewer than 2 replicas
  selector: { matchLabels: { app: panel-operaciones } }

Without it, a drain can take all three replicas at once and the operations dashboard disappears during the upgrade. Round it out with a planned maintenance window (az aks maintenanceconfiguration add) so that automatic node OS upgrades do not land in the check-in rush hour.

  1. Storage, observability, Helm and cost

A pod's disk is ephemeral. To persist, you declare a persistent volume claim against a storage class:

Class Backing Access Use at Contoso
managed-csi (and -premium) Azure Disk A single node Data for a single pod; the Premium variant for demanding I/O
azurefile-csi Azure Files (SMB/NFS) Several nodes at once Files shared between replicas

The decisive distinction is the access mode: an Azure Disk is mounted by a single node, so it is no use for three replicas spread across zones; for that you need Azure Files. And by default the reclaim policy is Delete: deleting the claim makes the disk and the data disappear. In production, Retain.

Observability is solved with Container Insights, already enabled in the az aks create against log-contoso-pro: node and pod metrics, container and control plane logs, all queryable with KQL. How to exploit them is module 7 (07-01 and 07-02); here it is enough to leave it switched on from the start, because nobody enables it in time once the cluster is already failing.

Helm, GitOps and realistic cost

Helm is the Kubernetes package manager: it packages a set of manifests into a chart with parameterized values, so that deploying to desarrollo and to produccion is the same chart with a different values file; it is to manifests what Bicep modules are to templates (05-06). GitOps with Flux is the natural next step: instead of the pipeline pushing with kubectl apply, an agent inside the cluster watches the contoso-infra repository and reconciles the cluster towards what Git says; the repository becomes the single source of truth and configuration drift corrects itself. AKS offers it as a managed extension.

Realistic cost. A production cluster like Contoso's, with 3 Standard_D4s_v5 system nodes and 2 to 12 Standard_D8s_v5 application nodes, plus the Standard tier, disks, load balancer and log ingestion, comes in at the order of several thousand euros a month, and Log Analytics ingestion surprises people more than anyone expects. How to bring it down:

  • Spot instances (az aks nodepool add --priority Spot --eviction-policy Delete --spot-max-price -1) in a dedicated pool for interruption-tolerant workloads — batch jobs, testing: up to 80-90% less, in exchange for an eviction with two minutes' notice.
  • Scaling user pools to zero with --min-count 0, and stopping the development cluster with az aks stop / az aks start: a stopped cluster does not bill for nodes. Automate it overnight and at weekends with Azure Automation (07-04).
  • Tuning requests to what is genuinely consumed: inflated requests force the autoscaler to start half-empty nodes. It is the least visible saving and often the biggest.

Common Mistakes and Tips

  • Adopting AKS without needing it: if Container Apps covers the case, AKS only adds bills and work. And deploying with no requests or limits, the number one cause of unstable clusters; enforce it with LimitRange.
  • Choosing Azure CNI without doing the IP arithmetic. The subnet runs out and expanding it forces you to rebuild the cluster. Use CNI Overlay.
  • Mixing application workloads into the system pool. A runaway pod takes down CoreDNS and the cluster with it.
  • Storing secrets as Kubernetes Secrets (base64 only) or putting a LoadBalancer Service on each microservice (twelve public IPs). Workload identity against kv-contoso-pro, and a single ingress with host-based routing.
  • Leaving the cluster un-upgraded: versions fall out of support and the accumulated upgrade becomes risky. Quarterly calendar.
  • Tip: kubectl describe pod before anything else. 90% of failures (ImagePullBackOff, CrashLoopBackOff, Pending for lack of resources) are explained in its events section. And apply network policies from the start: retrofitting them into a production cluster is painful.

Exercises

Exercise 1. An operations microservice stays in Pending state and the cluster autoscaler does not start any nodes. Its manifest asks for requests: { cpu: "8000m", memory: "32Gi" } and the aplicaciones pool uses Standard_D8s_v5 (8 vCPU, 32 GiB).

  1. Explain why the pod will never be scheduled and why the cluster autoscaler does not fix it by adding nodes.
  2. Give two different solutions and say which one you would choose.

Exercise 2. Design the cluster for the "Contoso Miles" platform: six microservices, daytime traffic and almost none at night, plus a nightly points recalculation process that tolerates interruptions.

  1. Define the node pools with their mode, size, zones and autoscaler bounds.
  2. Justify the use of spot instances and their risks, state the mandatory tags for the secondary project and two additional cost-saving measures.

Exercise 3. A pod has to read a secret from kv-contoso-pro and query db-reservas.

  1. List the steps to achieve that with no credential in the cluster, and explain the relationship between the OIDC issuer, the service account and id-contoso-api-pro.
  2. Why is it better than mounting a Kubernetes Secret with the connection string?

Solutions

Solution 1:

  1. Because the request consumes the whole node, and the operating system, the kubelet and the system add-ons already reserve a share: the allocatable capacity of a Standard_D8s_v5 is less than 8 vCPU and 32 GiB, so no node of that size has room. The autoscaler only starts nodes if the pod would fit on a new node in the pool; since it does not fit, it concludes that adding nodes is useless and does nothing. That is correct behavior, even if the silence is confusing.
  2. (a) Reduce the request to what it genuinely consumes, measured with kubectl top — 4 vCPU and 16 GiB, for example. (b) Create a node pool with larger machines, of the Standard_E16s_v5 kind, and steer the pod there with nodeSelector. I would go for (a) first, because the request is almost always inflated "just in case"; (b) only if the measurement confirms that the workload genuinely needs that size.

Solution 2:

  1. A sistema pool in System mode, 2 Standard_D2s_v5 nodes, zones 1-2-3, autoscaler from 2 to 3. An aplicaciones pool in User mode, Standard_D4s_v5, zones 1-2-3, autoscaler from 2 to 8 during the day. A lotes pool in User mode with --priority Spot, Standard_D8s_v5, autoscaler from 0 to 6, with its corresponding taint so that only the nightly process gets scheduled there.
  2. The points recalculation is idempotent, resumable and has no user waiting on it: if Azure evicts a node with two minutes' notice, the job is rescheduled and only time is lost, in exchange for an enormous saving. The real risk is using spot instances for online services, where an eviction translates into errors for the user; that is why the pool is separate and tainted. Tags: entorno, proyecto=contoso-millas, centro-coste=CC-2077 and propietario. Additional savings: scale the lotes pool to zero outside the nightly window and stop the development cluster with az aks stop from a runbook overnight and at weekends.

Solution 3:

  1. (a) Create the cluster with --enable-oidc-issuer --enable-workload-identity. (b) Create the sa-operaciones service account in operaciones-vuelo, annotated with the client ID of id-contoso-api-pro. (c) Create the federated credential with az identity federated-credential create and the subject system:serviceaccount:operaciones-vuelo:sa-operaciones. (d) Give id-contoso-api-pro the Key Vault Secrets User role on kv-contoso-pro and create the external user in db-reservas. (e) In the pod, serviceAccountName and the azure.workload.identity/use: "true" label, and in the code, DefaultAzureCredential. As for the relationship: the cluster's OIDC issuer signs the service account's token and the federated credential declares to Entra ID that that specific issuer and that specific subject may obtain tokens for id-contoso-api-pro; the trust is cryptographic, not a shared password.
  2. Because a Kubernetes Secret is base64-encoded, not encrypted: anyone who can read it in the namespace, or who gets hold of an etcd backup, reads it in the clear. On top of that it has to be rotated by hand in every cluster. With workload identity the secret does not exist: there are short-lived tokens issued and revocable from Entra ID, with traceability in the sign-in logs.

Conclusion

Kubernetes stops being a word and becomes a tool with a criterion for use. You know when it is justified and when it is over-engineering, and you have seen Contoso adopt it only for the flight operations platform while the availability engine stays quite happily on Container Apps. You handle the essential concepts — control plane and nodes, pod, deployment, replica, service, ingress, namespace, ConfigMap and Secret — and you understand the reconciliation loop that holds them up. You are clear about the responsibility boundary: the control plane is free, the nodes are paid for, and upgrades, limits and policies remain yours.

You have created aks-contoso-operaciones with separate system and user pools, availability zones, cluster autoscaler, CNI Overlay so as not to exhaust the subnet, network policy, Entra ID integration and Azure RBAC per namespace, image pulls from acrcontosopro with --attach-acr, and workload identity that gives pods access to kv-contoso-pro and db-reservas without a single secret. You have deployed with manifests explained field by field, published with the application routing add-on and Key Vault certificates, and you know how to use kubectl to diagnose. You have mastered the three scalers and, above all, why the absence of requests and limits is the number one cause of unstable clusters. You know how to upgrade in the right order while protecting availability with disruption budgets and maintenance windows, how to persist with disks versus Azure Files depending on the access mode, and how to leave Container Insights on from minute one. And you know the maturity path — Helm, GitOps with Flux — and the real cost with its levers: spot instances, pools that scale to zero, stopping the development cluster and tuning requests.

Contoso now has two ways of running its own code and a reasonable doubt: for many tasks, keeping something running is absurd. Generating the PDF of a boarding pass takes two seconds and happens when a booking is confirmed; synchronizing the fare catalog happens when a document changes in cosmos-contoso-tarifas-pro. For that you do not want a container waiting or a pod switched on, you want the code to run when something happens and not to exist the rest of the time. That is serverless computing, and the next lesson, Azure Functions, takes it in detail: triggers and bindings, hosting plans, Contoso's two real functions, Durable Functions for orchestrating check-in, and the hard lesson nobody gets to skip — idempotency.

Azure Course

Module 1: Introduction to Azure

Module 2: Core Azure Services

Module 3: Azure Databases

Module 4: Security in Azure

Module 5: Azure DevOps

Module 6: Advanced Azure Services

Module 7: Monitoring and Management

Module 8: Cost Management and Optimization

Module 9: Case Studies and Best Practices

© Copyright 2026. All rights reserved