Microsoft Azure Services and Architecture Questions
Microsoft Azure's core service catalog and architectural patterns: Virtual Machines, managed Kubernetes (AKS), App Service and Azure Functions, Storage accounts and managed disks, Azure SQL and Cosmos DB, VNets with hybrid connectivity and global load balancing, Microsoft Entra ID and RBAC, and Key Vault secrets and encryption. Covers Azure service selection, infrastructure as code (ARM, Bicep, Terraform), observability with Azure Monitor and Kusto queries, cost governance and Azure Policy, the Azure Well-Architected design principles, and hybrid management via Azure Arc, common in enterprise Azure estates. For provider-agnostic trade-offs, see the cross-cloud entries.
Compare Azure Functions hosting plans: Consumption, Premium, and Dedicated (App Service Plan). For a bursty event-driven API with sensitivity to cold starts and a need for VNet access, which hosting plan would you recommend and what mitigations would you apply to reduce cold-start impact?
Sample Answer
Direct answer
For a bursty, event-driven API that is sensitive to cold starts and needs Virtual Network (VNet) access, recommend Flex Consumption, the current recommended plan for new serverless Azure Functions apps, sized with a small number of always-ready instances to cover baseline traffic. If the workload's language or region isn't yet supported on Flex Consumption, fall back to Premium with a minimum instance count of at least 1. The older Consumption plan is disqualified outright: it doesn't support outbound virtual network integration at all, so it can't meet the VNet requirement no matter how cold starts are handled.
Hosting plan comparison
| Plan | Scaling model | Cold starts | VNet | Cost model |
|---|---|---|---|---|
| Consumption (legacy) | Fully event-driven autoscale from zero | Expected on every scale-from-zero instance, with no always-ready option to avoid it | Not supported: the plan has no outbound VNet integration at all | Pay per execution only |
| Flex Consumption (current default) | Event-driven autoscale, plus configurable "always ready" instances | Eliminated for traffic within the always-ready capacity; burst instances beyond it still cold-start | Native, no extra hop | Pay per execution, plus cost for always-ready instances |
| Premium (Elastic Premium) | Pre-warmed instances (a configurable minimum count) plus autoscale for bursts | Eliminated on the pre-warmed capacity | Full support | Billed for pre-warmed capacity continuously, plus scale-out usage |
| Dedicated (App Service Plan) | Runs on VM capacity you already pay for; not autoscaled for event volume unless you add App Service autoscale rules | None, as long as "Always On" is set | Full support | Continuous VM cost regardless of function invocations; idle capacity is wasted spend |
Cold-start mitigations, regardless of plan
- Keep the deployment package small and the dependency tree lean; fewer assemblies or packages to load on a cold instance means a shorter cold start.
- Keep the function app's own startup code (static constructors, dependency-injection container setup) minimal, since it reruns on every cold start.
- The legacy Consumption plan cannot be paired with VNet integration at all, since the plan doesn't support it; move VNet-plus-cold-start-sensitive workloads to Flex Consumption or Premium instead.
- If stuck on Consumption for now, a scheduled timer-triggered "warm-up" ping is a workaround, not a fix; treat it as temporary.
Worked example
A payment-webhook receiver expects a steady 5 requests/second baseline and bursts to 200 requests/second for a few minutes at a time, with a hard requirement that outbound calls to a Key Vault (Azure's managed service for storing secrets, keys, and certificates) and a database go through a private VNet. Configure Flex Consumption with an instance memory size of 2048 MB and an always-ready instance count sized to comfortably absorb the 5 requests/second baseline, so steady traffic never cold-starts. Let the 200 requests/second burst scale out on top of that; the newly spun-up burst instances, not the always-ready ones, absorb the cold-start cost. If even burst traffic can't tolerate a cold start, size the always-ready count closer to the burst peak instead, which trades cost for latency consistency.
Trade-offs and pitfalls
- Premium and Flex Consumption both cost money at zero traffic once you configure pre-warmed or always-ready capacity, so "serverless" here is a spectrum, not a binary; sizing that capacity to the true peak defeats the pay-per-use benefit that made a consumption model attractive in the first place.
- Sizing always-ready or minimum instances too low reproduces the exact cold-start problem the plan change was meant to solve; validate against real traffic percentiles, not the average.
- Legacy Consumption has no outbound VNet integration at all, so it is disqualified immediately for any VNet-plus-cold-start-sensitive scenario, not merely a slower option; don't reach for it out of familiarity.
Design a secure cross-tenant integration for APIs between two organizations' Azure AD tenants that requires least-privilege access and auditability. Explain options using service principals, managed identities, Azure AD B2B invitations, or application proxying, and detail token flows, consent, and monitoring approaches.
Sample Answer
Direct answer
For machine-to-machine API access between two organizations' tenants, the least-privilege, most auditable option is a service principal in the resource tenant, granted access via an Entra ID app registration (Entra ID is Microsoft's cloud identity and access-management service, the directory that holds an organization's users, registered applications, and permission grants; it is the current name for Azure Active Directory, or Azure AD, so an Azure AD tenant and an Entra ID tenant are the same thing under different names) with admin-consented, tightly-scoped API permissions, not a shared user account and not a broad B2B guest invitation. Two terms are doing real work here and are worth pinning down up front: an app registration is the definition of an application in Entra ID, the record saying "this app exists, and here is what it is allowed to ask for"; a service principal is the actual identity created from that definition inside a given tenant, the object that can actually authenticate and be granted permissions there, roughly the difference between a class and an instance of it. B2B guest invitations are the right tool when a person at the partner organization needs interactive access; managed identities only work within a single tenant's own resources and can't authenticate across a tenant boundary at all, which rules them out for this specific ask despite being the default choice for same-tenant service-to-service calls.
Options and where each fits
| Option | Fits when | Doesn't fit when |
|---|---|---|
| Service principal (app registration, tenant A's app registered and consented in tenant B) | Machine-to-machine API access, least privilege via app roles, fully auditable via sign-in logs | A human at the partner needs interactive access to a portal or app UI |
| Managed identity | Never, across tenants: managed identities are tenant-local by design and cannot be assigned permissions in a different tenant | Any cross-tenant scenario at all |
| Microsoft Entra B2B (guest invitation) | A named person at the partner organization needs to sign into tenant A's own resources with their home tenant's credentials | Machine-to-machine, unattended API access, since it's built around a signed-in user session |
| Application proxy / API gateway with its own auth layer | Neither side wants to register an app in the other's tenant at all (e.g., a lower-trust integration), and you're willing to own a separate auth boundary (API keys, mutual TLS) instead of using Entra ID token flows directly | You want native Entra ID auditability and conditional access to apply to the cross-tenant calls, which an out-of-band API key doesn't get you |
Design: service principal, client credentials flow
- Tenant B (the resource owner, the organization exposing the API) registers an app representing the API itself, and defines app roles (not delegated scopes, since there's no signed-in user) representing the specific permissions a caller can be granted, e.g.
Orders.Read, scoped as narrowly as the integration actually needs, never a broadOrders.ReadWrite.All-style role if the caller only ever reads. - Tenant A (the calling organization) registers its own app representing the calling service, and is granted tenant B's app role on tenant A's service principal, which requires an admin in tenant B to consent, explicitly, to tenant A's app having that specific role. This consent step is the actual trust boundary and the reason this is more auditable than a shared secret: it's a named, reviewable grant in tenant B's own Entra ID enterprise applications list, not an out-of-band credential nobody tracks.
- Token flow (OAuth2 client credentials grant): tenant A's service authenticates to its own tenant's Entra ID endpoint using its app registration's credential (a certificate, strongly preferred over a client secret, since certificates are harder to leak accidentally and support automated rotation more cleanly), requesting a token scoped to tenant B's API's app ID URI. Entra ID issues a token whose audience is tenant B's API and whose claims include the granted app role. Tenant A's service presents that token to tenant B's API, which validates the token's issuer, audience, and app role claim before serving the request.
sequenceDiagram
participant SvcA as Tenant A service (service principal)
participant IdA as Tenant A Entra ID
participant API as Tenant B API
SvcA->>IdA: client credentials grant (cert), request token for Tenant B API audience
IdA-->>SvcA: access token, aud=Tenant B API, roles=[Orders.Read]
SvcA->>API: call with Bearer token
API->>API: validate issuer, audience, app role claim
API-->>SvcA: response (or 403 if role insufficient)
- Least privilege in practice: define a distinct app role per integration purpose rather than one broad role reused everywhere, so revoking or auditing one partner's access never touches another's, and so the sign-in/audit logs clearly attribute each call to a specific named grant.
- Auditability: every token issuance shows up in tenant A's Entra ID sign-in logs (which app requested a token, for which audience), and every API call's authorization decision can be logged in tenant B against the specific app role claim used; combined, this gives a full audit trail without either tenant needing visibility into the other's internal identity system.
Trade-offs and pitfalls
The most common mistake is using B2B guest invitations for a machine-to-machine integration because it's the more familiar cross-tenant mechanism, which forces the integration to impersonate a person (often a shared "service account" guest user, which is both a security anti-pattern and breaks the moment that person leaves the organization or their password/MFA changes). The second is granting an overly broad app role "to avoid having to come back and expand it later," which defeats least privilege and makes the eventual audit ("what can tenant A's app actually do in our tenant") much harder to answer confidently. The third is using client secrets instead of certificates for the app registration's credential, since secrets are more prone to being pasted into a config file or committed accidentally; certificates, ideally with an automated rotation process, close that specific leak vector.
Write a Bicep template snippet that defines an AKS cluster with two node pools: a default (general) pool and a spot-preemptible node pool for noncritical batch jobs. Include parameters for node sizes and counts, enable managed identity, and set the spot node pool to use spot instances. Provide only the resource declarations necessary to create the managed cluster and the two agent pools (no pipeline code).
Sample Answer
Approach
Two agent pools, two different jobs, inside one AKS cluster (AKS: Azure Kubernetes Service, Azure's managed Kubernetes offering, where Azure runs and patches the control plane and you manage the worker node pools underneath it): the default pool is a System-mode pool that always runs on-demand (regular) VMs, since it has to host the cluster's own critical add-ons and can't be evicted mid-workload; the second pool is a User-mode pool with scaleSetPriority: 'Spot', which only makes sense for workloads that tolerate eviction (batch jobs), since Azure can reclaim spot capacity with a short notice period whenever it needs the capacity back at on-demand price. The template below was compiled with the Bicep CLI (bicep build) against its bundled Azure resource type definitions, which is the strongest available check of resource type/property correctness without live Azure credentials: it validates the exact property names and structure against Bicep's own schema for Microsoft.ContainerService/managedClusters@2024-05-01, not just that the file parses as valid Bicep syntax.
@description('Azure region for all resources')
param location string = resourceGroup().location
@description('Name of the AKS cluster')
param clusterName string = 'aks-prod-cluster'
@description('Kubernetes version')
param kubernetesVersion string = '1.30.3'
@description('VM size for the default system node pool')
param systemNodeVmSize string = 'Standard_D4s_v5'
@description('Node count for the default system node pool')
param systemNodeCount int = 3
@description('VM size for the spot node pool')
param spotNodeVmSize string = 'Standard_D4s_v5'
@description('Node count for the spot node pool')
param spotNodeCount int = 2
resource aks 'Microsoft.ContainerService/managedClusters@2024-05-01' = {
name: clusterName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
kubernetesVersion: kubernetesVersion
dnsPrefix: '${clusterName}-dns'
agentPoolProfiles: [
{
name: 'system'
mode: 'System'
vmSize: systemNodeVmSize
count: systemNodeCount
osType: 'Linux'
type: 'VirtualMachineScaleSets'
}
]
}
}
resource spotPool 'Microsoft.ContainerService/managedClusters/agentPools@2024-05-01' = {
parent: aks
name: 'spotpool'
properties: {
mode: 'User'
vmSize: spotNodeVmSize
count: spotNodeCount
osType: 'Linux'
type: 'VirtualMachineScaleSets'
scaleSetPriority: 'Spot'
scaleSetEvictionPolicy: 'Delete'
spotMaxPrice: -1
nodeTaints: [
'kubernetes.azure.com/scalesetpriority=spot:NoSchedule'
]
}
}
output aksName string = aks.name
output spotPoolName string = spotPool.name
Actual verification performed: bicep build microsoft-azure-services-and-architecture-b5-aks.bicep --outfile microsoft-azure-services-and-architecture-b5-aks.json completed with zero errors and zero warnings using Bicep CLI 0.47.16, confirming every property name and value type above (scaleSetPriority, scaleSetEvictionPolicy, spotMaxPrice, mode, nodeTaints) matches the actual Microsoft.ContainerService/managedClusters and .../agentPools resource schema for the 2024-05-01 API version, not just that the Bicep syntax itself is well-formed. This environment has no Azure credentials, so bicep deploy/an actual az deployment was not run; the compile-and-type-check step above is the strongest verification available without live Azure access, and is a materially stronger check than "it looks right," since Bicep's compiler rejects unknown or mistyped resource properties.
Key points
spotMaxPrice: -1means "pay up to the current on-demand price," the standard safe default; a positive value caps the price you'll pay and the node pool stops accepting new spot capacity above that cap, which trades cost predictability for a higher eviction/unavailability rate.scaleSetEvictionPolicy: 'Delete'removes the underlying VM entirely on eviction (versus'Deallocate', which stops but keeps the VM allocated, billing for disk but not compute);Deleteis the right choice for a stateless batch node pool that autoscales, since there's no reason to keep a deallocated node around.- The
nodeTaintsentry here is actually redundant, not a required step: AKS automatically applies thekubernetes.azure.com/scalesetpriority=spot:NoScheduletaint (and the matchingkubernetes.azure.com/scalesetpriority: spotlabel) to any node pool created withscaleSetPriority: 'Spot', whether or not the template lists it, exactly as Microsoft's own Spot node pool documentation states ("A Spot node pool has the ... taint"). Declaring it explicitly does no harm since it matches what AKS enforces anyway, but the real thing to get right is on the consumer side: any pod meant to run on the spot pool needs a matchingtoleration(and normally a node affinity for thekubernetes.azure.com/scalesetpriority: spotlabel) in its pod spec, since the taint exists regardless of what this Bicep file says. - A
System-mode pool cannot itself be spot-priority; onlyUser-mode pools supportscaleSetPriority: 'Spot', which is exactly why the cluster needs at least the one non-spot system pool this template always creates.
Complexity and edge cases
There's no algorithmic complexity here since this is declarative infrastructure, not a runtime algorithm; the relevant "complexity" is the resource dependency graph, which is deliberately small and linear here (one cluster, one child agent pool resource depending on it via parent:), so Bicep/ARM can compute a safe deployment order with no manual dependsOn needed. Edge cases worth naming explicitly: a spot pool scaled to zero nodes during low-demand windows needs the cluster autoscaler enabled (not included above, since the question scoped this to "resource declarations necessary to create the cluster and the two pools," not the autoscaler configuration) or it simply won't scale back up on its own; an eviction happening mid-batch-job needs the workload itself to be checkpoint/restart-tolerant, which is an application-level requirement this template cannot enforce, only enable via the taint; and a region or zone briefly running out of spot capacity for the requested VM size will leave spotNodeCount unmet until capacity frees up, which is expected spot behavior, not a template bug.
Describe Azure Virtual Network fundamentals: address spaces, subnets, Network Security Groups (NSGs), User-Defined Routes (UDRs), service tags, and Azure-provided DNS. Provide an example CIDR allocation for production with three subnets (web, app, db) and explain how NSGs can isolate tiers while allowing required connectivity.
Sample Answer
Direct answer
A Virtual Network (VNet) is a private address space you carve into subnets, each of which can carry its own Network Security Group (NSG) for allow/deny packet filtering and its own User-Defined Route (UDR) to override Azure's default routing. Service tags let those rules reference a named group of Microsoft-maintained IP prefixes (like "Storage" or "Internet") instead of hardcoded addresses, and Azure-provided Domain Name System (DNS) resolves VM names inside the VNet automatically without you running your own DNS server.
The building blocks
- Address space: the VNet's overall private Classless Inter-Domain Routing (CIDR) range, typically drawn from the private ranges reserved by RFC 1918 (
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16). - Subnets: subdivisions of that address space; every subnet lives entirely within one VNet and one region, and cannot span multiple VNets or regions.
- Network Security Groups (NSGs): a stateful, priority-ordered list of allow/deny rules for layer 3/4 traffic (source, destination, port, protocol), attached to a subnet or a network interface. Azure adds default rules at the lowest priority, including
AllowVnetInBound,AllowAzureLoadBalancerInBound, andDenyAllInBound, so anything you don't explicitly allow above those is denied by default. - User-Defined Routes (UDRs): override Azure's automatic system routes, most commonly used to force a subnet's traffic through a firewall or network virtual appliance (NVA) by setting a route's next hop type to "Virtual appliance" instead of the internet directly.
- Service tags: named, Microsoft-maintained groups of IP prefixes (
Storage,Sql,Internet,VirtualNetwork,AzureLoadBalancer, and others) that NSG and UDR rules can reference directly, so a rule keeps working as the underlying IP ranges for a service change over time. - Azure-provided DNS: a platform-managed resolver (at the well-known address
168.63.129.16) that resolves VM names within the VNet and forwards internet lookups, with no DNS server to deploy or patch; cross-VNet name resolution or custom domains typically move to Azure Private DNS zones or your own DNS servers instead.
Worked example: CIDR allocation for a three-tier production network
A 10.0.0.0/16 VNet (65,536 addresses) split into three /24 subnets:
| Subnet | CIDR | Usable addresses |
|---|---|---|
| Web | 10.0.1.0/24 | 251 |
| App | 10.0.2.0/24 | 251 |
| DB | 10.0.3.0/24 | 251 |
Azure reserves 5 addresses per subnet regardless of size (the network address, .1 for the default gateway, .2 and .3 for Azure's internal DNS mapping, and the broadcast address), so a /24's usable count is:
For p = 24: 28−5=251, verified directly (10.0.1.0/24 has 256 total addresses; 256 minus the 5 Azure reserves leaves 251).
Isolating tiers with NSGs while allowing required connectivity
| Subnet | Inbound allow | Inbound deny (default) | Outbound |
|---|---|---|---|
Web (10.0.1.0/24) | Port 443/80 from Internet (or narrower, from a load balancer's subnet only) | Everything else | To App subnet on the app's port |
App (10.0.2.0/24) | App port, from Web subnet's prefix only | Everything else, including direct Internet | To DB subnet on the database port |
DB (10.0.3.0/24) | Database port (for example, 1433 for SQL), from App subnet's prefix only | Everything else | Deny to Internet explicitly |
The database tier's explicit outbound deny to the internet matters as much as its inbound restriction: a compromised database tier reaching out to the internet is a common data-exfiltration path, and NSGs are stateful but don't stop an allowed inbound connection's application from opening its own outbound one.
Trade-offs and pitfalls
- Sizing subnets too tightly (a
/28for a tier expected to autoscale) is a common planning mistake; leave headroom, since resizing a subnet with resources already in it is disruptive. - Referencing a service tag instead of a hardcoded IP range is almost always the right call for anything Microsoft manages (
Storage,Sql), since the underlying addresses do change over time and a hardcoded rule silently goes stale. - A UDR forcing traffic through a firewall or NVA adds a real network hop and a potential single point of failure; plan its own high availability before making it mandatory for every subnet's egress (its outbound traffic).
Write a Bicep template that deploys a StorageV2 account (general-purpose v2) into a specified resource group with LRS replication, creates a blob container named 'app-logs', and configures a lifecycle management rule to move blobs to the cool tier after 30 days and delete them after 365 days. The template must accept 'location' and 'storageAccountName' as parameters.
Sample Answer
Direct answer
Below is a Bicep template that deploys a general-purpose v2 (StorageV2) storage account with locally redundant storage (LRS, the cheapest replication tier: three synchronous copies in one datacenter), creates a blob container named app-logs, and adds a lifecycle management rule that moves blobs in that container to the cool access tier after 30 days and deletes them after 365 days. It takes location and storageAccountName as required parameters. It was compiled with the Bicep CLI (bicep build, version 0.47.16) and linted (bicep lint) with zero errors and zero warnings.
Structured elaboration: approach
Three resources, declared as a parent/child chain so Bicep can infer the dependency order correctly: the storage account, a blobServices/default child (blob service settings live one level under the account), and a blobServices/containers grandchild for app-logs. The lifecycle policy is its own top-level child resource (managementPolicies) attached to the account, scoped with a prefixMatch filter so the rule only touches blobs under the app-logs/ virtual path rather than every container in the account.
@description('Azure region for the storage account.')
param location string
@description('Globally unique storage account name, 3-24 lowercase letters/numbers.')
@minLength(3)
@maxLength(24)
param storageAccountName string
param environment string = 'dev'
param owner string = 'platform-team'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
tags: {
environment: environment
owner: owner
}
properties: {
accessTier: 'Hot'
minimumTlsVersion: 'TLS1_2'
supportsHttpsTrafficOnly: true
}
}
resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
parent: storageAccount
name: 'default'
}
resource appLogsContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = {
parent: blobService
name: 'app-logs'
properties: {
publicAccess: 'None'
}
}
resource lifecyclePolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2023-01-01' = {
parent: storageAccount
name: 'default'
properties: {
policy: {
rules: [
{
enabled: true
name: 'move-app-logs-then-expire'
type: 'Lifecycle'
definition: {
filters: {
blobTypes: [
'blockBlob'
]
prefixMatch: [
'app-logs/'
]
}
actions: {
baseBlob: {
tierToCool: {
daysAfterModificationGreaterThan: 30
}
delete: {
daysAfterModificationGreaterThan: 365
}
}
}
}
}
]
}
}
}
output storageAccountId string = storageAccount.id
output primaryBlobEndpoint string = storageAccount.properties.primaryEndpoints.blob
Verified: bicep build main.bicep --outfile main.json succeeds and produces a valid ARM JSON template; bicep lint main.bicep returns no diagnostics. This template has no targetScope declaration, which defaults to resourceGroup, so "into a specified resource group" is satisfied by where the template is deployed (az deployment group create --resource-group <rg> --template-file main.bicep ...) rather than by a parameter inside the file: a resource group is a deployment target, not a property any resource inside the template sets on itself.
Worked example: what actually happens to a blob
Concretely, if a log blob app-logs/2026-06-01.log is last modified on 2026-06-01 and untouched afterward: on day 31 (2026-07-02) the lifecycle engine's daily sweep moves it to the cool tier (cheaper per-GB storage, slightly higher per-operation read cost, no retrieval latency penalty the way archive tier has); on day 366 (2027-06-02, not a full year later since 2027 is not a leap year but the count still runs from the original June date) it is deleted outright. The policy engine runs once every 24 hours and is not real-time, so "after 30 days" means "on the first daily sweep on or after day 30," not to-the-second.
Trade-offs and pitfalls
Key points. The lifecycle rule's enabled flag makes it possible to ship the rule disabled first and flip it on after confirming it targets the right prefix, which is the safe way to introduce a delete-capable policy against production data. tierToCool before delete gives a cheaper holding period rather than jumping straight to deletion, which is what the question specifically asked for and is also generally the right default for logs someone might still need to investigate an incident.
Edge cases. The prefixMatch string's format is [container name]/[blob name prefix], and the trailing slash after app-logs matters more than it looks: because the rule uses app-logs/ with the slash, Microsoft's documented prefix-match behavior scopes it to blobs inside the container literally named app-logs, and only that container. Drop the trailing slash to just app-logs and the match becomes a prefix on the container name itself, so it would then also sweep any other container in the account whose name happens to start with app-logs, for example app-logs-archive or app-logs2. Always keep the trailing slash when the intent is "this one container, nothing else," and scope filters carefully when copying this pattern elsewhere. If a blob is modified again during the cool-tier window (say on day 45), daysAfterModificationGreaterThan resets from that new modification date for the delete action's clock as well, since Azure evaluates lifecycle timing from Last-Modified, not from a separately tracked "moved to cool on" timestamp: a blob that gets touched periodically may never reach 365 days of continuous inactivity and so never gets deleted, which is a common source of "why hasn't this old data been purged" tickets. Also note this account has supportsHttpsTrafficOnly: true and minimumTlsVersion: 'TLS1_2' set defensively even though the question did not ask for hardening; a storage account with neither of these is a common audit finding, and there is no cost to setting them on a brand-new account.
Pitfall to avoid. Do not attach the lifecycle policy resource before the container exists in dependency terms even though the platform does not strictly require the container to pre-exist for the policy to validate: a rule with a prefixMatch for a container that is never created will silently do nothing forever, which is much harder to notice than a deployment failure.
Unlock Full Question Bank
Get access to all Microsoft Azure Services and Architecture interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.