visit
Before we kick this off, it'sĀ REALLY IMPORTANTĀ to note that Container Apps isĀ currently in preview! That means what I publish in my present might/will change in your future! One example of this is that the namespace that Container Apps currently reside in will be changing in March 2022, as referenced inĀ
To work with Bicep, there's a fantasticĀ
To work with Bicep, you'll also need to have Azure CLI version 2.20.0 or later. Check outĀ
@description('Name of the log analytics workspace')
param logAnalyticsName string
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = {
name: logAnalyticsName
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
}
Next up we will need to create an Azure Container Registry. In future posts, I'll show you how we can pull images from our container registry and deploy it to a Container App. But for now, we can create our Container Registry in Bicep like so:
@description('Name of the connected Container Registry')
param containerRegistryName string
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-12-01-preview' = {
name: containerRegistryName
location: location
sku: {
name: 'Basic'
}
properties: {
adminUserEnabled: true
}
}
Usually, weĀ shouldn'tĀ do this. Instead, we'd create a managed identity for our Container Registry and our Container App, and then assign aĀ
Let's move onto creating an environment for our Container Apps. Individual Container Apps are deployed to a singleĀ
For our Bicep template, we'll define our Container App environment and configure it to send logs to our Log Analytics workspace that we've just defined.
@description('Name of the Container App Environment')
param containerAppEnvName string
resource containerAppEnvironment 'Microsoft.Web/kubeEnvironments@2021-03-01' = {
name: containerAppEnvName
location: location
kind: 'containerenvironment'
properties: {
environmentType: 'managed'
internalLoadBalancerEnabled: false
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalytics.properties.customerId
sharedKey: logAnalytics.listKeys().primarySharedKey
}
}
}
}
Here we're providing a name for our Container Apps environment with a parameter and deploying it in the same location as our other resources. For this Container Apps environment, we are disabling the internal load balancer, because we're not working with a vNET for this environment. We can set this flag toĀ true
Ā to make this environment visible only within the vNET subnet, but that's out of scope for this article.
We set the environment type toĀ managed
Ā as this is the only supported type for Container App Environments. We then configure our environment to send logs to Log Analytics with theĀ logAnalyticsConfiguration
Ā block. Here we use theĀ customerId
Ā and theĀ primarySharedKey
, which we can access as outputs of ourĀ logAnalytics
Ā resource.
To see what else we can configure when creating Container App Environments in Bicep, check out the template referenceĀ
We now have an environment that we can deploy our Container Apps to, so let's write up some Bicep for a single Container App.
@description('Name of the TodoApi Container App')
param todoApiContainerName string
resource todoApiContainerApp 'Microsoft.Web/containerApps@2021-03-01' = {
name: todoApiContainerName
location: location
properties: {
kubeEnvironmentId: containerAppEnvironment.id
configuration: {
ingress: {
external: true
targetPort: 80
allowInsecure: false
traffic: [
{
latestRevision: true
weight: 100
}
]
}
registries: [
{
server: containerRegistry.name
username: containerRegistry.properties.loginServer
passwordSecretRef: 'container-registry-password'
}
]
secrets: [
{
name: 'container-registry-password'
value: containerRegistry.listCredentials().passwords[0].value
}
]
}
template: {
containers: [
{
name: todoApiContainerName
image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
resources: {
cpu: '0.5'
memory: '1Gi'
}
}
]
scale: {
minReplicas: 1
maxReplicas: 1
}
}
}
}
containerAppEnvironment
Ā resource.configuration
Ā block, we're enabling external Ingress and setting our target port for this Container to port 80. We deny insecure traffic and set the traffic level to our latest revision at 100%. If we hadĀ containerRegistry
Ā resource block that we defined earlier. We then provide aĀ referenceĀ to the name of the secret that we will use to store the login password for our Azure Container Registry.secret
Ā block that will create our secret that has a value containing the password needed to access our Azure Container Registry. Again, we use the output from ourĀ containerRegistry
Ā to get this password.template
Ā block, we define the container that we'll deploy to our Container App. In myĀ container
Ā array, I'm using the same name as my container app for my image, using a simple hello-world image that Microsoft has provided and setting both CPU and Memory resources (You can read how to configure your containers in Container AppsĀ scale
Ā block, I'm just setting the minimum and the maximum number of replicas to 1, but at the time of writing, we could set aĀ
For more information on what we can define in a Container Apps Bicep template, check out the template guideĀ
Our full Bicep template should look like this (I've moved things around just to tidy it up a bit, so feel free to copy and paste this if you want, or fix your template to make it look similar):
@description('Name of the log analytics workspace')
param logAnalyticsName string
@description('Name of the connected Container Registry')
param containerRegistryName string
@description('Name of the Container App Environment')
param containerAppEnvName string
@description('Name of the TodoApi Container App')
param todoApiContainerName string
param location string = resourceGroup().location
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = {
name: logAnalyticsName
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
}
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-12-01-preview' = {
name: containerRegistryName
location: location
sku: {
name: 'Basic'
}
properties: {
adminUserEnabled: true
}
}
resource containerAppEnvironment 'Microsoft.Web/kubeEnvironments@2021-03-01' = {
name: containerAppEnvName
location: location
kind: 'containerenvironment'
properties: {
environmentType: 'managed'
internalLoadBalancerEnabled: false
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalytics.properties.customerId
sharedKey: logAnalytics.listKeys().primarySharedKey
}
}
}
}
resource todoApiContainerApp 'Microsoft.Web/containerApps@2021-03-01' = {
name: todoApiContainerName
location: location
properties: {
kubeEnvironmentId: containerAppEnvironment.id
configuration: {
ingress: {
external: true
targetPort: 80
allowInsecure: false
traffic: [
{
latestRevision: true
weight: 100
}
]
}
registries: [
{
server: containerRegistry.name
username: containerRegistry.properties.loginServer
passwordSecretRef: 'container-registry-password'
}
]
secrets: [
{
name: 'container-registry-password'
value: containerRegistry.listCredentials().passwords[0].value
}
]
}
template: {
containers: [
{
name: todoApiContainerName
image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
resources: {
cpu: '0.5'
memory: '1Gi'
}
}
]
scale: {
minReplicas: 1
maxReplicas: 1
}
}
}
}
Our parameter file will look like this (You'll need to provide your own values):
{
"$schema": "//schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"logAnalyticsName": {
"value": "<log-analytics-workspace-name>"
},
"containerAppEnvName": {
"value": "<container-environment-name>"
},
"todoApiContainerName": {
"value": "<container-app-name>"
},
"containerRegistryName": {
"value": "<container-registry-name>"
}
}
}
We can now deploy our Bicep template. As you can see within the Bicep template, I've set theĀ location
Ā parameter to be the location of the resource group that we will deploy our Container App resources to.
At the time of writing, Container Apps can only be provisioned in the following environments:
With that in mind, we'll create a resource group that we'll deploy our resources to by running the following AZ CLI command.
az group create --name <name-of-your-resource-group> --location <one-of-the-above-locations>
We now have a resource group to deploy our Container App resources to. Let's do that by running the following command:
az deployment group create --resource-group <name-of-your-resource-group> --template-file <your-bicep-file>.bicep --parameters --<your-parameter-file>.json
Click onĀ Go to the resource groupĀ and we should see that all the resources we defined in our Bicep template have been deployed to Azure!
As you can see, we can manage and deploy our Container Apps using Bicep! As this awesome product grows, more features will be released meaning that we can extend our Bicep template further (
If you want a reference to the code that we've written in this post, you can do so in thisĀ
If you have any questions, feel free to reach out to me on TwitterĀ