SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
Deploy and manage Azure compute resources

Provision and Manage Containers in Azure (AZ-104)

22 min readAZ-104 · Deploy and manage Azure compute resourcesUpdated

Azure gives you three ways to work with containers without building your own Kubernetes cluster, and the AZ-104 exam expects you to pick the right one and configure it. Azure Container Registry (ACR) is your private registry: it stores the container images you push, build or import, and your services pull from it. Azure Container Instances (ACI) is the fastest way to run a single container or a small container group: it is serverless, billed per second for the resources you request, and ideal for short, isolated tasks with no orchestration. Azure Container Apps runs serverless containers that scale automatically, including scale-to-zero, behind managed ingress with revisions, making it the natural home for microservices and event-driven workloads. This lesson shows you how to create and secure an ACR, provision and configure containers with ACI and Container Apps, size and scale each service, and decide between ACI, Container Apps, and AKS for a given workload.

What you’ll learn
  • Create and manage an Azure Container Registry: choose a tier, get images into it, and pick a least-privilege authentication method
  • Provision Azure Container Instances with the right restart policy, networking, configuration and volumes
  • Deploy a Container App and control its environment, ingress and revisions
  • Configure sizing and scaling for Container Instances and Container Apps, including which ACI changes need a redeploy
  • Choose between ACI, Container Apps, AKS and App Service for a given workload

Three ways to run containers on Azure

Before you deploy anything, you need to know what each Azure container service is for, because the exam tests the decision as much as the steps. All three services run OCI-compliant container images, but they solve different problems.

Azure Container Registry (ACR) is not a place to run containers; it is a private, managed registry that stores your images so your compute services can pull them. Almost every container workload starts by pushing an image to ACR.

Azure Container Instances (ACI) is the simplest way to run a container. You give it an image, a CPU and memory size, and it starts in seconds. There is no cluster and no orchestration, so it suits short-lived, isolated, or bursty tasks.

Azure Container Apps is a serverless platform for running containers that need to scale. It adds automatic scaling (including scaling to zero), HTTPS ingress, and revisions, so it fits microservices, APIs, and event-driven jobs without you managing any Kubernetes.

For heavier needs there is Azure Kubernetes Service (AKS), a fully managed Kubernetes cluster, but on AZ-104 you keep AKS at recognition level and focus on ACR, ACI, and Container Apps. Think of it as registry, run-it-once, and scale-it: that mental model answers most questions.

Create and manage an Azure Container Registry (ACR)

Azure Container Registry is a fully managed, private registry for storing and distributing container images and related artifacts. You create one from the portal with Create a resource > Containers > Container Registry, giving it a globally unique name; its login server becomes <name>.azurecr.io, and every image in it is addressed as <name>.azurecr.io/<repository>:<tag>.

Service tiers

ACR comes in three service tiers (SKUs). All three support the same core registry operations, Microsoft Entra authentication and repository-scoped tokens; they differ in included storage, throughput and a set of Premium-only features. You can change tier at any time without downtime.

TierBest forNotable features
BasicLearning and small workloadsLowest cost, least included storage and throughput
StandardMost production workloadsMore storage and throughput than Basic
PremiumHigh-scale, network-restricted or multi-region registriesHighest throughput, geo-replication, private endpoints (Private Link) and public-network IP rules, dedicated data endpoints

Zone redundancy is not a Premium feature any more. Microsoft now makes every registry zone-redundant automatically, in every tier, in regions that support availability zones. Zone redundancy protects against a datacenter failure within one region; it does nothing for slow pulls from a distant region or for a whole-region outage. Those needs are met by geo-replication (Premium): one registry name, one push, with replicas in each region you add so each region pulls locally and keeps pulling if another region fails.

Use a private endpoint (Premium) when the registry must be reachable only on a private IP in your virtual network, with public network access disabled. When clients sit behind a strict firewall and cannot use Private Link, dedicated data endpoints (Premium) help: image layers normally download from a broad *.blob.core.windows.net storage domain, but with dedicated data endpoints enabled they come from <registry>.<region>.data.azurecr.io, one per region where the registry has a replica. The firewall then allows only the login server and those data endpoints instead of opening every Azure storage account.

