Skip to content

Commit a309044

Browse files
authored
feat(service): deploy application in container apps (#1303)
<!--- Provide a general summary of your changes in the Title above --> ## Description <!--- Describe your changes in detail --> - Added Service in all environments in container app. Using webapi for now until Service is ready - Added user assigned identity instead of using the created managed identity created by the container app to avoid potential race conditions. This should be required eventually for all container apps. Making it optional for now. ## Related Issue(s) - #1301 ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new infrastructure configuration for deploying a container application in Azure. - Added support for multiple environments (production, staging, test) with dynamic parameter management. - Enhanced identity management for the container app, allowing for user-assigned identities. - **Bug Fixes** - Improved health probe configurations for better application monitoring. - **Documentation** - Updated workflow to include deployment capabilities for the new service component. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 1ae4f41 commit a309044

File tree

6 files changed

+217
-4
lines changed

6 files changed

+217
-4
lines changed
+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
targetScope = 'resourceGroup'
2+
3+
@description('The tag of the image to be used')
4+
@minLength(3)
5+
param imageTag string
6+
7+
@description('The environment for the deployment')
8+
@minLength(3)
9+
param environment string
10+
11+
@description('The location where the resources will be deployed')
12+
@minLength(3)
13+
param location string
14+
15+
@description('The suffix for the revision of the container app')
16+
@minLength(3)
17+
param revisionSuffix string
18+
19+
@description('CPU and memory resources for the container app')
20+
param resources object?
21+
22+
@description('The name of the container app environment')
23+
@minLength(3)
24+
@secure()
25+
param containerAppEnvironmentName string
26+
27+
@description('The connection string for Application Insights')
28+
@minLength(3)
29+
@secure()
30+
param appInsightConnectionString string
31+
32+
@description('The name of the App Configuration store')
33+
@minLength(5)
34+
param appConfigurationName string
35+
36+
@description('The name of the Key Vault for the environment')
37+
@minLength(3)
38+
param environmentKeyVaultName string
39+
40+
var namePrefix = 'dp-be-${environment}'
41+
var baseImageUrl = 'ghcr.io/digdir/dialogporten-'
42+
var tags = {
43+
Environment: environment
44+
Product: 'Dialogporten'
45+
}
46+
47+
resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = {
48+
name: appConfigurationName
49+
}
50+
51+
resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2024-03-01' existing = {
52+
name: containerAppEnvironmentName
53+
}
54+
55+
var containerAppEnvVars = [
56+
{
57+
name: 'ASPNETCORE_ENVIRONMENT'
58+
value: environment
59+
}
60+
{
61+
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
62+
value: appInsightConnectionString
63+
}
64+
{
65+
name: 'AZURE_APPCONFIG_URI'
66+
value: appConfiguration.properties.endpoint
67+
}
68+
{
69+
name: 'ASPNETCORE_URLS'
70+
value: 'http://+:8080'
71+
}
72+
]
73+
74+
resource environmentKeyVaultResource 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
75+
name: environmentKeyVaultName
76+
}
77+
78+
var serviceName = 'service'
79+
80+
var containerAppName = '${namePrefix}-${serviceName}'
81+
82+
var port = 8080
83+
84+
var probes = [
85+
{
86+
periodSeconds: 5
87+
initialDelaySeconds: 2
88+
type: 'Liveness'
89+
httpGet: {
90+
path: '/health/liveness'
91+
port: port
92+
}
93+
}
94+
{
95+
periodSeconds: 5
96+
initialDelaySeconds: 2
97+
type: 'Readiness'
98+
httpGet: {
99+
path: '/health/readiness'
100+
port: port
101+
}
102+
}
103+
{
104+
periodSeconds: 5
105+
initialDelaySeconds: 2
106+
type: 'Startup'
107+
httpGet: {
108+
path: '/health/startup'
109+
port: port
110+
}
111+
}
112+
]
113+
114+
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
115+
name: '${namePrefix}-service-identity'
116+
location: location
117+
tags: tags
118+
}
119+
120+
module keyVaultReaderAccessPolicy '../../modules/keyvault/addReaderRoles.bicep' = {
121+
name: 'keyVaultReaderAccessPolicy-${containerAppName}'
122+
params: {
123+
keyvaultName: environmentKeyVaultResource.name
124+
principalIds: [managedIdentity.properties.principalId]
125+
}
126+
}
127+
128+
module appConfigReaderAccessPolicy '../../modules/appConfiguration/addReaderRoles.bicep' = {
129+
name: 'appConfigReaderAccessPolicy-${containerAppName}'
130+
params: {
131+
appConfigurationName: appConfigurationName
132+
principalIds: [managedIdentity.properties.principalId]
133+
}
134+
}
135+
136+
module containerApp '../../modules/containerApp/main.bicep' = {
137+
name: containerAppName
138+
params: {
139+
name: containerAppName
140+
// todo: make this dynamic based on service name. Using webapi for now.
141+
// image: '${baseImageUrl}${serviceName}:${imageTag}'
142+
image: '${baseImageUrl}webapi:${imageTag}'
143+
location: location
144+
envVariables: containerAppEnvVars
145+
containerAppEnvId: containerAppEnvironment.id
146+
tags: tags
147+
resources: resources
148+
probes: probes
149+
port: port
150+
revisionSuffix: revisionSuffix
151+
userAssignedIdentityId: managedIdentity.id
152+
// TODO: Once all container apps use user-assigned identities, remove this comment and ensure userAssignedIdentityId is always provided
153+
}
154+
dependsOn: [
155+
keyVaultReaderAccessPolicy
156+
appConfigReaderAccessPolicy
157+
]
158+
}
159+
160+
output name string = containerApp.outputs.name
161+
output revisionName string = containerApp.outputs.revisionName
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using './main.bicep'
2+
3+
param environment = 'prod'
4+
param location = 'norwayeast'
5+
param imageTag = readEnvironmentVariable('IMAGE_TAG')
6+
param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX')
7+
8+
// secrets
9+
param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME')
10+
param containerAppEnvironmentName = readEnvironmentVariable('AZURE_CONTAINER_APP_ENVIRONMENT_NAME')
11+
param appInsightConnectionString = readEnvironmentVariable('AZURE_APP_INSIGHTS_CONNECTION_STRING')
12+
param appConfigurationName = readEnvironmentVariable('AZURE_APP_CONFIGURATION_NAME')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using './main.bicep'
2+
3+
param environment = 'staging'
4+
param location = 'norwayeast'
5+
param imageTag = readEnvironmentVariable('IMAGE_TAG')
6+
param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX')
7+
8+
// secrets
9+
param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME')
10+
param containerAppEnvironmentName = readEnvironmentVariable('AZURE_CONTAINER_APP_ENVIRONMENT_NAME')
11+
param appInsightConnectionString = readEnvironmentVariable('AZURE_APP_INSIGHTS_CONNECTION_STRING')
12+
param appConfigurationName = readEnvironmentVariable('AZURE_APP_CONFIGURATION_NAME')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using './main.bicep'
2+
3+
param environment = 'test'
4+
param location = 'norwayeast'
5+
param imageTag = readEnvironmentVariable('IMAGE_TAG')
6+
param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX')
7+
8+
// secrets
9+
param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME')
10+
param containerAppEnvironmentName = readEnvironmentVariable('AZURE_CONTAINER_APP_ENVIRONMENT_NAME')
11+
param appInsightConnectionString = readEnvironmentVariable('AZURE_APP_INSIGHTS_CONNECTION_STRING')
12+
param appConfigurationName = readEnvironmentVariable('AZURE_APP_CONFIGURATION_NAME')

