diff --git a/docs/DeploymentGuide.md b/docs/DeploymentGuide.md index d9919c44..6c80ac54 100644 --- a/docs/DeploymentGuide.md +++ b/docs/DeploymentGuide.md @@ -301,7 +301,23 @@ azd up ## Step 5: Post-Deployment Configuration -### 5.1 Schema Registration (Automatic) +### 5.1 Run Post Deployment Script + +1. You can run the ACR build and push script from the project root. Use the appropriate command for your shell: + + - For Bash (Linux/macOS/WSL): + + ```bash + bash infra/scripts/acr_build_push.sh + ``` + + - For PowerShell (Windows): + + ```powershell + infra\scripts\acr_build_push.ps1 + ``` + +### 5.2 Schema Registration (Automatic) > Want to customize the schemas for your own documents? [Learn more about adding your own schemas here.](./CustomizeSchemaData.md) diff --git a/infra/main.bicep b/infra/main.bicep index 34c40e41..3ce3db4f 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -72,12 +72,6 @@ param gptModelVersion string = '2025-11-13' @description('Optional. Capacity of the GPT deployment: (minimum 10).') param gptDeploymentCapacity int = 300 -@description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') -param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' - -@description('Optional. The image tag for the container images.') -param imageTag string = 'latest_v2' - @description('Optional. Enable WAF for the deployment.') param enablePrivateNetworking bool = false @@ -722,11 +716,6 @@ module avmAiServices 'modules/account/aifoundry.bicep' = { customSubDomainName: 'aif-${solutionSuffix}' diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null roleAssignments: [ - { - principalId: avmManagedIdentity.outputs.principalId - roleDefinitionIdOrName: '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' // Owner role - principalType: 'ServicePrincipal' - } { principalId: avmContainerApp.outputs.systemAssignedMIPrincipalId! roleDefinitionIdOrName: 'Cognitive Services OpenAI User' @@ -888,19 +877,24 @@ module avmContainerApp 'br/public:avm/res/app/container-app:0.22.1' = { environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' enableTelemetry: enableTelemetry - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] managedIdentities: { systemAssigned: true userAssignedResourceIds: [ avmContainerRegistryReader.outputs.resourceId ] } - + containers: [ { name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { cpu: 4 memory: '8.0Gi' @@ -957,7 +951,12 @@ module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' enableTelemetry: enableTelemetry - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] tags: tags managedIdentities: { systemAssigned: true @@ -968,7 +967,7 @@ module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { containers: [ { name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' resources: { cpu: 4 memory: '8.0Gi' @@ -1079,7 +1078,7 @@ module avmContainerApp_API 'br/public:avm/res/app/container-app:0.22.1' = { } } } - + //========== Container App Web ========== // module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-web.${solutionSuffix}', 64) @@ -1089,7 +1088,12 @@ module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' enableTelemetry: enableTelemetry - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] tags: tags managedIdentities: { systemAssigned: true @@ -1119,7 +1123,7 @@ module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { containers: [ { name: 'ca-${solutionSuffix}-web' - image: '${containerRegistryEndpoint}/contentprocessorweb:${imageTag}' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' resources: { cpu: 4 memory: '8.0Gi' @@ -1162,7 +1166,7 @@ module avmContainerApp_Web 'br/public:avm/res/app/container-app:0.22.1' = { ] } } - + // ========== Container App Workflow ========== // module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-wkfl.${solutionSuffix}', 64) @@ -1172,7 +1176,12 @@ module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' enableTelemetry: enableTelemetry - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] tags: tags managedIdentities: { systemAssigned: true @@ -1183,7 +1192,7 @@ module avmContainerApp_Workflow 'br/public:avm/res/app/container-app:0.22.1' = { containers: [ { name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' resources: { cpu: 4 memory: '8.0Gi' @@ -1550,7 +1559,12 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { enableTelemetry: enableTelemetry environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] tags: tags managedIdentities: { systemAssigned: true @@ -1561,8 +1575,8 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { containers: [ { name: 'ca-${solutionSuffix}' - image: '${containerRegistryEndpoint}/contentprocessor:${imageTag}' - + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { cpu: 4 memory: '8.0Gi' @@ -1623,7 +1637,7 @@ module avmContainerApp_update 'br/public:avm/res/app/container-app:0.22.1' = { cognitiveServicePrivateEndpoint ] } - + module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-api.update.${solutionSuffix}', 64) params: { @@ -1632,7 +1646,12 @@ module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = enableTelemetry: enableTelemetry environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] tags: tags managedIdentities: { systemAssigned: true @@ -1640,11 +1659,11 @@ module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = avmContainerRegistryReader.outputs.resourceId ] } - + containers: [ { name: 'ca-${solutionSuffix}-api' - image: '${containerRegistryEndpoint}/contentprocessorapi:${imageTag}' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' resources: { cpu: 4 memory: '8.0Gi' @@ -1758,7 +1777,7 @@ module avmContainerApp_API_update 'br/public:avm/res/app/container-app:0.22.1' = cognitiveServicePrivateEndpoint ] } - + // ========== Container App Workflow Update ========== // module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22.1' = { name: take('avm.res.app.container-app-wkfl.update.${solutionSuffix}', 64) @@ -1768,7 +1787,12 @@ module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22 enableTelemetry: enableTelemetry environmentResourceId: avmContainerAppEnv.outputs.resourceId workloadProfileName: 'Consumption' - registries: null + registries: [ + { + server: avmContainerRegistry.outputs.loginServer + identity: avmContainerRegistryReader.outputs.resourceId + } + ] tags: tags managedIdentities: { systemAssigned: true @@ -1779,7 +1803,7 @@ module avmContainerApp_Workflow_update 'br/public:avm/res/app/container-app:0.22 containers: [ { name: 'ca-${solutionSuffix}-wkfl' - image: '${containerRegistryEndpoint}/contentprocessorworkflow:${imageTag}' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' resources: { cpu: 4 memory: '8.0Gi' diff --git a/infra/main.json b/infra/main.json index 7aa966c0..bb5d61a0 100644 --- a/infra/main.json +++ b/infra/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.44.1.10279", - "templateHash": "3841741921827855283" + "templateHash": "13603749367961036380" }, "name": "Content Processing Solution Accelerator", "description": "Bicep template to deploy the Content Processing Solution Accelerator with AVM compliance." @@ -105,20 +105,6 @@ "description": "Optional. Capacity of the GPT deployment: (minimum 10)." } }, - "containerRegistryEndpoint": { - "type": "string", - "defaultValue": "cpscontainerreg.azurecr.io", - "metadata": { - "description": "Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint)." - } - }, - "imageTag": { - "type": "string", - "defaultValue": "latest_v2", - "metadata": { - "description": "Optional. The image tag for the container images." - } - }, "enablePrivateNetworking": { "type": "bool", "defaultValue": false, @@ -36185,8 +36171,8 @@ "avmContainerApp_API", "avmContainerApp_Workflow", "avmManagedIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", "virtualNetwork" ] }, @@ -36241,11 +36227,6 @@ "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]", "roleAssignments": { "value": [ - { - "principalId": "[reference('avmManagedIdentity').outputs.principalId.value]", - "roleDefinitionIdOrName": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635", - "principalType": "ServicePrincipal" - }, { "principalId": "[reference('avmContainerApp').outputs.systemAssignedMIPrincipalId.value]", "roleDefinitionIdOrName": "Cognitive Services OpenAI User", @@ -41809,7 +41790,6 @@ "dependsOn": [ "avmContainerApp", "avmContainerApp_Workflow", - "avmManagedIdentity", "logAnalyticsWorkspace" ] }, @@ -44169,7 +44149,12 @@ "value": "[parameters('enableTelemetry')]" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "managedIdentities": { "value": { @@ -44183,7 +44168,7 @@ "value": [ { "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -45771,6 +45756,7 @@ "dependsOn": [ "applicationInsights", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader" ] }, @@ -45800,7 +45786,12 @@ "value": "[parameters('enableTelemetry')]" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "tags": { "value": "[parameters('tags')]" @@ -45817,7 +45808,7 @@ "value": [ { "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -47469,6 +47460,7 @@ "dependsOn": [ "applicationInsights", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader" ] }, @@ -47498,7 +47490,12 @@ "value": "[parameters('enableTelemetry')]" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "tags": { "value": "[parameters('tags')]" @@ -47546,7 +47543,7 @@ "value": [ { "name": "[format('ca-{0}-web', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorweb:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -49120,6 +49117,7 @@ "dependsOn": [ "avmContainerApp_API", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader" ] }, @@ -49149,7 +49147,12 @@ "value": "[parameters('enableTelemetry')]" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "tags": { "value": "[parameters('tags')]" @@ -49166,7 +49169,7 @@ "value": [ { "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -50751,6 +50754,7 @@ "dependsOn": [ "applicationInsights", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader" ] }, @@ -61434,7 +61438,12 @@ "value": "Consumption" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "tags": { "value": "[parameters('tags')]" @@ -61451,7 +61460,7 @@ "value": [ { "name": "[format('ca-{0}', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessor:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -63038,6 +63047,7 @@ "applicationInsights", "avmAppConfig", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader", "cognitiveServicePrivateEndpoint" ] @@ -63068,7 +63078,12 @@ "value": "Consumption" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "tags": { "value": "[parameters('tags')]" @@ -63085,7 +63100,7 @@ "value": [ { "name": "[format('ca-{0}-api', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorapi:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -64738,6 +64753,7 @@ "applicationInsights", "avmAppConfig", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader", "cognitiveServicePrivateEndpoint" ] @@ -64768,7 +64784,12 @@ "value": "Consumption" }, "registries": { - "value": null + "value": [ + { + "server": "[reference('avmContainerRegistry').outputs.loginServer.value]", + "identity": "[reference('avmContainerRegistryReader').outputs.resourceId.value]" + } + ] }, "tags": { "value": "[parameters('tags')]" @@ -64785,7 +64806,7 @@ "value": [ { "name": "[format('ca-{0}-wkfl', variables('solutionSuffix'))]", - "image": "[format('{0}/contentprocessorworkflow:{1}', parameters('containerRegistryEndpoint'), parameters('imageTag'))]", + "image": "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest", "resources": { "cpu": 4, "memory": "8.0Gi" @@ -66371,6 +66392,7 @@ "applicationInsights", "avmAppConfig", "avmContainerAppEnv", + "avmContainerRegistry", "avmContainerRegistryReader" ] } diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 44153d57..ecf93fc5 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -28,12 +28,6 @@ }, "existingFoundryProjectResourceId": { "value": "${AZURE_EXISTING_AIPROJECT_RESOURCE_ID}" - }, - "containerRegistryEndpoint": { - "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" - }, - "imageTag": { - "value": "${AZURE_ENV_IMAGETAG=latest_v2}" } } } \ No newline at end of file diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index 8e145a07..e5ef332d 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -46,12 +46,6 @@ }, "vmSize": { "value": "${AZURE_ENV_VM_SIZE}" - }, - "containerRegistryEndpoint": { - "value": "${AZURE_ENV_CONTAINER_REGISTRY_ENDPOINT}" - }, - "imageTag": { - "value": "${AZURE_ENV_IMAGETAG=latest_v2}" } } } \ No newline at end of file diff --git a/infra/main_custom.bicep b/infra/main_custom.bicep index 71add0f0..043ff9ce 100644 --- a/infra/main_custom.bicep +++ b/infra/main_custom.bicep @@ -75,12 +75,6 @@ param gptModelVersion string = '2025-11-13' @description('Optional. Capacity of the GPT deployment: (minimum 10).') param gptDeploymentCapacity int = 300 -@description('Optional. The container registry login server/endpoint for the container images (for example, an Azure Container Registry endpoint).') -param containerRegistryEndpoint string = 'cpscontainerreg.azurecr.io' - -@description('Optional. The image tag for the container images.') -param imageTag string = 'latest_v2' - @description('Optional. Enable WAF for the deployment.') param enablePrivateNetworking bool = false diff --git a/infra/scripts/acr_build_push.ps1 b/infra/scripts/acr_build_push.ps1 new file mode 100644 index 00000000..71b21dcc --- /dev/null +++ b/infra/scripts/acr_build_push.ps1 @@ -0,0 +1,216 @@ +# ============================================================================= +# ACR Build and Push Script (PowerShell) +# This script builds container images remotely using Azure Container Registry +# and updates the Container Apps to use the new images. +# ============================================================================= + param( + [string]$ResourceGroupName +) + +$ErrorActionPreference = "Stop" + +Write-Host "============================================================" +Write-Host "ACR Build and Push - Starting..." +Write-Host "============================================================" + +if ([string]::IsNullOrWhiteSpace($ResourceGroupName)) { + + Write-Host "Using azd environment values..." + + $ACR_NAME = azd env get-value CONTAINER_REGISTRY_NAME + $ACR_LOGIN_SERVER = azd env get-value CONTAINER_REGISTRY_LOGIN_SERVER + $RESOURCE_GROUP = azd env get-value AZURE_RESOURCE_GROUP + $CONTAINER_APP_NAME = azd env get-value CONTAINER_APP_NAME + $CONTAINER_API_APP_NAME = azd env get-value CONTAINER_API_APP_NAME + $CONTAINER_WEB_APP_NAME = azd env get-value CONTAINER_WEB_APP_NAME + $CONTAINER_WORKFLOW_APP_NAME = azd env get-value CONTAINER_WORKFLOW_APP_NAME + $USER_IDENTITY_ID = azd env get-value CONTAINER_APP_USER_IDENTITY_ID + +} +else { + + Write-Host "Using existing deployment from Resource Group: $ResourceGroupName" + + $RESOURCE_GROUP = $ResourceGroupName + + # Get ACR + $acr = az acr list ` + --resource-group $RESOURCE_GROUP ` + --query "[0]" ` + | ConvertFrom-Json + + if (-not $acr) { + throw "No Azure Container Registry found in $RESOURCE_GROUP" + } + + $ACR_NAME = $acr.name + $ACR_LOGIN_SERVER = $acr.loginServer + + # Get Container Apps + $containerApps = az containerapp list ` + --resource-group $RESOURCE_GROUP ` + | ConvertFrom-Json + + foreach ($app in $containerApps) { + + switch -Wildcard ($app.name) { + + "*-api" { + $CONTAINER_API_APP_NAME = $app.name + } + + "*-web" { + $CONTAINER_WEB_APP_NAME = $app.name + } + + "*-wkfl" { + $CONTAINER_WORKFLOW_APP_NAME = $app.name + } + + default { + $CONTAINER_APP_NAME = $app.name + } + } + } + + # Optional - Get Managed Identity + $USER_IDENTITY_ID = ( + az identity list ` + --resource-group $RESOURCE_GROUP ` + --query "[0].id" ` + -o tsv + ) +} + +$IMAGE_TAG = "latest" + +# Get the script directory and navigate to repo root +$ScriptDir = $PSScriptRoot +$RepoRoot = Resolve-Path (Join-Path $ScriptDir "..\..") + +Write-Host "" +Write-Host " ACR Name: $ACR_NAME" +Write-Host " ACR Login Server: $ACR_LOGIN_SERVER" +Write-Host " Resource Group: $RESOURCE_GROUP" +Write-Host " Image Tag: $IMAGE_TAG" +Write-Host "" + + # ============================================================================= + # Step 1: Build and push images to ACR using az acr build + # ============================================================================= + + Write-Host "============================================================" + Write-Host "Step 1: Building and pushing images to ACR..." + Write-Host "============================================================" + + # --- ContentProcessor --- + Write-Host "" + Write-Host " Building contentprocessor image..." + az acr build ` + --registry $ACR_NAME ` + --image "contentprocessor:$IMAGE_TAG" ` + --file "$RepoRoot\src\ContentProcessor\Dockerfile" ` + --platform linux ` + "$RepoRoot\src\ContentProcessor" + + if ($LASTEXITCODE -ne 0) { throw "Failed to build contentprocessor image" } + Write-Host " [OK] contentprocessor image built and pushed." + + # --- ContentProcessorAPI --- + Write-Host "" + Write-Host " Building contentprocessorapi image..." + az acr build ` + --registry $ACR_NAME ` + --image "contentprocessorapi:$IMAGE_TAG" ` + --file "$RepoRoot\src\ContentProcessorAPI\Dockerfile" ` + --platform linux ` + "$RepoRoot\src\ContentProcessorAPI" + + if ($LASTEXITCODE -ne 0) { throw "Failed to build contentprocessorapi image" } + Write-Host " [OK] contentprocessorapi image built and pushed." + + # --- ContentProcessorWeb --- + Write-Host "" + Write-Host " Building contentprocessorweb image..." + az acr build ` + --registry $ACR_NAME ` + --image "contentprocessorweb:$IMAGE_TAG" ` + --file "$RepoRoot\src\ContentProcessorWeb\Dockerfile" ` + --platform linux ` + "$RepoRoot\src\ContentProcessorWeb" + + if ($LASTEXITCODE -ne 0) { throw "Failed to build contentprocessorweb image" } + Write-Host " [OK] contentprocessorweb image built and pushed." + + # --- ContentProcessorWorkflow --- + Write-Host "" + Write-Host " Building contentprocessorworkflow image..." + az acr build ` + --registry $ACR_NAME ` + --image "contentprocessorworkflow:$IMAGE_TAG" ` + --file "$RepoRoot\src\ContentProcessorWorkflow\Dockerfile" ` + --platform linux ` + "$RepoRoot\src\ContentProcessorWorkflow" + + if ($LASTEXITCODE -ne 0) { throw "Failed to build contentprocessorworkflow image" } + Write-Host " [OK] contentprocessorworkflow image built and pushed." + + Write-Host "" + Write-Host " All images built and pushed successfully." + + # ============================================================================= + # Step 2: Update Container Apps to use the new images from ACR + # ============================================================================= + Write-Host "" + Write-Host "============================================================" + Write-Host "Step 2: Updating Container Apps with new images..." + Write-Host "============================================================" + + # --- Update ContentProcessor Container App --- + Write-Host "" + Write-Host " Updating $CONTAINER_APP_NAME..." + az containerapp update ` + --name $CONTAINER_APP_NAME ` + --resource-group $RESOURCE_GROUP ` + --image "$ACR_LOGIN_SERVER/contentprocessor:$IMAGE_TAG" + + if ($LASTEXITCODE -ne 0) { throw "Failed to update $CONTAINER_APP_NAME" } + Write-Host " [OK] $CONTAINER_APP_NAME updated." + + # --- Update ContentProcessorAPI Container App --- + Write-Host "" + Write-Host " Updating $CONTAINER_API_APP_NAME..." + az containerapp update ` + --name $CONTAINER_API_APP_NAME ` + --resource-group $RESOURCE_GROUP ` + --image "$ACR_LOGIN_SERVER/contentprocessorapi:$IMAGE_TAG" + + if ($LASTEXITCODE -ne 0) { throw "Failed to update $CONTAINER_API_APP_NAME" } + Write-Host " [OK] $CONTAINER_API_APP_NAME updated." + + # --- Update ContentProcessorWeb Container App --- + Write-Host "" + Write-Host " Updating $CONTAINER_WEB_APP_NAME..." + az containerapp update ` + --name $CONTAINER_WEB_APP_NAME ` + --resource-group $RESOURCE_GROUP ` + --image "$ACR_LOGIN_SERVER/contentprocessorweb:$IMAGE_TAG" + + if ($LASTEXITCODE -ne 0) { throw "Failed to update $CONTAINER_WEB_APP_NAME" } + Write-Host " [OK] $CONTAINER_WEB_APP_NAME updated." + + # --- Update ContentProcessorWorkflow Container App --- + Write-Host "" + Write-Host " Updating $CONTAINER_WORKFLOW_APP_NAME..." + az containerapp update ` + --name $CONTAINER_WORKFLOW_APP_NAME ` + --resource-group $RESOURCE_GROUP ` + --image "$ACR_LOGIN_SERVER/contentprocessorworkflow:$IMAGE_TAG" + + if ($LASTEXITCODE -ne 0) { throw "Failed to update $CONTAINER_WORKFLOW_APP_NAME" } + Write-Host " [OK] $CONTAINER_WORKFLOW_APP_NAME updated." + + Write-Host "" + Write-Host "============================================================" + Write-Host "ACR Build and Push - Completed Successfully!" + Write-Host "============================================================" diff --git a/infra/scripts/acr_build_push.sh b/infra/scripts/acr_build_push.sh new file mode 100644 index 00000000..0fdc1143 --- /dev/null +++ b/infra/scripts/acr_build_push.sh @@ -0,0 +1,201 @@ +#!/bin/bash + +# ============================================================================= +# ACR Build and Push Script +# This script builds container images remotely using Azure Container Registry +# and updates the Container Apps to use the new images. +# ============================================================================= + +set -e + +RESOURCE_GROUP_NAME="$1" + +echo "============================================================" +echo "ACR Build and Push - Starting..." +echo "============================================================" + +if [ -z "$RESOURCE_GROUP_NAME" ]; then + + echo "Using azd environment values..." + + ACR_NAME=$(azd env get-value CONTAINER_REGISTRY_NAME) + ACR_LOGIN_SERVER=$(azd env get-value CONTAINER_REGISTRY_LOGIN_SERVER) + RESOURCE_GROUP=$(azd env get-value AZURE_RESOURCE_GROUP) + + CONTAINER_APP_NAME=$(azd env get-value CONTAINER_APP_NAME) + CONTAINER_API_APP_NAME=$(azd env get-value CONTAINER_API_APP_NAME) + CONTAINER_WEB_APP_NAME=$(azd env get-value CONTAINER_WEB_APP_NAME) + CONTAINER_WORKFLOW_APP_NAME=$(azd env get-value CONTAINER_WORKFLOW_APP_NAME) + +else + + echo "Using existing deployment from Resource Group: $RESOURCE_GROUP_NAME" + + RESOURCE_GROUP="$RESOURCE_GROUP_NAME" + + ACR_NAME=$(az acr list \ + --resource-group "$RESOURCE_GROUP" \ + --query "[0].name" \ + -o tsv) + + ACR_LOGIN_SERVER=$(az acr show \ + --name "$ACR_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --query loginServer \ + -o tsv) + + while read APP; do + + case "$APP" in + + *-app) + CONTAINER_APP_NAME="$APP" + ;; + + *-api) + CONTAINER_API_APP_NAME="$APP" + ;; + + *-web) + CONTAINER_WEB_APP_NAME="$APP" + ;; + + *-wkfl) + CONTAINER_WORKFLOW_APP_NAME="$APP" + ;; + + esac + + done < <( + az containerapp list \ + --resource-group "$RESOURCE_GROUP" \ + --query "[].name" \ + -o tsv + ) + +fi + +IMAGE_TAG="latest" + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Navigate to repo root (infra/scripts -> root) +REPO_ROOT="$(realpath "$SCRIPT_DIR/../..")" + +echo "" +echo " ACR Name: $ACR_NAME" +echo " ACR Login Server: $ACR_LOGIN_SERVER" +echo " Resource Group: $RESOURCE_GROUP" +echo " Image Tag: $IMAGE_TAG" +echo "" + +# ============================================================================= +# Step 1: Build and push images to ACR using az acr build +# ============================================================================= +echo "============================================================" +echo "Step 1: Building and pushing images to ACR..." +echo "============================================================" + +# --- ContentProcessor --- +echo "" +echo " Building contentprocessor image..." +az acr build \ + --registry "$ACR_NAME" \ + --image "contentprocessor:$IMAGE_TAG" \ + --file "$REPO_ROOT/src/ContentProcessor/Dockerfile" \ + --platform linux \ + "$REPO_ROOT/src/ContentProcessor" + +echo " ✅ contentprocessor image built and pushed." + +# --- ContentProcessorAPI --- +echo "" +echo " Building contentprocessorapi image..." +az acr build \ + --registry "$ACR_NAME" \ + --image "contentprocessorapi:$IMAGE_TAG" \ + --file "$REPO_ROOT/src/ContentProcessorAPI/Dockerfile" \ + --platform linux \ + "$REPO_ROOT/src/ContentProcessorAPI" + +echo " ✅ contentprocessorapi image built and pushed." + +# --- ContentProcessorWeb --- +echo "" +echo " Building contentprocessorweb image..." +az acr build \ + --registry "$ACR_NAME" \ + --image "contentprocessorweb:$IMAGE_TAG" \ + --file "$REPO_ROOT/src/ContentProcessorWeb/Dockerfile" \ + --platform linux \ + "$REPO_ROOT/src/ContentProcessorWeb" + +echo " ✅ contentprocessorweb image built and pushed." + +# --- ContentProcessorWorkflow --- +echo "" +echo " Building contentprocessorworkflow image..." +az acr build \ + --registry "$ACR_NAME" \ + --image "contentprocessorworkflow:$IMAGE_TAG" \ + --file "$REPO_ROOT/src/ContentProcessorWorkflow/Dockerfile" \ + --platform linux \ + "$REPO_ROOT/src/ContentProcessorWorkflow" + +echo " ✅ contentprocessorworkflow image built and pushed." + +echo "" +echo " All images built and pushed successfully." + +# ============================================================================= +# Step 2: Update Container Apps to use the new images from ACR +# ============================================================================= +echo "" +echo "============================================================" +echo "Step 2: Updating Container Apps with new images..." +echo "============================================================" + +# --- Update ContentProcessor Container App --- +echo "" +echo " Updating $CONTAINER_APP_NAME..." +az containerapp update \ + --name "$CONTAINER_APP_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --image "$ACR_LOGIN_SERVER/contentprocessor:$IMAGE_TAG" + +echo " ✅ $CONTAINER_APP_NAME updated." + +# --- Update ContentProcessorAPI Container App --- +echo "" +echo " Updating $CONTAINER_API_APP_NAME..." +az containerapp update \ + --name "$CONTAINER_API_APP_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --image "$ACR_LOGIN_SERVER/contentprocessorapi:$IMAGE_TAG" + +echo " ✅ $CONTAINER_API_APP_NAME updated." + +# --- Update ContentProcessorWeb Container App --- +echo "" +echo " Updating $CONTAINER_WEB_APP_NAME..." +az containerapp update \ + --name "$CONTAINER_WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --image "$ACR_LOGIN_SERVER/contentprocessorweb:$IMAGE_TAG" + +echo " ✅ $CONTAINER_WEB_APP_NAME updated." + +# --- Update ContentProcessorWorkflow Container App --- +echo "" +echo " Updating $CONTAINER_WORKFLOW_APP_NAME..." +az containerapp update \ + --name "$CONTAINER_WORKFLOW_APP_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --image "$ACR_LOGIN_SERVER/contentprocessorworkflow:$IMAGE_TAG" + +echo " ✅ $CONTAINER_WORKFLOW_APP_NAME updated." + +echo "" +echo "============================================================" +echo "ACR Build and Push - Completed Successfully!" +echo "============================================================" \ No newline at end of file