Older material also lists content trust (Docker Content Trust, for signed images) as a Premium feature. Microsoft is retiring it: since 31 May 2026 it cannot be enabled on registries that did not already use it, and it will be removed on 31 March 2028. Image signing now uses the Notary Project instead.

Getting images into the registry

There are three ways to put an image into ACR, and the right one depends on where the image is and whether Docker is available:

  • Push a local image. Sign in with az acr login --name <name>, then docker tag the local image with the fully qualified name (<name>.azurecr.io/repo:tag) and docker push that name. Docker uses the registry host in the image name to decide where to push, so an image tagged without the login server goes nowhere useful.
  • Build in Azure with az acr build. ACR Tasks builds the image from a Dockerfile and build context you upload, then pushes the result to the registry. No local Docker daemon is needed, which is why it works from Azure Cloud Shell or a lightweight build agent.
  • Copy from another registry with az acr import. Import copies an existing image from Docker Hub, another ACR or another public or private registry straight into yours, server-side, without pulling it to your machine. It does not build anything.

Authentication and least privilege

Choose the authentication method by who the client is and how little access it needs:

MethodWhat it isWhen to use it
Admin userOne built-in username with two passwords, granting full push and pull on the whole registry; disabled by defaultTesting only; avoid in production because it is a shared, registry-wide stored secret
Microsoft Entra identity + RBACUsers, groups or service principals assigned roles such as AcrPull (pull only) or AcrPush (pull and push)People and pipelines; give AcrPull to anything that only runs images
Managed identity + AcrPullAn Azure resource's own identity (ACI, Container Apps, App Service, an AKS kubelet identity) granted AcrPullAzure workloads that pull images with no stored credential at all
Repository-scoped tokenA token with passwords, linked to a scope map that lists repositories and actions (content/read, content/write, content/delete, metadata actions)Clients outside Microsoft Entra (an external partner, an IoT device) that must reach only specific repositories

A service principal with AcrPull is least-privilege but still authenticates with a client secret or certificate that someone must store and rotate; a managed identity removes that secret entirely. For AKS, az aks update --attach-acr <registry> (or --attach-acr at cluster creation) assigns AcrPull on the registry to the cluster's kubelet managed identity, so nodes pull without any image pull secret.

Tokens are available in every tier. To push, a token's scope map needs both content/read and content/write on the repository (a push reads existing layers too). The built-in system scope maps (_repositories_pull, _repositories_push, _repositories_admin) apply to every repository, so single-repository access needs a custom scope map. Disabling or deleting one token revokes just that client.

Provision a container with Azure Container Instances (ACI)

Azure Container Instances is the quickest path from an image to a running container. You create a Container instance resource, point it at an image in ACR (or a public registry), set the number of CPU cores and amount of memory (GB), and Azure starts it in seconds: no VM to patch and no orchestrator to configure. ACI runs both Linux and Windows containers, although Windows is limited to single-container groups and cannot mount volumes (VNet deployment works for both).

Billing

ACI bills per second, for the vCPU and memory a container group requests, from the moment its image starts pulling until the group stops. The charge is on the allocation, not on measured utilisation: a group that requests 2 vCPUs and 4 GB pays for 2 vCPUs and 4 GB even if the application idles at a fraction of that. Right-sizing the request is therefore the main cost lever, and a run-to-completion job that stops (restart policy OnFailure or Never) stops billing.

Restart policy

The restart policy is set once per container group and applies to all its containers:

PolicyBehaviourUse it for
Always (default)Restarts a container whenever it exits, whatever the exit codeLong-running services such as web APIs
OnFailureRestarts only on a non-zero exit code; a clean exit (code 0) ends the runBatch jobs that should retry on error but run once on success
NeverNever restarts; the container runs at most onceJobs that must not be retried automatically

A service deployed with OnFailure or Never stays down after it exits, because OnFailure ignores a clean exit and Never ignores every exit. The restart policy cannot be changed on an existing group: you delete and recreate it (see sizing and updates below).

Container groups

A container group is the unit ACI schedules: a collection of containers placed on the same host that start and stop together and share one IP address and port namespace and any mounted volumes, similar to a Kubernetes pod. Containers in a group reach each other over localhost on their ports, which makes the sidecar pattern (a log shipper or proxy beside the app) natural; two containers in one group cannot both listen on the same port. The host provides the sum of each container's CPU and memory requests. Multi-container groups are Linux-only and are deployed from a YAML file (az container create --file) or an ARM/Bicep template; the portal's create wizard deploys a single container.

