VNet Integration¶
Deploy Container Apps in a custom virtual network for network isolation.
Overview¶
Container Apps can be deployed into a custom VNet to: - Isolate traffic from the public internet - Connect to private resources (databases, storage) - Control ingress/egress with NSG rules
Subnet sizing is not optional
The Container Apps infrastructure subnet must be at least /23. Smaller subnets commonly fail at environment provisioning time.
Architecture¶
flowchart TD
subgraph VNet ["Virtual Network (10.0.0.0/16)"]
subgraph CASubnet ["Container Apps Subnet (10.0.0.0/23)"]
subgraph Environment ["Container Apps Environment"]
CA1[App 1]
CA2[App 2]
INV[Ingress: Envoy]
end
end
subgraph PESubnet ["Private Endpoint Subnet (10.0.2.0/24)"]
PE[Private Endpoint]
end
end
subgraph Internet [Public Internet]
U[User]
end
U -- External Ingress --> INV
INV -- Routing --> CA1
CA1 -- VNet-Local Call --> CA2
CA1 -- Private Link --> PE Prerequisites¶
- Azure subscription with VNet creation permissions
- Existing VNet or create new one
Create VNet with Subnets¶
Container Apps requires a dedicated subnet with minimum /23 CIDR block.
Using Azure CLI:¶
# Create VNet
az network vnet create \
--name vnet-containerapp \
--resource-group $RESOURCE_GROUP \
--location $LOCATION \
--address-prefix 10.0.0.0/16
# Create subnet for Container Apps (minimum /23)
az network vnet subnet create \
--name snet-containerapp \
--vnet-name vnet-containerapp \
--resource-group $RESOURCE_GROUP \
--address-prefix 10.0.0.0/23
Using Bicep:¶
resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = {
name: 'vnet-containerapp'
location: location
properties: {
addressSpace: {
addressPrefixes: ['10.0.0.0/16']
}
subnets: [
{
name: 'snet-containerapp'
properties: {
addressPrefix: '10.0.0.0/23'
}
}
]
}
}
Deploy Container Apps Environment with VNet¶
resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-05-01' = {
name: 'cae-${baseName}'
location: location
properties: {
vnetConfiguration: {
infrastructureSubnetId: vnet.properties.subnets[0].id
internal: false // true for internal-only access
}
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalytics.properties.customerId
sharedKey: logAnalytics.listKeys().primarySharedKey
}
}
}
}
Internal vs External Ingress¶
| Mode | Description | Use Case |
|---|---|---|
internal: false | Public IP + VNet | Public APIs with VNet backend access |
internal: true | Private IP only | Internal microservices, no public access |
Access Private Resources¶
Once in a VNet, Container Apps can access: - Private Endpoints (Azure SQL, Storage, Key Vault) - VNet-peered resources - On-premises via VPN/ExpressRoute
Treat DNS as part of networking design
Private endpoint connectivity depends on DNS zone linkage and name resolution. Validate DNS records before investigating application code.
Example: Connect to Private Azure SQL¶
import os
import pyodbc
# Connection string uses private endpoint DNS
conn_str = os.environ['SQL_CONNECTION_STRING']
# Server=myserver.database.windows.net -> resolves to private IP
Network Security Groups¶
Apply NSG rules to the Container Apps subnet:
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = {
name: 'nsg-containerapp'
location: location
properties: {
securityRules: [
{
name: 'AllowHTTPS'
properties: {
priority: 100
direction: 'Inbound'
access: 'Allow'
protocol: 'Tcp'
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '443'
}
}
]
}
}
Troubleshooting¶
Container can't reach private endpoint¶
- Check DNS resolution inside container
- Verify private endpoint is in same/peered VNet
- Check NSG rules allow outbound traffic
Public access not working¶
- Verify
internal: falsein environment config - Check ingress is enabled on container app
- Verify FQDN is correctly configured