Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/CustomizingAzdParameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_ENV_CONTAINER_IMAGE_TAG` | string | `latest` | Sets the container image tag (e.g., `latest`, `dev`, `hotfix`). |
| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of provisioning a new one. |
| `AZURE_ENV_FOUNDRY_PROJECT_ID` | string | Guide to get your [Existing AI Project ID](/docs/re-use-foundry-project.md) | Reuses an existing AI Foundry and AI Foundry Project instead of creating a new one. |
| `AZURE_ENV_VM_SIZE` | string | `Standard_D2s_v5` | Overrides the jumpbox VM size (private networking only). Default: `Standard_D2s_v5`. |

## How to Set a Parameter

Expand Down
4 changes: 3 additions & 1 deletion docs/TroubleShootingSteps.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Use these as quick reference guides to unblock your deployments.
| **InternalSubscriptionIsOverQuotaForSku/<br>ManagedEnvironmentProvisioningError** | Subscription quota exceeded for the requested SKU | Quotas are applied per resource group, subscriptions, accounts, and other scopes. For example, your subscription might be configured to limit the number of vCPUs for a region. If you attempt to deploy a virtual machine with more vCPUs than the permitted amount, you receive an error that the quota was exceeded.<br><br>For PowerShell, use the `Get-AzVMUsage` cmdlet to find virtual machine quotas:<br>`Get-AzVMUsage -Location "West US"`<br><br>Based on available quota you can deploy application otherwise, you can request for more quota |
| **InsufficientQuota** | Not enough quota available in subscription | <ul><li>Check if you have sufficient quota available in your subscription before deployment</li><li>To verify, refer to the [quota_check](../docs/quota_check.md) file for details</li></ul> |
| **MaxNumberOfRegionalEnvironmentsInSubExceeded** | Maximum Container App Environments limit reached for region |This error occurs when you attempt to create more **Azure Container App Environments** than the regional quota limit allows for your subscription. Each Azure region has a specific limit on the number of Container App Environments that can be created per subscription.<br><br>**Common Causes:**<br><ul><li>Deploying to regions with low quota limits (e.g., Sweden Central allows only 1 environment)</li><li>Multiple deployments without cleaning up previous environments</li><li>Exceeding the standard limit of 15 environments in most major regions</li></ul><br>**Resolution:**<br><ul><li>**Delete unused environments** in the target region, OR</li><li>**Deploy to a different region** with available capacity, OR</li><li>**Request quota increase** via [Azure Support](https://go.microsoft.com/fwlink/?linkid=2208872)</li></ul><br>**Reference:**<br><ul><li>[Azure Container Apps quotas](https://learn.microsoft.com/en-us/azure/container-apps/quotas)</li><li>[Azure subscription and service limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits)</li></ul> |
| **SkuNotAvailable** | Requested SKU not available in selected location or zone | You receive this error in the following scenarios:<br><ul><li>When the resource SKU you've selected, such as VM size, isn't available for a location or zone</li><li>If you're deploying an Azure Spot VM or Spot scale set instance, and there isn't any capacity for Azure Spot in this location. For more information, see Spot error messages</li></ul> |
| **SkuNotAvailable** | Requested SKU not available in selected location or zone | This error occurs when the resource SKU you've selected (such as VM size) isn't available for the target location or availability zone.<br><br>**In this deployment**, the jumpbox VM defaults to `Standard_D2s_v5`. While this size is available in most regions, certain regions or zones may not support it.<br><br>**Resolution:**<br><ul><li>**Check SKU availability** for your target region:<br>`az vm list-skus --location <region> --size Standard_D2s --output table`</li><li>**Override the VM size** if the default isn't available in your region:<br>`azd env set AZURE_ENV_VM_SIZE Standard_D2s_v4`</li><li>**Recommended alternatives** (all support accelerated networking):<br>`Standard_D2s_v4`, `Standard_D2as_v5` (AMD), `Standard_D2s_v3`</li><li>**Avoid these sizes**: `Standard_DS2_v2` (being retired), A-series (no accelerated networking)</li><li>If deploying an Azure Spot VM, check [Spot capacity](https://aka.ms/azurespotpricing)</li></ul> |
| **Conflict - No available instances to satisfy this request** | Azure App Service has insufficient capacity in the region | This error occurs when Azure App Service doesn't have enough available compute instances in the selected region to provision or scale your app.<br><br>**Common Causes:**<br><ul><li>High demand in the selected region (e.g., East US, West Europe)</li><li>Specific SKUs experiencing capacity constraints (Free, Shared, or certain Premium tiers)</li><li>Multiple rapid deployments in the same region</li></ul><br>**Resolution:**<br><ul><li>**Wait and Retry** (15-30 minutes): `azd up`</li><li>**Deploy to a New Resource Group** (Recommended for urgent cases):<br>```<br>azd down --force --purge<br>azd up<br>```</li><li>**Try a Different Region:**<br>Update region in `main.bicep` or `azure.yaml` to a less congested region (e.g., `westus2`, `centralus`, `northeurope`)</li><li>**Use a Different SKU/Tier:**<br>If using Free/Shared tier, upgrade to Basic or Standard<br>Check SKU availability: `az appservice list-locations --sku <sku-name>`</li></ul><br>**Reference:** [Azure App Service Plans](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans) |

--------------------------------
Expand Down Expand Up @@ -121,6 +121,8 @@ Use these as quick reference guides to unblock your deployments.
|-----------------|-------------|------------------|
| **NetcfgSubnetRangeOutsideVnet** | Subnet IP range outside virtual network address space | <ul><li>Ensure the subnet's IP address range falls within the virtual network's address space</li><li>Always validate that the subnet CIDR block is a subset of the VNet range</li><li>For Azure Bastion, the AzureBastionSubnet must be at least /27</li><li>Confirm that the AzureBastionSubnet is deployed inside the VNet</li></ul> |
| **DisableExport_PublicNetworkAccessMustBeDisabled** | Public network access must be disabled when export is disabled | <ul><li>**Check container source:** Confirm whether the deployment is using a Docker image or Azure Container Registry (ACR)</li><li>**Verify ACR configuration:** If ACR is included, review its settings to ensure they comply with Azure requirements</li><li>**Check export settings:** If export is disabled in ACR, make sure public network access is also disabled</li><li>**Redeploy after fix:** Correct the configuration and redeploy. This will prevent the Conflict error during deployment</li><li>For more information refer [ACR Data Loss Prevention](https://learn.microsoft.com/en-us/azure/container-registry/data-loss-prevention) document</li></ul> |
| **VMSizeIsNotPermittedToEnableAcceleratedNetworking** | VM size does not support accelerated networking | This error occurs when you attempt to enable accelerated networking on a VM size that does not support it. This deployment's jumpbox VM **requires** accelerated networking.<br><br>**Default VM size:** `Standard_D2s_v5` — supports accelerated networking.<br><br>**How this error happens:**<br><ul><li>You override the VM size (via `AZURE_ENV_VM_SIZE`) with a size that doesn't support accelerated networking (e.g., `Standard_A2m_v2`, A-series, or B-series VMs)</li><li>Azure rejects the deployment with `VMSizeIsNotPermittedToEnableAcceleratedNetworking`</li></ul><br>**Resolution:**<br><ul><li>Use the default `Standard_D2s_v5` (recommended)</li><li>If overriding VM size, choose one that supports accelerated networking:<br>`Standard_D2s_v4`, `Standard_D2as_v5` (AMD), `Standard_D2s_v3`</li><li>Verify VM size supports accelerated networking:<br>`az vm list-skus --location <region> --size <vm-size> --query "[?capabilities[?name=='AcceleratedNetworkingEnabled' && value=='True']]"`</li><li>Avoid A-series and B-series VMs — they do not support accelerated networking</li><li>See [VM sizes with accelerated networking](https://learn.microsoft.com/en-us/azure/virtual-network/accelerated-networking-overview)</li></ul> |
| **NetworkSecurityGroupNotCompliantForAzureBastionSubnet** / **SecurityRuleParameterContainsUnsupportedValue** | NSG rules blocking required Azure Bastion ports | This error occurs when the Network Security Group (NSG) attached to `AzureBastionSubnet` explicitly denies inbound TCP ports 443 and/or 4443, which Azure Bastion requires for management and tunneling.<br><br>**How to reproduce:**<br><ul><li>Deploy the template with `enablePrivateNetworking=true` so the virtualNetwork module creates `AzureBastionSubnet` and a Network Security Group that denies ports 443 and 4443</li><li>Attempt to deploy Azure Bastion into that subnet</li><li>During validation, Bastion detects the deny rules and fails with `NetworkSecurityGroupNotCompliantForAzureBastionSubnet`</li></ul><br>**Resolution:**<br><ul><li>**Remove or modify deny rules** for ports 443 and 4443 in the NSG attached to `AzureBastionSubnet`</li><li>**Ensure required inbound rules** per [Azure Bastion NSG requirements](https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg)</li><li>**Use Bicep conditions** to skip NSG attachments for `AzureBastionSubnet` if deploying Bastion</li><li>**Validate the NSG configuration** before deploying Bastion into the subnet</li></ul> |

---------------------------------

Expand Down
139 changes: 85 additions & 54 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.20.0' = if (enable
enableTelemetry: enableTelemetry
computerName: take(jumpboxVmName, 15)
osType: 'Windows'
vmSize: empty(vmSize) ? 'Standard_DS2_v2' : vmSize
vmSize: empty(vmSize) ? 'Standard_D2s_v5' : vmSize
adminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername
adminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword
managedIdentities: {
Expand Down Expand Up @@ -776,40 +776,50 @@ module avmAiServices 'modules/account/aifoundry.bicep' = {
// WAF related parameters
publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled'
//publicNetworkAccess: 'Enabled' // Always enabled for AI Services
privateEndpoints: (enablePrivateNetworking && empty(existingProjectResourceId))
? [
{
name: 'pep-aiservices-${solutionSuffix}'
customNetworkInterfaceName: 'nic-aiservices-${solutionSuffix}'
privateEndpointResourceId: virtualNetwork!.outputs.resourceId
privateDnsZoneGroup: {
privateDnsZoneGroupConfigs: [
{
name: 'ai-services-dns-zone-cognitiveservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-openai'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-aiservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-contentunderstanding'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId
}
]
}
subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet
}
]
: []
}
}

module avmAiServices_cu 'br/public:avm/res/cognitive-services/account:0.13.2' = {
module cognitiveServicePrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.8.1' = if (enablePrivateNetworking && empty(existingProjectResourceId)) {
name: take('avm.res.network.private-endpoint.${solutionSuffix}', 64)
params: {
name: 'pep-aiservices-${solutionSuffix}'
location: location
tags: tags
customNetworkInterfaceName: 'nic-aiservices-${solutionSuffix}'
privateLinkServiceConnections: [
{
name: 'pep-aiservices-${solutionSuffix}-cognitiveservices-connection'
properties: {
privateLinkServiceId: avmAiServices.outputs.resourceId
groupIds: ['account']
}
}
]
privateDnsZoneGroup: {
privateDnsZoneGroupConfigs: [
{
name: 'ai-services-dns-zone-cognitiveservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-openai'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-aiservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-contentunderstanding'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId
}
]
}
subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId
}
}

module avmAiServices_cu 'br/public:avm/res/cognitive-services/account:0.14.1' = {
name: take('avm.res.cognitive-services.account.content-understanding.${solutionSuffix}', 64)

params: {
Expand Down Expand Up @@ -848,28 +858,42 @@ module avmAiServices_cu 'br/public:avm/res/cognitive-services/account:0.13.2' =
]

publicNetworkAccess: (enablePrivateNetworking) ? 'Disabled' : 'Enabled'
privateEndpoints: (enablePrivateNetworking)
? [
{
name: 'pep-aicu-${solutionSuffix}'
customNetworkInterfaceName: 'nic-aicu-${solutionSuffix}'
privateEndpointResourceId: virtualNetwork!.outputs.resourceId
privateDnsZoneGroup: {
privateDnsZoneGroupConfigs: [
{
name: 'aicu-dns-zone-cognitiveservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId
}
{
name: 'aicu-dns-zone-contentunderstanding'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId
}
]
}
subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId // Use the backend subnet
}
]
: []
}
}

module contentUnderstandingPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.8.1' = if (enablePrivateNetworking) {
name: take('avm.res.network.private-endpoint.aicu-${solutionSuffix}', 64)
params: {
name: 'pep-aicu-${solutionSuffix}'
location: location
tags: tags
customNetworkInterfaceName: 'nic-aicu-${solutionSuffix}'
privateLinkServiceConnections: [
{
name: 'pep-aicu-${solutionSuffix}-cognitiveservices-connection'
properties: {
privateLinkServiceId: avmAiServices_cu.outputs.resourceId
groupIds: ['account']
}
}
]
privateDnsZoneGroup: {
privateDnsZoneGroupConfigs: [
{
name: 'aicu-dns-zone-cognitiveservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId
}
{
name: 'ai-services-dns-zone-aiservices'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId
}
{
name: 'aicu-dns-zone-contentunderstanding'
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.contentUnderstanding]!.outputs.resourceId
}
]
}
subnetResourceId: virtualNetwork!.outputs.backendSubnetResourceId
}
}

Expand Down Expand Up @@ -1631,6 +1655,10 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.19.0' = {
: []
}
}
dependsOn: [
cognitiveServicePrivateEndpoint
contentUnderstandingPrivateEndpoint
]
}

module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.19.0' = {
Expand Down Expand Up @@ -1754,6 +1782,9 @@ module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.19.0' =
]
}
}
dependsOn: [
cognitiveServicePrivateEndpoint
]
}

// ========== Container App Workflow Update ========== //
Expand Down
Loading