Networking and DNS

A group gets either a public IP or a private address in a virtual network:

  • Public: add a DNS name label to get a stable host name under <region>.azurecontainer.io. The public IP itself is not guaranteed to survive a restart or redeploy, so clients should use the name. The DNS name label scope reuse policy (tenant, subscription, resource group, no reuse, or any reuse) controls who can claim the same label later; every policy except any reuse appends a generated hash to the label in the FQDN, which protects against someone else taking over a deleted name.
  • Virtual network: deploy the group into a delegated subnet to reach private resources such as a VM on its private IP. A VNet-deployed group cannot have a public IP or a DNS name label. To publish it to the internet, put an Application Gateway (or a Standard Load Balancer) with a public frontend in front of it; outbound traffic must go through a NAT gateway on the subnet (the only supported outbound configuration), which also gives the group a fixed public outbound IP.

Attach a managed identity with AcrPull so the group can pull from ACR without stored credentials. ACI does not autoscale; it runs exactly what you deploy. Choose it for simple, isolated, or bursty tasks that need no orchestration.

ACI configuration, secrets and volumes

ACI gives you three ways to hand configuration to a container, and the right one depends on whether the value is sensitive and whether the application expects a variable or a file. Volumes, in turn, decide whether data survives the container group.

OptionWhat the app seesVisibility and notes
Environment variable (value)An environment variableShown in the portal and returned by az container show; fine for non-sensitive settings
Secure environment variable (secureValue)An environment variableValue is hidden from the portal and the API output; use it for a connection string or password the app reads from its environment
Secret volumeFiles in a mounted directoryLinux only; read-only; backed by tmpfs (RAM), so values are never written to disk; use it for certificates, keys or config files

ACI volume types and how long their data lives:

VolumeLifetimeTypical use
Azure Files shareIndependent of the group: data stays in the storage account after the group is deletedPersistent output, state, shared files
emptyDirLives as long as the group; survives a container restart but not group deletionScratch space shared between containers in the group
gitRepoCloned at deployment; tied to the groupPulling a Git repository into the container at startup
SecretTied to the group; held in memorySensitive files

Mounting an Azure Files share has three constraints worth knowing: it is supported only for Linux containers, the deployment must supply the storage account name and storage account key, and the container must run as root. It is the only ACI volume whose data outlives the container group, so it is the answer whenever output must be available after the group is deleted or redeployed.

Provision a container with Azure Container Apps

Azure Container Apps is a serverless container platform for applications that need to scale and talk to each other. It is built on Kubernetes, KEDA, Dapr, and Envoy, but Microsoft manages all of that for you: you never create or patch a cluster. It runs Linux (linux/amd64) container images only. You provision a Container App inside a Container Apps environment (a secure boundary that apps share, typically sending logs to a Log Analytics workspace and optionally placed in your own virtual network), choose an image, and set CPU and memory.

Its defining feature is automatic scaling driven by scale rules: Container Apps adds or removes replicas between a minimum and maximum based on HTTP traffic, TCP connections, CPU or memory, or KEDA event sources such as the length of a queue, and with the right rules it scales to zero (details in the sizing section). It also provides built-in ingress with automatic HTTPS certificates and load balancing, and revisions, immutable snapshots of a version that you can split traffic across and roll back to. Together these make Container Apps the right choice for microservices, background processors, and event-driven workloads that a single ACI container cannot scale to handle.

Container Apps environments and ingress

Who can reach a container app is decided at two levels: the environment, chosen once when you create it, and each app's ingress, which you can change at any time.

SettingOptionsEffect
Environment virtual networkDefault (Azure-managed) or a custom virtual networkFixed at creation. A custom VNet is required to make the environment internal and to use external TCP ingress
Environment accessibilityExternal (public endpoint) or Internal (private IP in your VNet only)Fixed at creation. An internal environment has no public endpoint, so no app in it is reachable from the internet
App ingress trafficAccepting traffic from anywhere or limited to the Container Apps environment"Anywhere" exposes the app on the environment's endpoint (the internet for an external environment, the VNet for an internal one). "Limited to the environment" (internal app ingress) lets only other apps in the same environment call it; requests from elsewhere in the network, including peered VNets, get HTTP 404

