
Vivian Andringa 11 Jul, 2022
Resource | Description |
Container Environment | Each container app requires a container environment which will hold one or many container apps. Under the hood, the environment is provisioned on the same virtual network. |
Container Registry | The container registry is where we will house the container images for our application which is then referenced by the container app. |
Container App | The container app resource itself. |
Log Analytics | We’ll use log analytics for logging various data from the container environment such as telemetry and performance logs. |
Key Vault | Key vault will be used to store secrets we’ll need for our app to access log analytics and credentials to pull images from the container registry. |
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# Checkout code
- uses: actions/checkout@main
# Log into Azure
- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
# Deploy Bicep file
- name: deploy
uses: azure/arm-deploy@v1
with:
subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }}
resourceGroupName: ${{ secrets.AZURE_RG }}
template: ./deploy/main.bicep
parameters: sqlAdminUsername=${{ secrets.SQL_USERNAME }} sqlAdmin=${{ secrets.SQL_PASSWORD }}
failOnStdErr: false
output userName string = containerRegistry.listCredentials().username
//logAnalytics.bicep
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
name: keyVaultName
}
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2020-10-01' = {
name: logAnalyticsWorkspaceName
location: location
tags: tags
properties: {
retentionInDays: 30
features: {
searchVersion: 1
}
sku: {
name: 'PerGB2018'
}
}
}
//set up a shared secret in key vault which containts the log analytics primary shared key
resource sharedKeySecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
name: sharedKeyName
parent: keyVault
properties: {
value: logAnalytics.listKeys().primarySharedKey
}
}
Here you can see the log analytics resource defined on line 7. What’s more interesting is I’ve defined another resource referencing the existing Key Vault in main.bicep on line 3. I’m using it to set the parent when we add the log analytics shared key to the vault on line 25.//containerAppEnvironment.bicep
param containerEnvironmentName string
param location string
param logAnalyticsCustomerId string
@secure()
param logAnalyticsSharedKey string
param tags object
resource env 'Microsoft.App/managedEnvironments@2022-03-01' = {
name: containerEnvironmentName
location: location
tags: tags
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalyticsCustomerId
sharedKey: logAnalyticsSharedKey
}
}
}
}
output containerAppEnvId string = env.id
Notice on line 7 we have a parameter for the log analytics shared key which is used to configure the container environment on line 19.//containerRegistry.bicep
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
name: keyVaultName
}
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' = {
name: crName
location: location
tags: tags
sku: {
name: 'Basic'
}
properties: {
adminUserEnabled: true
}
identity: {
type: 'SystemAssigned'
}
}
//adding container registry username to keyvault
resource acrUsername 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
name: usernameSecret
parent: keyVault
properties: {
value: containerRegistry.listCredentials().username
}
}
//adding container registry password to key vault
resource acrPasswordSecret1 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
name: primaryPasswordSecret
parent: keyVault
properties: {
value: containerRegistry.listCredentials().passwords[0].value
}
}
Similar to what was done in logAnalytics.bicep, the username and password are being added to key vault starting on line 23. This is important because the container app itself will utilize those secrets from Key Vault to pull the images from the registry.//containerApp.bicep
resource containerApp 'Microsoft.App/containerApps@2022-03-01' = {
name: containerAppName
location: location
tags: tags
properties: {
managedEnvironmentId: containerAppEnvId
configuration: {
activeRevisionsMode: 'Single'
ingress: {
external: true
transport: 'http'
targetPort: 3500
allowInsecure: false
traffic: [
{
latestRevision: true
weight: 100
}
]
}
secrets: [
{
name: 'container-registry-password'
value: acrPasswordSecret
}
]
registries: [
{
server: acrServerName
username: acrUsername
passwordSecretRef: 'container-registry-password'
}
]
}
template: {
containers: [
{
name: containerAppName
image: '${acrServerName}/epic-app:latest'
env: envVariables
resources: {
cpu: 1
memory: '2.0Gi'
}
}
]
scale: {
minReplicas: 1
maxReplicas: 10
}
}
}
identity: {
type: 'SystemAssigned'
}
}
Notice we’re passing in the container registry credentials and using them on line 32 so the container app will have access to pull the images. Another important line is 41 where the image is specified. We’re providing the container app the server name of the registry and the name of the image.//main.bicep
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = {
name: keyVaultName
location: location
tags: tags
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: tenant().tenantId
enabledForDeployment: true
enabledForTemplateDeployment: true
enableSoftDelete: false
accessPolicies: [
]
}
}
//module invocations:
module logAnalytics 'logAnalytics.bicep' = {
name: 'log-analytics'
params: {
tags: tags
keyVaultName: keyVault.name
location: location
logAnalyticsWorkspaceName: logAnalyticsWorkspaceName
}
}
module containerEnv 'containerAppEnvironment.bicep' = {
name: 'container-app-env'
params: {
containerEnvironmentName: containerEnvironmentName
location: location
logAnalyticsCustomerId: logAnalytics.outputs.customerId
logAnalyticsSharedKey: keyVault.getSecret('law-shared-key')
tags: tags
}
}
module containerRegistry 'containerRegistry.bicep' = {
name: 'acr'
params: {
tags: tags
crName: containerRegistryName
keyVaultName: keyVault.name
location: location
}
}
module containerApp 'containerapp.bicep' = if (isContainerImagePresent){
name: 'container-app'
params: {
tags: tags
location: location
containerAppName: containerAppName
envVariables: containerAppEnvVariables
containerAppEnvId: containerEnv.outputs.containerAppEnvId
acrServerName: containerRegistry.outputs.serverName
acrUsername: keyVault.getSecret('acr-username-shared-key')
acrPasswordSecret: keyVault.getSecret('acr-password-shared-key')
}
}
You can see here where the Key Vault resource is defined and how all the modules are being invoked and deployed. az deployment group create --resource-group rg-epic-app --template-file main.bicep --parameters isContainerImagePresent=t