diff --git a/playground/AzureAppService/AzureAppService.AppHost/api-website.module.bicep b/playground/AzureAppService/AzureAppService.AppHost/api-website.module.bicep new file mode 100644 index 00000000000..2767dee5fb4 --- /dev/null +++ b/playground/AzureAppService/AzureAppService.AppHost/api-website.module.bicep @@ -0,0 +1,155 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param infra_outputs_azure_container_registry_endpoint string + +param infra_outputs_planid string + +param infra_outputs_azure_container_registry_managed_identity_id string + +param infra_outputs_azure_container_registry_managed_identity_client_id string + +param api_containerimage string + +param api_containerport string + +param storage_outputs_blobendpoint string + +param account_outputs_connectionstring string + +@secure() +param secretparam_value string + +param api_identity_outputs_principalname string + +param api_identity_outputs_id string + +param api_identity_outputs_clientid string + +param infra_outputs_azure_app_service_dashboard_uri string + +param infra_outputs_azure_website_contributor_managed_identity_id string + +param infra_outputs_azure_website_contributor_managed_identity_principal_id string + +resource mainContainer 'Microsoft.Web/sites/sitecontainers@2024-11-01' = { + name: 'main' + properties: { + authType: 'UserAssigned' + image: api_containerimage + isMain: true + targetPort: api_containerport + userManagedIdentityClientId: infra_outputs_azure_container_registry_managed_identity_client_id + } + parent: webapp +} + +resource webapp 'Microsoft.Web/sites@2024-11-01' = { + name: take('${toLower('api')}-${uniqueString(resourceGroup().id)}', 60) + location: location + properties: { + serverFarmId: infra_outputs_planid + keyVaultReferenceIdentity: api_identity_outputs_id + siteConfig: { + numberOfWorkers: 30 + linuxFxVersion: 'SITECONTAINERS' + acrUseManagedIdentityCreds: true + acrUserManagedIdentityID: infra_outputs_azure_container_registry_managed_identity_client_id + appSettings: [ + { + name: 'WEBSITES_PORT' + value: api_containerport + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY' + value: 'in_memory' + } + { + name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED' + value: 'true' + } + { + name: 'HTTP_PORTS' + value: api_containerport + } + { + name: 'ConnectionStrings__blobs' + value: storage_outputs_blobendpoint + } + { + name: 'ConnectionStrings__account' + value: account_outputs_connectionstring + } + { + name: 'VALUE' + value: secretparam_value + } + { + name: 'AZURE_PRINCIPAL_NAME' + value: api_identity_outputs_principalname + } + { + name: 'AZURE_CLIENT_ID' + value: api_identity_outputs_clientid + } + { + name: 'AZURE_TOKEN_CREDENTIALS' + value: 'ManagedIdentityCredential' + } + { + name: 'ASPIRE_ENVIRONMENT_NAME' + value: 'infra' + } + { + name: 'OTEL_SERVICE_NAME' + value: 'api' + } + { + name: 'OTEL_EXPORTER_OTLP_PROTOCOL' + value: 'grpc' + } + { + name: 'OTEL_EXPORTER_OTLP_ENDPOINT' + value: 'http://localhost:6001' + } + { + name: 'WEBSITE_ENABLE_ASPIRE_OTEL_SIDECAR' + value: 'true' + } + { + name: 'OTEL_COLLECTOR_URL' + value: infra_outputs_azure_app_service_dashboard_uri + } + { + name: 'OTEL_CLIENT_ID' + value: infra_outputs_azure_container_registry_managed_identity_client_id + } + ] + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${infra_outputs_azure_container_registry_managed_identity_id}': { } + '${api_identity_outputs_id}': { } + } + } +} + +resource api_website_ra 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(webapp.id, infra_outputs_azure_website_contributor_managed_identity_id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772')) + properties: { + principalId: infra_outputs_azure_website_contributor_managed_identity_principal_id + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772') + principalType: 'ServicePrincipal' + } + scope: webapp +} \ No newline at end of file diff --git a/playground/AzureAppService/AzureAppService.AppHost/aspire-manifest.json b/playground/AzureAppService/AzureAppService.AppHost/aspire-manifest.json index 310101c2988..403924b3e40 100644 --- a/playground/AzureAppService/AzureAppService.AppHost/aspire-manifest.json +++ b/playground/AzureAppService/AzureAppService.AppHost/aspire-manifest.json @@ -40,7 +40,7 @@ "path": "../AzureAppService.ApiService/AzureAppService.ApiService.csproj", "deployment": { "type": "azure.bicep.v0", - "path": "api.module.bicep", + "path": "api-website.module.bicep", "params": { "infra_outputs_azure_container_registry_endpoint": "{infra.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT}", "infra_outputs_planid": "{infra.outputs.planId}", diff --git a/playground/AzureAppService/AzureAppService.AppHost/infra.module.bicep b/playground/AzureAppService/AzureAppService.AppHost/infra.module.bicep index ea7c9458c23..0c9493976f6 100644 --- a/playground/AzureAppService/AzureAppService.AppHost/infra.module.bicep +++ b/playground/AzureAppService/AzureAppService.AppHost/infra.module.bicep @@ -128,6 +128,8 @@ output name string = infra_asplan.name output planId string = infra_asplan.id +output webSiteSuffix string = uniqueString(resourceGroup().id) + output AZURE_CONTAINER_REGISTRY_NAME string = infra_acr.name output AZURE_CONTAINER_REGISTRY_ENDPOINT string = infra_acr.properties.loginServer diff --git a/playground/AzureContainerApps/AzureContainerApps.AppHost/api-containerapp.module.bicep b/playground/AzureContainerApps/AzureContainerApps.AppHost/api-containerapp.module.bicep new file mode 100644 index 00000000000..aa81deb04e0 --- /dev/null +++ b/playground/AzureContainerApps/AzureContainerApps.AppHost/api-containerapp.module.bicep @@ -0,0 +1,184 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param infra_outputs_azure_container_apps_environment_default_domain string + +param infra_outputs_azure_container_apps_environment_id string + +param infra_outputs_azure_container_registry_endpoint string + +param infra_outputs_azure_container_registry_managed_identity_id string + +param api_containerimage string + +param api_identity_outputs_id string + +param api_containerport string + +param storage_outputs_blobendpoint string + +@secure() +param cache_password_value string + +param account_kv_outputs_name string + +@secure() +param secretparam_value string + +param api_identity_outputs_principalname string + +param api_identity_outputs_clientid string + +param certificateName string + +param customDomain string + +resource account_kv 'Microsoft.KeyVault/vaults@2024-11-01' existing = { + name: account_kv_outputs_name +} + +resource account_kv_connectionstrings__account 'Microsoft.KeyVault/vaults/secrets@2024-11-01' existing = { + name: 'connectionstrings--account' + parent: account_kv +} + +resource api 'Microsoft.App/containerApps@2025-02-02-preview' = { + name: 'api' + location: location + properties: { + configuration: { + secrets: [ + { + name: 'connectionstrings--cache' + value: 'cache:6379,password=${cache_password_value}' + } + { + name: 'cache-password' + value: cache_password_value + } + { + name: 'cache-uri' + value: 'redis://:${uriComponent(cache_password_value)}@cache:6379' + } + { + name: 'connectionstrings--account' + identity: api_identity_outputs_id + keyVaultUrl: account_kv_connectionstrings__account.properties.secretUri + } + { + name: 'value' + value: secretparam_value + } + ] + activeRevisionsMode: 'Single' + ingress: { + external: true + targetPort: int(api_containerport) + transport: 'http' + customDomains: [ + { + name: customDomain + bindingType: (certificateName != '') ? 'SniEnabled' : 'Disabled' + certificateId: (certificateName != '') ? '${infra_outputs_azure_container_apps_environment_id}/managedCertificates/${certificateName}' : null + } + ] + } + registries: [ + { + server: infra_outputs_azure_container_registry_endpoint + identity: infra_outputs_azure_container_registry_managed_identity_id + } + ] + runtime: { + dotnet: { + autoConfigureDataProtection: true + } + } + } + environmentId: infra_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: api_containerimage + name: 'api' + env: [ + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY' + value: 'in_memory' + } + { + name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED' + value: 'true' + } + { + name: 'HTTP_PORTS' + value: api_containerport + } + { + name: 'ConnectionStrings__blobs' + value: storage_outputs_blobendpoint + } + { + name: 'ConnectionStrings__cache' + secretRef: 'connectionstrings--cache' + } + { + name: 'CACHE_HOST' + value: 'cache' + } + { + name: 'CACHE_PORT' + value: '6379' + } + { + name: 'CACHE_PASSWORD' + secretRef: 'cache-password' + } + { + name: 'CACHE_URI' + secretRef: 'cache-uri' + } + { + name: 'ConnectionStrings__account' + secretRef: 'connectionstrings--account' + } + { + name: 'VALUE' + secretRef: 'value' + } + { + name: 'AZURE_PRINCIPAL_NAME' + value: api_identity_outputs_principalname + } + { + name: 'AZURE_CLIENT_ID' + value: api_identity_outputs_clientid + } + { + name: 'AZURE_TOKEN_CREDENTIALS' + value: 'ManagedIdentityCredential' + } + ] + } + ] + scale: { + minReplicas: 0 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${api_identity_outputs_id}': { } + '${infra_outputs_azure_container_registry_managed_identity_id}': { } + } + } +} \ No newline at end of file diff --git a/playground/AzureContainerApps/AzureContainerApps.AppHost/aspire-manifest.json b/playground/AzureContainerApps/AzureContainerApps.AppHost/aspire-manifest.json index 89326b3c649..dc6f27a8aa7 100644 --- a/playground/AzureContainerApps/AzureContainerApps.AppHost/aspire-manifest.json +++ b/playground/AzureContainerApps/AzureContainerApps.AppHost/aspire-manifest.json @@ -42,7 +42,7 @@ "image": "docker.io/library/redis:8.2", "deployment": { "type": "azure.bicep.v0", - "path": "cache.module.bicep", + "path": "cache-containerapp.module.bicep", "params": { "infra_outputs_azure_container_apps_environment_default_domain": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "infra_outputs_azure_container_apps_environment_id": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", @@ -107,7 +107,7 @@ }, "deployment": { "type": "azure.bicep.v0", - "path": "pythonapp.module.bicep", + "path": "pythonapp-containerapp.module.bicep", "params": { "infra_outputs_azure_container_apps_environment_default_domain": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "infra_outputs_azure_container_apps_environment_id": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", @@ -122,7 +122,7 @@ "path": "../AzureContainerApps.ApiService/AzureContainerApps.ApiService.csproj", "deployment": { "type": "azure.bicep.v0", - "path": "api.module.bicep", + "path": "api-containerapp.module.bicep", "params": { "infra_outputs_azure_container_apps_environment_default_domain": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "infra_outputs_azure_container_apps_environment_id": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", diff --git a/playground/AzureContainerApps/AzureContainerApps.AppHost/cache-containerapp.module.bicep b/playground/AzureContainerApps/AzureContainerApps.AppHost/cache-containerapp.module.bicep new file mode 100644 index 00000000000..ba7d5f72070 --- /dev/null +++ b/playground/AzureContainerApps/AzureContainerApps.AppHost/cache-containerapp.module.bicep @@ -0,0 +1,70 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param infra_outputs_azure_container_apps_environment_default_domain string + +param infra_outputs_azure_container_apps_environment_id string + +@secure() +param cache_password_value string + +param infra_outputs_volumes_cache_0 string + +resource cache 'Microsoft.App/containerApps@2025-01-01' = { + name: 'cache' + location: location + properties: { + configuration: { + secrets: [ + { + name: 'redis-password' + value: cache_password_value + } + ] + activeRevisionsMode: 'Single' + ingress: { + external: false + targetPort: 6379 + transport: 'tcp' + } + } + environmentId: infra_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: 'docker.io/library/redis:8.2' + name: 'cache' + command: [ + '/bin/sh' + ] + args: [ + '-c' + 'redis-server --requirepass \$REDIS_PASSWORD --save 60 1' + ] + env: [ + { + name: 'REDIS_PASSWORD' + secretRef: 'redis-password' + } + ] + volumeMounts: [ + { + volumeName: 'v0' + mountPath: '/data' + } + ] + } + ] + scale: { + minReplicas: 1 + } + volumes: [ + { + name: 'v0' + storageType: 'AzureFile' + storageName: infra_outputs_volumes_cache_0 + } + ] + } + } +} \ No newline at end of file diff --git a/playground/AzureContainerApps/AzureContainerApps.AppHost/pythonapp-containerapp.module.bicep b/playground/AzureContainerApps/AzureContainerApps.AppHost/pythonapp-containerapp.module.bicep new file mode 100644 index 00000000000..f0c194b9225 --- /dev/null +++ b/playground/AzureContainerApps/AzureContainerApps.AppHost/pythonapp-containerapp.module.bicep @@ -0,0 +1,46 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param infra_outputs_azure_container_apps_environment_default_domain string + +param infra_outputs_azure_container_apps_environment_id string + +param infra_outputs_azure_container_registry_endpoint string + +param infra_outputs_azure_container_registry_managed_identity_id string + +param pythonapp_containerimage string + +resource pythonapp 'Microsoft.App/containerApps@2025-01-01' = { + name: 'pythonapp' + location: location + properties: { + configuration: { + activeRevisionsMode: 'Single' + registries: [ + { + server: infra_outputs_azure_container_registry_endpoint + identity: infra_outputs_azure_container_registry_managed_identity_id + } + ] + } + environmentId: infra_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: pythonapp_containerimage + name: 'pythonapp' + } + ] + scale: { + minReplicas: 1 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${infra_outputs_azure_container_registry_managed_identity_id}': { } + } + } +} \ No newline at end of file diff --git a/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/apiservice-containerapp.module.bicep b/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/apiservice-containerapp.module.bicep new file mode 100644 index 00000000000..948015c838b --- /dev/null +++ b/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/apiservice-containerapp.module.bicep @@ -0,0 +1,139 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param env_outputs_azure_container_apps_environment_default_domain string + +param env_outputs_azure_container_apps_environment_id string + +param env_outputs_azure_container_registry_endpoint string + +param env_outputs_azure_container_registry_managed_identity_id string + +param apiservice_containerimage string + +param apiservice_identity_outputs_id string + +param apiservice_containerport string + +param eventhubs_outputs_eventhubsendpoint string + +param messaging_outputs_servicebusendpoint string + +param cosmosdb_outputs_connectionstring string + +param storage_outputs_queueendpoint string + +param storage_outputs_blobendpoint string + +param apiservice_identity_outputs_clientid string + +resource apiservice 'Microsoft.App/containerApps@2025-02-02-preview' = { + name: 'apiservice' + location: location + properties: { + configuration: { + activeRevisionsMode: 'Single' + ingress: { + external: true + targetPort: int(apiservice_containerport) + transport: 'http' + } + registries: [ + { + server: env_outputs_azure_container_registry_endpoint + identity: env_outputs_azure_container_registry_managed_identity_id + } + ] + runtime: { + dotnet: { + autoConfigureDataProtection: true + } + } + } + environmentId: env_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: apiservice_containerimage + name: 'apiservice' + env: [ + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY' + value: 'in_memory' + } + { + name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED' + value: 'true' + } + { + name: 'HTTP_PORTS' + value: apiservice_containerport + } + { + name: 'ConnectionStrings__myhub' + value: 'Endpoint=${eventhubs_outputs_eventhubsendpoint};EntityPath=myhub' + } + { + name: 'ConnectionStrings__messaging' + value: messaging_outputs_servicebusendpoint + } + { + name: 'ConnectionStrings__cosmosdb' + value: cosmosdb_outputs_connectionstring + } + { + name: 'ConnectionStrings__queue' + value: storage_outputs_queueendpoint + } + { + name: 'ConnectionStrings__blob' + value: storage_outputs_blobendpoint + } + { + name: 'FUNCAPP_HTTP' + value: 'http://funcapp.${env_outputs_azure_container_apps_environment_default_domain}' + } + { + name: 'services__funcapp__http__0' + value: 'http://funcapp.${env_outputs_azure_container_apps_environment_default_domain}' + } + { + name: 'FUNCAPP_HTTPS' + value: 'https://funcapp.${env_outputs_azure_container_apps_environment_default_domain}' + } + { + name: 'services__funcapp__https__0' + value: 'https://funcapp.${env_outputs_azure_container_apps_environment_default_domain}' + } + { + name: 'AZURE_CLIENT_ID' + value: apiservice_identity_outputs_clientid + } + { + name: 'AZURE_TOKEN_CREDENTIALS' + value: 'ManagedIdentityCredential' + } + ] + } + ] + scale: { + minReplicas: 1 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${apiservice_identity_outputs_id}': { } + '${env_outputs_azure_container_registry_managed_identity_id}': { } + } + } +} \ No newline at end of file diff --git a/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/aspire-manifest.json b/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/aspire-manifest.json index 1b748584eb3..91bad7b24d9 100644 --- a/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/aspire-manifest.json +++ b/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/aspire-manifest.json @@ -68,7 +68,7 @@ "path": "../AzureFunctionsEndToEnd.Functions/AzureFunctionsEndToEnd.Functions.csproj", "deployment": { "type": "azure.bicep.v0", - "path": "funcapp.module.bicep", + "path": "funcapp-containerapp.module.bicep", "params": { "env_outputs_azure_container_apps_environment_default_domain": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "env_outputs_azure_container_apps_environment_id": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", @@ -146,7 +146,7 @@ "path": "../AzureFunctionsEndToEnd.ApiService/AzureFunctionsEndToEnd.ApiService.csproj", "deployment": { "type": "azure.bicep.v0", - "path": "apiservice.module.bicep", + "path": "apiservice-containerapp.module.bicep", "params": { "env_outputs_azure_container_apps_environment_default_domain": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "env_outputs_azure_container_apps_environment_id": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", @@ -174,7 +174,9 @@ "ConnectionStrings__cosmosdb": "{cosmosdb.connectionString}", "ConnectionStrings__queue": "{queue.connectionString}", "ConnectionStrings__blob": "{blob.connectionString}", + "FUNCAPP_HTTP": "{funcapp.bindings.http.url}", "services__funcapp__http__0": "{funcapp.bindings.http.url}", + "FUNCAPP_HTTPS": "{funcapp.bindings.https.url}", "services__funcapp__https__0": "{funcapp.bindings.https.url}" }, "bindings": { diff --git a/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/funcapp-containerapp.module.bicep b/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/funcapp-containerapp.module.bicep new file mode 100644 index 00000000000..e8c22d76574 --- /dev/null +++ b/playground/AzureFunctionsEndToEnd/AzureFunctionsEndToEnd.AppHost/funcapp-containerapp.module.bicep @@ -0,0 +1,228 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param env_outputs_azure_container_apps_environment_default_domain string + +param env_outputs_azure_container_apps_environment_id string + +param env_outputs_azure_container_registry_endpoint string + +param env_outputs_azure_container_registry_managed_identity_id string + +param funcapp_containerimage string + +param funcapp_identity_outputs_id string + +param funcstorage67c6c_outputs_blobendpoint string + +param funcstorage67c6c_outputs_queueendpoint string + +param funcstorage67c6c_outputs_tableendpoint string + +param eventhubs_outputs_eventhubsendpoint string + +param messaging_outputs_servicebusendpoint string + +param cosmosdb_outputs_connectionstring string + +param storage_outputs_blobendpoint string + +param storage_outputs_queueendpoint string + +param funcapp_identity_outputs_clientid string + +resource funcapp 'Microsoft.App/containerApps@2025-02-02-preview' = { + name: 'funcapp' + location: location + properties: { + configuration: { + activeRevisionsMode: 'Single' + ingress: { + external: true + targetPort: 8080 + transport: 'http' + } + registries: [ + { + server: env_outputs_azure_container_registry_endpoint + identity: env_outputs_azure_container_registry_managed_identity_id + } + ] + runtime: { + dotnet: { + autoConfigureDataProtection: true + } + } + } + environmentId: env_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: funcapp_containerimage + name: 'funcapp' + env: [ + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY' + value: 'in_memory' + } + { + name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED' + value: 'true' + } + { + name: 'FUNCTIONS_WORKER_RUNTIME' + value: 'dotnet-isolated' + } + { + name: 'AzureFunctionsJobHost__telemetryMode' + value: 'OpenTelemetry' + } + { + name: 'ASPNETCORE_URLS' + value: 'http://+:8080' + } + { + name: 'AzureWebJobsStorage__blobServiceUri' + value: funcstorage67c6c_outputs_blobendpoint + } + { + name: 'AzureWebJobsStorage__queueServiceUri' + value: funcstorage67c6c_outputs_queueendpoint + } + { + name: 'AzureWebJobsStorage__tableServiceUri' + value: funcstorage67c6c_outputs_tableendpoint + } + { + name: 'Aspire__Azure__Storage__Blobs__AzureWebJobsStorage__ServiceUri' + value: funcstorage67c6c_outputs_blobendpoint + } + { + name: 'Aspire__Azure__Storage__Queues__AzureWebJobsStorage__ServiceUri' + value: funcstorage67c6c_outputs_queueendpoint + } + { + name: 'Aspire__Azure__Data__Tables__AzureWebJobsStorage__ServiceUri' + value: funcstorage67c6c_outputs_tableendpoint + } + { + name: 'myhub__fullyQualifiedNamespace' + value: eventhubs_outputs_eventhubsendpoint + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventHubProducerClient__myhub__FullyQualifiedNamespace' + value: eventhubs_outputs_eventhubsendpoint + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventHubConsumerClient__myhub__FullyQualifiedNamespace' + value: eventhubs_outputs_eventhubsendpoint + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventProcessorClient__myhub__FullyQualifiedNamespace' + value: eventhubs_outputs_eventhubsendpoint + } + { + name: 'Aspire__Azure__Messaging__EventHubs__PartitionReceiver__myhub__FullyQualifiedNamespace' + value: eventhubs_outputs_eventhubsendpoint + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventHubBufferedProducerClient__myhub__FullyQualifiedNamespace' + value: eventhubs_outputs_eventhubsendpoint + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventHubProducerClient__myhub__EventHubName' + value: 'myhub' + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventHubConsumerClient__myhub__EventHubName' + value: 'myhub' + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventProcessorClient__myhub__EventHubName' + value: 'myhub' + } + { + name: 'Aspire__Azure__Messaging__EventHubs__PartitionReceiver__myhub__EventHubName' + value: 'myhub' + } + { + name: 'Aspire__Azure__Messaging__EventHubs__EventHubBufferedProducerClient__myhub__EventHubName' + value: 'myhub' + } + { + name: 'messaging__fullyQualifiedNamespace' + value: messaging_outputs_servicebusendpoint + } + { + name: 'Aspire__Azure__Messaging__ServiceBus__messaging__FullyQualifiedNamespace' + value: messaging_outputs_servicebusendpoint + } + { + name: 'cosmosdb__accountEndpoint' + value: cosmosdb_outputs_connectionstring + } + { + name: 'Aspire__Microsoft__EntityFrameworkCore__Cosmos__cosmosdb__AccountEndpoint' + value: cosmosdb_outputs_connectionstring + } + { + name: 'Aspire__Microsoft__Azure__Cosmos__cosmosdb__AccountEndpoint' + value: cosmosdb_outputs_connectionstring + } + { + name: 'ConnectionStrings__myblobcontainer' + value: 'Endpoint=${storage_outputs_blobendpoint};ContainerName=myblobcontainer' + } + { + name: 'blob__blobServiceUri' + value: storage_outputs_blobendpoint + } + { + name: 'blob__queueServiceUri' + value: storage_outputs_queueendpoint + } + { + name: 'Aspire__Azure__Storage__Blobs__blob__ServiceUri' + value: storage_outputs_blobendpoint + } + { + name: 'queue__queueServiceUri' + value: storage_outputs_queueendpoint + } + { + name: 'Aspire__Azure__Storage__Queues__queue__ServiceUri' + value: storage_outputs_queueendpoint + } + { + name: 'AZURE_CLIENT_ID' + value: funcapp_identity_outputs_clientid + } + { + name: 'AZURE_TOKEN_CREDENTIALS' + value: 'ManagedIdentityCredential' + } + ] + } + ] + scale: { + minReplicas: 1 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${funcapp_identity_outputs_id}': { } + '${env_outputs_azure_container_registry_managed_identity_id}': { } + } + } + kind: 'functionapp' +} \ No newline at end of file diff --git a/playground/AzureKusto/AzureKusto.AppHost/aspire-manifest.json b/playground/AzureKusto/AzureKusto.AppHost/aspire-manifest.json index a86b85a4d90..d70d9193dc5 100644 --- a/playground/AzureKusto/AzureKusto.AppHost/aspire-manifest.json +++ b/playground/AzureKusto/AzureKusto.AppHost/aspire-manifest.json @@ -22,7 +22,7 @@ "path": "../AzureKusto.Worker/AzureKusto.Worker.csproj", "deployment": { "type": "azure.bicep.v0", - "path": "worker.module.bicep", + "path": "worker-containerapp.module.bicep", "params": { "infra_outputs_azure_container_apps_environment_default_domain": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "infra_outputs_azure_container_apps_environment_id": "{infra.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", diff --git a/playground/AzureKusto/AzureKusto.AppHost/worker-containerapp.module.bicep b/playground/AzureKusto/AzureKusto.AppHost/worker-containerapp.module.bicep new file mode 100644 index 00000000000..7d881573dab --- /dev/null +++ b/playground/AzureKusto/AzureKusto.AppHost/worker-containerapp.module.bicep @@ -0,0 +1,84 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param infra_outputs_azure_container_apps_environment_default_domain string + +param infra_outputs_azure_container_apps_environment_id string + +param infra_outputs_azure_container_registry_endpoint string + +param infra_outputs_azure_container_registry_managed_identity_id string + +param worker_containerimage string + +param worker_identity_outputs_id string + +param kusto_outputs_clusteruri string + +param worker_identity_outputs_clientid string + +resource worker 'Microsoft.App/containerApps@2025-02-02-preview' = { + name: 'worker' + location: location + properties: { + configuration: { + activeRevisionsMode: 'Single' + registries: [ + { + server: infra_outputs_azure_container_registry_endpoint + identity: infra_outputs_azure_container_registry_managed_identity_id + } + ] + runtime: { + dotnet: { + autoConfigureDataProtection: true + } + } + } + environmentId: infra_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: worker_containerimage + name: 'worker' + env: [ + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY' + value: 'in_memory' + } + { + name: 'ConnectionStrings__testdb' + value: '${kusto_outputs_clusteruri};Initial Catalog=testdb' + } + { + name: 'AZURE_CLIENT_ID' + value: worker_identity_outputs_clientid + } + { + name: 'AZURE_TOKEN_CREDENTIALS' + value: 'ManagedIdentityCredential' + } + ] + } + ] + scale: { + minReplicas: 1 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${worker_identity_outputs_id}': { } + '${infra_outputs_azure_container_registry_managed_identity_id}': { } + } + } +} \ No newline at end of file diff --git a/playground/ExternalServices/ExternalServices.AppHost/aspire-manifest.json b/playground/ExternalServices/ExternalServices.AppHost/aspire-manifest.json index 368edbe202f..6eec2fbfe24 100644 --- a/playground/ExternalServices/ExternalServices.AppHost/aspire-manifest.json +++ b/playground/ExternalServices/ExternalServices.AppHost/aspire-manifest.json @@ -19,7 +19,7 @@ ], "env": { "ASPNETCORE_ENVIRONMENT": "Production", - "services__nuget__https__0": "https://api.nuget.org/", + "NUGET": "https://api.nuget.org/", "REVERSEPROXY__ROUTES__route0__MATCH__PATH": "/nuget/{**catchall}", "REVERSEPROXY__ROUTES__route0__CLUSTERID": "cluster_nuget", "REVERSEPROXY__ROUTES__route0__TRANSFORMS__0__PathRemovePrefix": "/nuget", @@ -28,7 +28,9 @@ "REVERSEPROXY__ROUTES__route1__TRANSFORMS__0__PathRemovePrefix": "/external-service", "REVERSEPROXY__CLUSTERS__cluster_nuget__DESTINATIONS__destination1__ADDRESS": "https://api.nuget.org/", "REVERSEPROXY__CLUSTERS__cluster_external-service__DESTINATIONS__destination1__ADDRESS": "{external-service-url.value}", - "services__external-service__default__0": "{external-service-url.value}" + "services__nuget__https__0": "https://api.nuget.org/", + "services__external-service__default__0": "{external-service-url.value}", + "EXTERNAL-SERVICE": "{external-service-url.value}" }, "bindings": { "http": { @@ -48,8 +50,10 @@ "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory", "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", "HTTP_PORTS": "{frontend.bindings.http.targetPort}", + "NUGET": "https://api.nuget.org/", "services__nuget__https__0": "https://api.nuget.org/", "EXTERNAL_SERVICE_URL": "{external-service-url.value}", + "GATEWAY_HTTP": "{gateway.bindings.http.url}", "services__gateway__http__0": "{gateway.bindings.http.url}" }, "bindings": { diff --git a/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/aspire-manifest.json b/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/aspire-manifest.json index 0a9e9a0ba3b..e2673730217 100644 --- a/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/aspire-manifest.json +++ b/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/aspire-manifest.json @@ -27,7 +27,7 @@ "path": "../GitHubModelsEndToEnd.WebStory/GitHubModelsEndToEnd.WebStory.csproj", "deployment": { "type": "azure.bicep.v0", - "path": "webstory.module.bicep", + "path": "webstory-containerapp.module.bicep", "params": { "env_outputs_azure_container_apps_environment_default_domain": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}", "env_outputs_azure_container_apps_environment_id": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}", diff --git a/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/webstory-containerapp.module.bicep b/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/webstory-containerapp.module.bicep new file mode 100644 index 00000000000..57f3933370c --- /dev/null +++ b/playground/GitHubModelsEndToEnd/GitHubModelsEndToEnd.AppHost/webstory-containerapp.module.bicep @@ -0,0 +1,109 @@ +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param env_outputs_azure_container_apps_environment_default_domain string + +param env_outputs_azure_container_apps_environment_id string + +param env_outputs_azure_container_registry_endpoint string + +param env_outputs_azure_container_registry_managed_identity_id string + +param webstory_containerimage string + +param webstory_containerport string + +@secure() +param chat_gh_apikey_value string + +resource webstory 'Microsoft.App/containerApps@2025-02-02-preview' = { + name: 'webstory' + location: location + properties: { + configuration: { + secrets: [ + { + name: 'connectionstrings--chat' + value: 'Endpoint=https://models.github.ai/inference;Key=${chat_gh_apikey_value};Model=openai/gpt-4o-mini' + } + { + name: 'chat-key' + value: chat_gh_apikey_value + } + ] + activeRevisionsMode: 'Single' + ingress: { + external: true + targetPort: int(webstory_containerport) + transport: 'http' + } + registries: [ + { + server: env_outputs_azure_container_registry_endpoint + identity: env_outputs_azure_container_registry_managed_identity_id + } + ] + runtime: { + dotnet: { + autoConfigureDataProtection: true + } + } + } + environmentId: env_outputs_azure_container_apps_environment_id + template: { + containers: [ + { + image: webstory_containerimage + name: 'webstory' + env: [ + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES' + value: 'true' + } + { + name: 'OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY' + value: 'in_memory' + } + { + name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED' + value: 'true' + } + { + name: 'HTTP_PORTS' + value: webstory_containerport + } + { + name: 'ConnectionStrings__chat' + secretRef: 'connectionstrings--chat' + } + { + name: 'CHAT_URI' + value: 'https://models.github.ai/inference' + } + { + name: 'CHAT_KEY' + secretRef: 'chat-key' + } + { + name: 'CHAT_MODEL' + value: 'openai/gpt-4o-mini' + } + ] + } + ] + scale: { + minReplicas: 1 + } + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${env_outputs_azure_container_registry_managed_identity_id}': { } + } + } +} \ No newline at end of file diff --git a/playground/TestShop/TestShop.AppHost/aspire-manifest.json b/playground/TestShop/TestShop.AppHost/aspire-manifest.json index 1da88c2b39f..3987a89ec95 100644 --- a/playground/TestShop/TestShop.AppHost/aspire-manifest.json +++ b/playground/TestShop/TestShop.AppHost/aspire-manifest.json @@ -194,9 +194,13 @@ "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory", "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", "HTTP_PORTS": "{frontend.bindings.http.targetPort}", + "BASKETSERVICE_HTTP": "{basketservice.bindings.http.url}", "services__basketservice__http__0": "{basketservice.bindings.http.url}", + "BASKETSERVICE_HTTPS": "{basketservice.bindings.https.url}", "services__basketservice__https__0": "{basketservice.bindings.https.url}", + "CATALOGSERVICE_HTTP": "{catalogservice.bindings.http.url}", "services__catalogservice__http__0": "{catalogservice.bindings.http.url}", + "CATALOGSERVICE_HTTPS": "{catalogservice.bindings.https.url}", "services__catalogservice__https__0": "{catalogservice.bindings.https.url}" }, "bindings": { @@ -238,7 +242,7 @@ ], "env": { "ASPNETCORE_ENVIRONMENT": "Development", - "services__catalogservice__http__0": "{catalogservice.bindings.http.url}", + "CATALOGSERVICE_HTTP": "{catalogservice.bindings.http.url}", "REVERSEPROXY__ROUTES__route0__MATCH__PATH": "/catalog/{**catch-all}", "REVERSEPROXY__ROUTES__route0__CLUSTERID": "cluster_catalogservice", "REVERSEPROXY__ROUTES__route0__TRANSFORMS__0__PathRemovePrefix": "/catalog", @@ -247,6 +251,8 @@ "REVERSEPROXY__ROUTES__route1__TRANSFORMS__0__PathRemovePrefix": "/basket", "REVERSEPROXY__CLUSTERS__cluster_catalogservice__DESTINATIONS__destination1__ADDRESS": "http://_http.catalogservice", "REVERSEPROXY__CLUSTERS__cluster_basketservice__DESTINATIONS__destination1__ADDRESS": "http://_http.basketservice", + "services__catalogservice__http__0": "{catalogservice.bindings.http.url}", + "BASKETSERVICE_HTTP": "{basketservice.bindings.http.url}", "services__basketservice__http__0": "{basketservice.bindings.http.url}" }, "bindings": { diff --git a/playground/keycloak/Keycloak.AppHost/aspire-manifest.json b/playground/keycloak/Keycloak.AppHost/aspire-manifest.json index 0f04c6bd98c..7343d3fa46f 100644 --- a/playground/keycloak/Keycloak.AppHost/aspire-manifest.json +++ b/playground/keycloak/Keycloak.AppHost/aspire-manifest.json @@ -51,7 +51,9 @@ "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory", "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", "HTTP_PORTS": "{apiservice.bindings.http.targetPort}", + "KEYCLOAK_HTTP": "{keycloak.bindings.http.url}", "services__keycloak__http__0": "{keycloak.bindings.http.url}", + "KEYCLOAK_MANAGEMENT": "{keycloak.bindings.management.url}", "services__keycloak__management__0": "{keycloak.bindings.management.url}" }, "bindings": { @@ -76,9 +78,13 @@ "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory", "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", "HTTP_PORTS": "{webfrontend.bindings.http.targetPort}", + "KEYCLOAK_HTTP": "{keycloak.bindings.http.url}", "services__keycloak__http__0": "{keycloak.bindings.http.url}", + "KEYCLOAK_MANAGEMENT": "{keycloak.bindings.management.url}", "services__keycloak__management__0": "{keycloak.bindings.management.url}", + "APISERVICE_HTTP": "{apiservice.bindings.http.url}", "services__apiservice__http__0": "{apiservice.bindings.http.url}", + "APISERVICE_HTTPS": "{apiservice.bindings.https.url}", "services__apiservice__https__0": "{apiservice.bindings.https.url}" }, "bindings": { diff --git a/playground/python/Python.AppHost/aspire-manifest.json b/playground/python/Python.AppHost/aspire-manifest.json index 732dcb07adf..5a5f9c79e15 100644 --- a/playground/python/Python.AppHost/aspire-manifest.json +++ b/playground/python/Python.AppHost/aspire-manifest.json @@ -80,6 +80,63 @@ "targetPort": 8001 } } + }, + "flask-app": { + "type": "container.v1", + "build": { + "context": "../flask_app", + "dockerfile": "flask-app.Dockerfile" + }, + "args": [ + "run", + "--host=0.0.0.0", + "--port=8002" + ], + "env": { + "OTEL_TRACES_EXPORTER": "otlp", + "OTEL_LOGS_EXPORTER": "otlp", + "OTEL_METRICS_EXPORTER": "otlp", + "OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED": "true", + "FLASK_APP": "app:create_app" + }, + "bindings": { + "http": { + "scheme": "http", + "protocol": "tcp", + "transport": "http", + "targetPort": 8002 + } + } + }, + "uvicorn-app": { + "type": "container.v1", + "build": { + "context": "../uvicorn_app", + "dockerfile": "uvicorn-app.Dockerfile" + }, + "args": [ + "app:app", + "--host", + "0.0.0.0", + "--port", + "{uvicorn-app.bindings.http.targetPort}" + ], + "env": { + "OTEL_TRACES_EXPORTER": "otlp", + "OTEL_LOGS_EXPORTER": "otlp", + "OTEL_METRICS_EXPORTER": "otlp", + "OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED": "true", + "PORT": "{uvicorn-app.bindings.http.targetPort}" + }, + "bindings": { + "http": { + "scheme": "http", + "protocol": "tcp", + "transport": "http", + "targetPort": 8003, + "external": true + } + } } } } \ No newline at end of file diff --git a/playground/python/Python.AppHost/flask-app.Dockerfile b/playground/python/Python.AppHost/flask-app.Dockerfile new file mode 100644 index 00000000000..f94c58a2210 --- /dev/null +++ b/playground/python/Python.AppHost/flask-app.Dockerfile @@ -0,0 +1,46 @@ +FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder + +# Enable bytecode compilation and copy mode for the virtual environment +ENV UV_COMPILE_BYTECODE=1 +ENV UV_LINK_MODE=copy + +WORKDIR /app + +# Copy pyproject.toml to install dependencies +COPY pyproject.toml /app/ + +# Install dependencies and generate lock file +# Uses BuildKit cache mount to speed up repeated builds +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-install-project --no-dev + +# Copy the rest of the application source and install the project +COPY . /app +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-dev + +FROM python:3.13-slim-bookworm AS app + +# ------------------------------ +# 🚀 Runtime stage +# ------------------------------ +# Create non-root user for security +RUN groupadd --system --gid 999 appuser && useradd --system --gid 999 --uid 999 --create-home appuser + +# Copy the application and virtual environment from builder +COPY --from=builder --chown=appuser:appuser /app /app + +# Add virtual environment to PATH and set VIRTUAL_ENV +ENV PATH=/app/.venv/bin:${PATH} +ENV VIRTUAL_ENV=/app/.venv +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# Use the non-root user to run the application +USER appuser + +# Set working directory +WORKDIR /app + +# Run the application +ENTRYPOINT ["python","-m","flask"] diff --git a/playground/python/Python.AppHost/uvicorn-app.Dockerfile b/playground/python/Python.AppHost/uvicorn-app.Dockerfile new file mode 100644 index 00000000000..c09afef949d --- /dev/null +++ b/playground/python/Python.AppHost/uvicorn-app.Dockerfile @@ -0,0 +1,43 @@ +FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder + +# Enable bytecode compilation and copy mode for the virtual environment +ENV UV_COMPILE_BYTECODE=1 +ENV UV_LINK_MODE=copy + +WORKDIR /app + +# Install dependencies first for better layer caching +# Uses BuildKit cache mounts to speed up repeated builds +RUN --mount=type=cache,target=/root/.cache/uv --mount=type=bind,source=uv.lock,target=uv.lock --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --locked --no-install-project --no-dev + +# Copy the rest of the application source and install the project +COPY . /app +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --locked --no-dev + +FROM python:3.13-slim-bookworm AS app + +# ------------------------------ +# 🚀 Runtime stage +# ------------------------------ +# Create non-root user for security +RUN groupadd --system --gid 999 appuser && useradd --system --gid 999 --uid 999 --create-home appuser + +# Copy the application and virtual environment from builder +COPY --from=builder --chown=appuser:appuser /app /app + +# Add virtual environment to PATH and set VIRTUAL_ENV +ENV PATH=/app/.venv/bin:${PATH} +ENV VIRTUAL_ENV=/app/.venv +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# Use the non-root user to run the application +USER appuser + +# Set working directory +WORKDIR /app + +# Run the application +ENTRYPOINT ["uvicorn"] diff --git a/playground/waitfor/WaitForSandbox.AppHost/aspire-manifest.json b/playground/waitfor/WaitForSandbox.AppHost/aspire-manifest.json index eb2f57f15d0..03e036f2476 100644 --- a/playground/waitfor/WaitForSandbox.AppHost/aspire-manifest.json +++ b/playground/waitfor/WaitForSandbox.AppHost/aspire-manifest.json @@ -79,7 +79,9 @@ "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory", "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true", "HTTP_PORTS": "{frontend.bindings.http.targetPort}", + "API_HTTP": "{api.bindings.http.url}", "services__api__http__0": "{api.bindings.http.url}", + "API_HTTPS": "{api.bindings.https.url}", "services__api__https__0": "{api.bindings.https.url}" }, "bindings": { diff --git a/playground/withdockerfile/WithDockerfile.AppHost/dynamic-sync.Dockerfile b/playground/withdockerfile/WithDockerfile.AppHost/dynamic-sync.Dockerfile index e5a9f23be8d..75fc0407034 100644 --- a/playground/withdockerfile/WithDockerfile.AppHost/dynamic-sync.Dockerfile +++ b/playground/withdockerfile/WithDockerfile.AppHost/dynamic-sync.Dockerfile @@ -1,7 +1,7 @@ FROM golang:1.22-alpine AS builder WORKDIR /app COPY . . -RUN echo "Built at 20251017161737" > /build-info.txt +RUN echo "Built at 20251029163708" > /build-info.txt RUN go build -o qots . FROM alpine:latest diff --git a/playground/yarp/Yarp.AppHost/aspire-manifest.json b/playground/yarp/Yarp.AppHost/aspire-manifest.json index 4550d25b3f7..ba98ee6738d 100644 --- a/playground/yarp/Yarp.AppHost/aspire-manifest.json +++ b/playground/yarp/Yarp.AppHost/aspire-manifest.json @@ -56,7 +56,7 @@ ], "env": { "ASPNETCORE_ENVIRONMENT": "Development", - "services__frontend__http__0": "{frontend.bindings.http.url}", + "FRONTEND_HTTP": "{frontend.bindings.http.url}", "REVERSEPROXY__ROUTES__route0__MATCH__PATH": "/{**catchall}", "REVERSEPROXY__ROUTES__route0__CLUSTERID": "cluster_frontend", "REVERSEPROXY__ROUTES__route1__MATCH__PATH": "/api/{**catch-all}", @@ -64,8 +64,12 @@ "REVERSEPROXY__ROUTES__route1__TRANSFORMS__0__PathRemovePrefix": "/api", "REVERSEPROXY__CLUSTERS__cluster_frontend__DESTINATIONS__destination1__ADDRESS": "https\u002Bhttp://frontend", "REVERSEPROXY__CLUSTERS__cluster_backend__DESTINATIONS__destination1__ADDRESS": "https\u002Bhttp://backend", + "services__frontend__http__0": "{frontend.bindings.http.url}", + "FRONTEND_HTTPS": "{frontend.bindings.https.url}", "services__frontend__https__0": "{frontend.bindings.https.url}", + "BACKEND_HTTP": "{backend.bindings.http.url}", "services__backend__http__0": "{backend.bindings.http.url}", + "BACKEND_HTTPS": "{backend.bindings.https.url}", "services__backend__https__0": "{backend.bindings.https.url}" }, "bindings": { @@ -94,7 +98,9 @@ "REVERSEPROXY__ROUTES__route0__CLUSTERID": "cluster_backend", "REVERSEPROXY__ROUTES__route0__TRANSFORMS__0__PathRemovePrefix": "/api", "REVERSEPROXY__CLUSTERS__cluster_backend__DESTINATIONS__destination1__ADDRESS": "https\u002Bhttp://backend", + "BACKEND_HTTP": "{backend.bindings.http.url}", "services__backend__http__0": "{backend.bindings.http.url}", + "BACKEND_HTTPS": "{backend.bindings.https.url}", "services__backend__https__0": "{backend.bindings.https.url}" }, "bindings": {