So an API that must be private to the network but callable by VMs in a peered VNet needs an internal environment plus app ingress accepting traffic from anywhere; internal app ingress would hide it from those VMs.

When you enable ingress you set the target port: the port the container actually listens on (for example 8080). Clients still connect on the standard ports, 443 for HTTPS (80 redirects to it by default), and Envoy forwards to the target port. Ingress is HTTP by default; TCP ingress serves non-HTTP protocols such as MQTT or a database wire protocol. External TCP ingress, and extra exposed TCP ports, require an environment with a custom virtual network, so if the environment was created without one you must create a new environment and redeploy the app there.

Container Apps revisions and traffic splitting

A revision is an immutable snapshot of a container app's template; changing the template creates a new revision. How revisions share traffic depends on the revision mode. The two generally available modes are (a newer deployment-labels mode is in preview):

  • Single revision mode (the default): only one revision is active. A new revision replaces the old one once it is ready, so you cannot split traffic.
  • Multiple revision mode: several revisions stay active and you assign traffic weights (for example 90/10 for a canary, then 0/100 to complete the rollout or back to roll back). Blue-green and canary releases need this mode.

Not every change creates a revision. Revision-scope changes (the container image, CPU and memory, environment variables, scale rules and other template properties) produce a new revision. Application-scope changes (secrets, ingress settings, traffic weights, revision mode, credentials and labels) apply to the app as a whole and create no revision. One consequence matters in practice: after you update a secret, running replicas keep the old value until you restart the revision or deploy a new revision.

A revision label gives a specific revision its own stable URL, independent of traffic weights. Move the label to a newer revision and the URL follows it, which suits a QA or preview endpoint while public traffic stays on the current revision (the revision's own URL changes with every revision, the label's does not).

ACI vs Container Apps vs AKS: choosing the right service

The most common container question on AZ-104 is which service fits this workload. The answer hinges on how much scaling and orchestration you need versus how much control and operational effort you are willing to take on.

AspectContainer Instances (ACI)Container AppsKubernetes Service (AKS)
ModelSingle container or container groupServerless microservices platformFull managed Kubernetes cluster
Operating systemsLinux and Windows (Windows: single-container groups)Linux (linux/amd64) onlyLinux and Windows node pools
ScalingNone (fixed size)Autoscale, including scale-to-zeroAutoscale via Kubernetes and node pools
OrchestrationNoneManaged (KEDA, Dapr, revisions)Full Kubernetes API and control
Operational effortLowestLowHighest
Best forShort, isolated, bursty tasksAPIs, microservices, event-driven appsComplex workloads needing full Kubernetes

Read the scenario for signals. Run a single container quickly with no orchestration, or a Windows container job, is ACI. Serverless containers that scale to zero and handle variable traffic or events is Container Apps. Full control over Kubernetes, custom operators, or an existing Helm and YAML estate is AKS. Cost follows the same logic: ACI bills per second for what each group requests while it runs, Container Apps bills for replicas in use (nothing at zero on the Consumption plan), and AKS bills for the cluster nodes you keep running.

App Service can also run a custom container (covered in the App Service lesson) and brings managed HTTPS, custom domains and deployment slots, but an App Service plan always keeps at least one instance running, so it cannot scale to zero. When idle cost must drop to nothing, Container Apps is the fit. For AZ-104, ACI and Container Apps carry the weight; recognize AKS but reach for the simpler managed option unless the scenario explicitly demands raw Kubernetes.

Sizing and scaling containers

Sizing and scaling work differently in each service, and the exam expects you to know which knobs exist and which changes need a redeploy.

Container Instances: fixed requests, limited in-place updates

For Azure Container Instances, sizing is a fixed request: you specify CPU cores and memory in GB for each container, and the group's host provides the sum. ACI has no autoscaling; for more capacity you deploy more container groups yourself. You update a running group by redeploying it with the same name (az container create again, or the same YAML/template), but only some properties can change that way:

Update in place (redeploy with the same name)Requires delete and recreate
Container image or tag, environment variables, DNS name label, and similar container settingsCPU and memory resources, OS type, restart policy, availability zone

An in-place update restarts the containers. Resizing a group therefore means deleting it and creating it again with the new values.

Container Apps: per-container allocations and workload profiles

