// Container App module for DB Planet MCP Server @description('The environment name (DEV, IAT, Prod)') param environment string @description('The location for the Container App') param location string @description('Tags to apply to resources') param tags object @description('Unique token for resource naming') param resourceToken string @description('Existing central Key Vault name (shared secrets)') param centralKeyVaultName string @description('Existing central Key Vault resource group') param centralKeyVaultResourceGroup string @description('App-specific Key Vault URI (created by keyvault.bicep)') param appKeyVaultUri string @description('Existing Container App Environment name') param containerAppEnvironmentName string @description('Existing Container App Environment resource group') param containerAppEnvironmentResourceGroup string @description('Artifactory server URL for container registry') param artifactoryServer string @description('Registry username for container registry authentication') param registryUsername string @description('Managed Identity ID for Key Vault access') param managedIdentityId string @description('Container image tag/version') param imageTag string = 'latest' @description('DB Planet base URL (staging vs production)') param dbplanetBaseUrl string @description('Custom domain name for the Container App') param customDomainName string = '' @description('Container App Certificate ID (if custom domain is configured)') param containerAppCertificateId string = '' var containerAppName = 'ca-dbp-${toLower(environment)}-${take(resourceToken, 8)}' // Custom domain configuration var customDomain = !empty(customDomainName) && !empty(containerAppCertificateId) ? [ { name: customDomainName certificateId: containerAppCertificateId bindingType: 'SniEnabled' } ] : [] // Reference existing central Key Vault resource centralKeyVault 'Microsoft.KeyVault/vaults@2024-11-01' existing = { name: centralKeyVaultName scope: resourceGroup(centralKeyVaultResourceGroup) } // Reference existing Container App Environment resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2025-01-01' existing = { name: containerAppEnvironmentName scope: resourceGroup(containerAppEnvironmentResourceGroup) } // Container App resource containerApp 'Microsoft.App/containerApps@2025-01-01' = { name: containerAppName location: location tags: tags identity: { type: 'SystemAssigned, UserAssigned' userAssignedIdentities: { '${managedIdentityId}': {} } } properties: { managedEnvironmentId: containerAppEnvironment.id workloadProfileName: 'Consumption' configuration: { ingress: { external: true targetPort: 4000 allowInsecure: false customDomains: customDomain traffic: [ { weight: 100 latestRevision: true } ] } secrets: [ { name: 'artifactory-token' keyVaultUrl: '${centralKeyVault.properties.vaultUri}secrets/artifactory-registry-token' identity: managedIdentityId } { name: 'appinsights-connection-string' keyVaultUrl: '${appKeyVaultUri}secrets/applicationinsights-connection-string' identity: 'system' } { name: 'dbplanet-username' keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-USERNAME' identity: 'system' } { name: 'dbplanet-password' keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-PASSWORD' identity: 'system' } { name: 'dbplanet-client-id' keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-CLIENT-ID' identity: 'system' } { name: 'dbplanet-client-secret' keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-CLIENT-SECRET' identity: 'system' } ] registries: [ { server: artifactoryServer username: registryUsername passwordSecretRef: 'artifactory-token' } ] } template: { containers: [ { name: 'dbplanet-mcp' image: '${artifactoryServer}/db-planet-mcp-server:${imageTag}' resources: { cpu: json(environment == 'Prod' ? '1.0' : '0.5') memory: environment == 'Prod' ? '2Gi' : '1Gi' } env: [ { name: 'DBPLANET_BASE_URL', value: dbplanetBaseUrl } { name: 'DBPLANET_USERNAME', secretRef: 'dbplanet-username' } { name: 'DBPLANET_PASSWORD', secretRef: 'dbplanet-password' } { name: 'DBPLANET_CLIENT_ID', secretRef: 'dbplanet-client-id' } { name: 'DBPLANET_CLIENT_SECRET', secretRef: 'dbplanet-client-secret' } { name: 'NODE_ENV', value: environment == 'Prod' ? 'production' : 'development' } { name: 'HTTP_PROXY', value: 'http://webproxy.comp.db.de:8080' } { name: 'HTTPS_PROXY', value: 'http://webproxy.comp.db.de:8080' } { name: 'http_proxy', value: 'http://webproxy.comp.db.de:8080' } { name: 'https_proxy', value: 'http://webproxy.comp.db.de:8080' } { name: 'NO_PROXY', value: '169.254.169.254,169.254.170.2,cognitiveservices.azure.com,internal.deutschebahn.com,db.de' } { name: 'no_proxy', value: '169.254.169.254,169.254.170.2,cognitiveservices.azure.com,internal.deutschebahn.com,db.de' } { name: 'STREAMABLE_HTTP', value: 'true' } { name: 'REMOTE_AUTHORIZATION', value: 'true' } { name: 'HOST', value: '0.0.0.0' } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' secretRef: 'appinsights-connection-string' } ] probes: [ { type: 'Readiness' httpGet: { path: '/health' port: 4000 } initialDelaySeconds: 5 periodSeconds: 30 } { type: 'Liveness' httpGet: { path: '/health' port: 4000 } initialDelaySeconds: 10 periodSeconds: 60 } ] } ] scale: { minReplicas: 1 maxReplicas: 1 } } } } output containerAppName string = containerApp.name output containerAppId string = containerApp.id output containerAppFqdn string = containerApp.properties.configuration.ingress.fqdn output systemIdentityPrincipalId string = containerApp.identity.principalId output containerAppEnvironmentStaticIp string = containerAppEnvironment.properties.staticIp