.azure/modules/containerApp/main.bicep

+19-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ param revisionSuffix string
3131
@description('The probes for the container app')
3232
param probes array = []
3333

34+
// TODO: Refactor to make userAssignedIdentityId a required parameter once all container apps use user-assigned identities
35+
@description('The ID of the user-assigned managed identity (optional)')
36+
param userAssignedIdentityId string = ''
37+
3438
// Container app revision name does not allow '.' character
3539
var cleanedRevisionSuffix = replace(revisionSuffix, '.', '-')
3640

@@ -50,12 +54,19 @@ var ingress = {
5054
ipSecurityRestrictions: ipSecurityRestrictions
5155
}
5256

57+
var identityConfig = empty(userAssignedIdentityId) ? {
58+
type: 'SystemAssigned'
59+
} : {
60+
type: 'UserAssigned'
61+
userAssignedIdentities: {
62+
'${userAssignedIdentityId}': {}
63+
}
64+
}
65+
5366
resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
5467
name: name
5568
location: location
56-
identity: {
57-
type: 'SystemAssigned'
58-
}
69+
identity: identityConfig
5970
properties: {
6071
configuration: {
6172
ingress: ingress
@@ -81,6 +92,10 @@ resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
8192
tags: tags
8293
}
8394

84-
output identityPrincipalId string = containerApp.identity.principalId
95+
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(userAssignedIdentityId)) {
96+
name: last(split(userAssignedIdentityId, '/'))
97+
}
98+
99+
output identityPrincipalId string = empty(userAssignedIdentityId) ? containerApp.identity.principalId : managedIdentity.properties.principalId
85100
output name string = containerApp.name
86101
output revisionName string = containerApp.properties.latestRevisionName

.github/workflows/workflow-deploy-apps.yml

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ jobs:
145145
- name: web-api-eu
146146
- name: web-api-so
147147
- name: graphql
148+
- name: service
148149
environment: ${{ inputs.environment }}
149150
permissions:
150151
id-token: write

0 commit comments

Comments
 (0)