In Azure Container Apps you set CPU and memory per container, but on the Consumption plan the total across all containers in the app (main container plus sidecars and init containers) must be one of the allowed pairs: vCPU in 0.25 steps with memory at twice the vCPU in Gi (0.25/0.5Gi, 0.5/1.0Gi, … up to 4 vCPU/8Gi; a Consumption-only environment tops out at 2 vCPU/4Gi). Adding a sidecar means choosing its allocation so the new total is still a valid pair.

A workload profiles environment offers two kinds of profile. The Consumption profile is serverless and billed per replica for what it uses. Dedicated profiles (general-purpose D-series and memory-optimized E-series sizes, plus GPU options) run on compute reserved for your environment, billed per node, and allow much larger replicas; choose Dedicated when replicas need more than the Consumption limits or the team wants predictable, reserved capacity.

Container Apps: scale rules and limits

Every app has a minimum and maximum replica count. The defaults are min 0 and max 10; the maximum can be raised (up to 1,000). Between them, scale rules add and remove replicas: HTTP (concurrent requests per replica), TCP (concurrent connections), custom rules backed by KEDA scalers (for example azure-servicebus on queue length, or an Azure Storage queue), and CPU or memory utilization.

  • Scale to zero needs min replicas 0 and an HTTP, TCP or event-driven rule. CPU and memory rules cannot scale to zero, because there is no replica left to measure.
  • Cold starts: with min 0 the first request after an idle period waits while a replica starts. Set min replicas to 1 or more to keep a replica warm (at a cost).
  • Hitting the ceiling: if the revision runs at its maximum and requests still queue, raise the maximum replica count.

The practical rule: if a workload has steady, predictable demand or runs once and stops, size it with ACI. If demand rises and falls, such as spiky web traffic or a queue that fills and drains, let Container Apps scale it. Adding or removing replicas automatically by traffic or queue length is a Container Apps scale rule; ACI has no equivalent.

Admin scenario: a nightly batch job and an autoscaling API

Consider two workloads in the same subscription, both using images stored in your Azure Container Registry.

Workload one: a nightly batch job. Every night a container must download files, transform them, and exit. It runs for a few minutes and does nothing the rest of the day, and it needs no scaling or ingress. This is a textbook fit for Azure Container Instances. You deploy a container instance sized to, say, 2 CPU and 4 GB, pull the image from ACR using a managed identity, and set the restart policy to OnFailure so it retries on error and stops when finished. Because ACI bills per second, you pay only for the few minutes it runs, with no idle cost and nothing to orchestrate.

Workload two: a public REST API. This service faces the internet, gets almost no traffic overnight, and spikes during business hours. Here you choose Azure Container Apps. You deploy the API with external HTTPS ingress, set the minimum replicas to 0 so it costs nothing when idle, and add an HTTP scale rule so replicas grow with concurrent requests and shrink again afterward. When you ship a new version, you release a new revision and split traffic to it, rolling back instantly if needed. Same registry, two workloads, two correctly chosen services.

Tip. Expect scenario questions that make you choose a container service from the wording, then configure it. Run a single or Windows container briefly with no orchestration points to Container Instances; scale to zero, revisions or event-driven scaling point to Container Apps. For ACR, know the Premium-only features, the tag-and-push, build and import paths, and the least-privilege authentication choice. For ACI, know restart policies, volume types, secure environment variables, VNet limits and which changes need delete-and-recreate. For Container Apps, know environment versus app ingress, revision modes and labels, Consumption sizing pairs and Dedicated profiles, and why some scale rules cannot reach zero.

Key takeaways
  • Choose ACI to run a container briefly with no orchestration, Container Apps for managed containers that autoscale (including to zero) with revisions, App Service for web apps that need slots, and AKS only when you need full Kubernetes control.
  • ACR stores images; push a local image by tagging it with the login server (<name>.azurecr.io/repo:tag), use az acr build when there is no local Docker, and az acr import to copy an existing image from another registry.
  • Every ACR tier is zone-redundant in supporting regions; geo-replication, private endpoints and dedicated data endpoints are Premium-only.
  • For ACR access, a managed identity with AcrPull is the passwordless least-privilege pull; repository-scoped tokens with scope maps serve clients outside Microsoft Entra; the admin user is for testing only.
  • ACI bills per second on requested vCPU and memory; restart policy Always suits services, OnFailure retries failed jobs, Never runs once; CPU, memory, OS type and restart policy changes need delete and recreate.
  • In ACI, secure environment variables hide values from the portal and API, secret volumes deliver files from RAM, and only Azure Files (Linux, storage key) persists data beyond the container group.
  • A VNet-deployed ACI group has no public IP or DNS label; publish it through Application Gateway or a load balancer, and send its outbound traffic through a NAT gateway.
  • Container Apps: internal vs external environment and custom VNet are fixed at creation; app ingress limited to the environment hides an app from the VNet; external TCP ingress needs a custom VNet.
  • Container Apps scale between min 0 and max 10 replicas by default; CPU and memory rules cannot scale to zero; traffic splitting needs multiple revision mode, and secret changes need a revision restart.

Frequently asked questions

What is the difference between Azure Container Instances and Container Apps?

Azure Container Instances (ACI) runs a single container or container group with a fixed CPU and memory size, no autoscaling, and per-second billing, which suits short, isolated, or bursty tasks. Azure Container Apps is a serverless platform that scales containers automatically using scale rules (including scale-to-zero), adds HTTPS ingress and revisions, and is built for microservices and event-driven apps. Use ACI to run something once quickly; use Container Apps when the workload must scale.

What is Azure Container Registry used for?

Azure Container Registry (ACR) is a private, fully managed registry that stores and distributes your container images and related artifacts. You get images into it by tagging a local image with the registry login server and running docker push, by building in Azure with az acr build, or by copying from another registry with az acr import. Azure Container Instances, Container Apps, App Service and AKS then pull from it, ideally with a managed identity that holds the AcrPull role. It comes in Basic, Standard and Premium tiers; Premium adds geo-replication, private endpoints and dedicated data endpoints.

When should I use Azure Container Apps instead of AKS?

Choose Azure Container Apps when you want serverless containers that autoscale (including to zero) with managed ingress and revisions, and you do not want to operate a cluster. Choose Azure Kubernetes Service (AKS) when you need full control over the Kubernetes API, custom operators, node pools, or an existing Helm and YAML estate. On AZ-104, Container Apps is usually the right managed answer unless the scenario explicitly requires raw Kubernetes.

How does billing work for Azure Container Instances?

Azure Container Instances bills per second for the vCPU and memory each container group requests, from when the image starts pulling until the group stops. You pay for the allocation, not for measured usage, so a group that requests more CPU or memory than the application uses still pays for the full request. A run-to-completion job with a restart policy of OnFailure or Never stops, and stops billing, once its work is done.

How do Azure Container Apps scale to zero?

An Azure container app scales to zero when its minimum replica count is 0 (the default) and it scales on an HTTP, TCP or event-driven rule, such as a KEDA rule on Service Bus queue length. When there is no traffic or no events, it runs no replicas and incurs no compute cost on the Consumption plan, then starts a replica on the next request or event, which adds a short cold start. CPU and memory scale rules cannot scale an app to zero, and setting the minimum to 1 keeps one replica warm.

Can you change the CPU and memory of a running Azure Container Instances group?

No. In Azure Container Instances, CPU and memory, the OS type and the restart policy cannot be changed on an existing container group; you delete the group and create it again with the new values. Other settings, such as the container image tag, environment variables and the DNS name label, can be updated by redeploying the group with the same name, which restarts its containers.

How do I split traffic between versions of an Azure container app?

Switch the container app to multiple revision mode, deploy the new version as a new revision, and assign traffic weights to the revisions, for example 90 percent to the current revision and 10 percent to the new one. In the default single revision mode only one revision is active, so traffic cannot be split. To give testers a stable URL for a specific revision without sending it public traffic, assign that revision a label.

How do I keep an Azure container app off the public internet?

Create the Container Apps environment with a custom virtual network and internal accessibility, which gives the environment only a private IP address in your virtual network; this choice is fixed when the environment is created. Then set the app ingress to accept traffic from anywhere so clients in the virtual network and connected networks can reach it. If you instead limit ingress to the Container Apps environment, only other apps in the same environment can call it.

Source

This lesson covers the "Deploy and manage Azure compute resources" domain of the official AZ-104 exam guide. Vendors revise their guides — check the source for the current version.

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?