Running Universal Dashboard Docker container in Azure Web Apps for Containers.
In my previous blog post I explained how to create a Docker container which is servicing an Universal Dashboard web page.
In this blog post I want to explain how you can host this Universal Dashboard Linux Docker container on Azure App Service on Linux.
Azure App Service on Linux
Azure Web App is a fully managed compute platform that is optimized for hosting websites and web applications. Customers can use App Service on Linux to host web apps natively on Linux for supported application stacks.
App Service on Linux supports a number of Built-in images in order to increase developer productivity. If the runtime your application requires is not supported in the built-in images, there are instructions on how to build your own Docker image to deploy to Web App for Containers.
And this is exactly what we are trying to achieve here. We want to use our custom Universal Dashboard Docker image in Web App for Containers.
Requirements
Before we can use our Docker Containerized Universal Dashboard within an Azure Web App for Container we need the following pre-requisites:
- Azure Resource Group
- Azure App Service Plan
- Azure Container Registry
- Universal Dashboard Docker image stored in Azure Container Registry.
For more information about above Azure Resources please look at the References section at the end of this blog post.
Deployment steps
There are different ways to deploy the Azure Resource Group, App Service Plan and Container Registry. In this blog post I’ll be using an ARM Template which deploys these required resources.
Example ARM Template for deploying Resource Group, App Service Plan and Container Registry.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupLocation": {
"type": "string",
"defaultValue": "WestEurope"
},
"resourceGroupName": {
"type": "string",
"metadata": {
"description": "The name of the Resource Group where to host the Web App Container."
}
},
"appServicePlanName": {
"type": "string",
"metadata": {
"description": "The name of the App Service plan to use for hosting the web app."
}
},
"servicePlanTier": {
"type": "string",
"allowedValues": [
"Basic",
"Standard"
],
"defaultValue": "Basic",
"metadata": {
"description": "Tier for Service Plan"
}
},
"servicePlanSku": {
"type": "string",
"allowedValues": [
"B1",
"B2",
"B3",
"S1",
"S2",
"S3"
],
"defaultValue": "B2",
"metadata": {
"description": "Size for Service Plan"
}
},
"acrName": {
"type": "string",
"metadata": {
"description": "The name of the Azure Container Registry"
}
}
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('resourceGroupLocation')]",
"name": "[parameters('resourceGroupName')]"
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-05-10",
"name": "appServicePlanDeployment",
"resourceGroup": "[parameters('resourceGroupName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('resourceGroupName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"comments": "This is the App Service Plan deployment",
"apiVersion": "2016-09-01",
"name": "[parameters('appServicePlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[parameters('resourceGroupLocation')]",
"properties": {
"name": "[parameters('appServicePlanName')]",
"workerSizeId": "1",
"reserved": true,
"numberOfWorkers": "1",
"hostingEnvironment": ""
},
"sku": {
"Tier": "[parameters('servicePlanTier')]",
"Name": "[parameters('servicePlanSku')]"
},
"kind": "linux"
},
{
"type": "Microsoft.ContainerRegistry/registries",
"sku": {
"name": "Premium",
"tier": "Premium"
},
"name": "[parameters('acrName')]",
"apiVersion": "2017-10-01",
"location": "[parameters('resourceGroupLocation')]",
"scale": null,
"properties": {
"adminUserEnabled": true
}
}
]
}
}
}
],
"outputs": {
"acrNameOutput": {
"value": "[parameters('acrName')]",
"type": "string"
},
"ResourceGroupOutput": {
"value": "[parameters('resourceGroupName')]",
"type": "string"
}
}
}
You can use the following PowerShell script to deploy the pre-requisites:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Deploy-WebAppContainerPrereqs.ps1
# Use this script to manually deploy the ARM Template with parameter input file.
# Change variables before running deployment
#region Variables
$Location = 'WestEurope'
$ResourceGroupName = 'WebAppContainer-rg'
$appServicePlanName = 'UDAppServiceLinuxPlan'
$servicePlanTier = 'Basic'
$servicePlanSku = 'B1'
$acrName = 'UDContainerRegistry'
#endregion
#region Connect to Azure
Add-AzureRmAccount
#Select Azure Subscription
$subscription =
(Get-AzureRmSubscription |
Out-GridView `
-Title 'Select an Azure Subscription ...' `
-PassThru)
Set-AzureRmContext -SubscriptionId $subscription.Id -TenantId $subscription.TenantID
#endregion
#region variables
$ARMTemplateFile = 'C:\Users\[username]\Source\Repos\Contoso\Products\WebAppContainer\Templates\WebAppContainerPrereqs.json'
#endregion
#region create ARM Template Parameter object
$parametersARM = @{}
$parametersARM.Add('resourceGroupLocation', $Location)
$parametersARM.Add('resourceGroupName', $ResourceGroupName)
$parametersARM.Add('appServicePlanName', $appServicePlanName)
$parametersARM.Add('servicePlanTier', $servicePlanTier)
$parametersARM.Add('servicePlanSku', $servicePlanSku)
$parametersARM.Add('acrName', $acrName)
#endregion
#region Deploy ARM Template
#region Test ARM Template
Test-AzureRmDeployment `
-TemplateFile $ARMTemplateFile `
-TemplateParameterObject $parametersARM `
-Location $Location `
-OutVariable testarmtemplate
#endregion
#region Deploy ARM Template with local Parameter file
$result = (New-AzureRMDeployment `
-TemplateFile $ARMTemplateFile `
-Location $Location `
-TemplateParameterObject $parametersARM -Verbose -DeploymentDebugLogLevel All)
$result
#endregion
#endregion
After deploying the above ARM Template you would see the following Azure Resource Deployed.
Build Docker image and Push Docker image to Azure Container Registry
You could use the Azure DevOps Pipelines to build a Docker container and push that container to the Azure Container Registry, but in this blog post we will use the docker commandline tool.
Build the image from the Docker file
Read my earlier blog post “Running Universal Dashboard in a Linux Docker Container” to see how you can build a (Linux) Docker image with an example Universal Dashboard.
Push the Docker image to Azure Container Registry
Log in to Azure Container Registry
In order to push an image to the registry, you need to supply credentials so the registry accepts the push. You can retrieve these credentials by using the following PowerShell command.
1
Get-AzureRmContainerRegistryCredential -ResourceGroupName $ResourceGroupName -Name $acrName
Retrieve Login Server name of Azure Container Registry:
1
Get-AzureRmContainerRegistry -ResourceGroupName $ResourceGroupName -Name $acrName | Select-Object Name, LoginServer, ResourceGroupName
From your local terminal window, log in to the Azure Container Registry using the docker login command. The server name is required to log in. Use the format azure-container-registry-name>.azurecr.io. Type in your password into the console at the prompt.
1
docker login udcontainerregistry.azurecr.io --username UDContainerRegistry
Push an image to Azure Container Registry
Push the image by using the docker push command. Tag the image with the name of the registry, followed by your image name and tag.
If you’re using your own image, tag the image as follows:
1
docker tag udcontainerregistry.azurecr.io/udhelloworld
The tag was already added during the build of the docker image step.
Remark:
This can take some time before the push to the Azure Container Registry is finished. So get yourself a cup of coffee or go for lunch and wait for the push to be finished. If you do this step in your Azure DevOps Pipeline is way faster in my experience.
PowerShell script to push the docker image to the ACR:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# PushDockerImage.ps1
# Use this script to manually Push the Docker image to the ACR.
# Change variables before running deployment
#region Variables
$ResourceGroupName = 'WebAppContainer-rg'
$acrName = 'UDContainerRegistry'
$dockerimagename = 'udhelloworld'
$dockerimageversion = 'latest'
$dockerfile = 'C:\Users\[username]\Source\Repos\Contoso\Products\WebAppContainer\Dockerfile\dockerfile'
#endregion
#region Connect to Azure
Add-AzureRmAccount
#Select Azure Subscription
$subscription =
(Get-AzureRmSubscription |
Out-GridView `
-Title 'Select an Azure Subscription ...' `
-PassThru)
Set-AzureRmContext -SubscriptionId $subscription.Id -TenantId $subscription.TenantID
#endregion
#region Build the image from the Docker file
# docker images are case-sensitive. Make sure acrname is lowercase.
$command = ('Get-Content -Path $dockerfile | docker build - -t {0}.azurecr.io/{1}:{2}' -f $($acrName.ToLower()), $dockerimagename, $dockerimageversion)
Invoke-Expression $command
#endregion
#region Push the Docker image to Azure Container Registry
#Log in to Azure Container Registry
$ContainerAdminUser = Get-AzureRmContainerRegistryCredential -ResourceGroupName $ResourceGroupName -Name $acrName
#Retrieve Login Server name of Azure Container Registry
Get-AzureRmContainerRegistry -ResourceGroupName $ResourceGroupName -Name $acrName | Select-Object Name, LoginServer, ResourceGroupName
#login in Docker Container Registry
$command = ('docker login {0}.azurecr.io --username {1} --password {2}' -f $($acrName.ToLower()), $ContainerAdminUser.Username, $ContainerAdminUser.Password)
Invoke-Expression $command
#Push Docker image to ACR
$command = ('docker push {0}.azurecr.io/{1}:{2}' -f $($acrName.ToLower()), $dockerimagename, $dockerimageversion)
Invoke-Expression $command
#endregion
Deploy and Configure Web App to use the image from Azure Container Registry
In the last step we are going to deploy and configure the Azure Web App using below ARM Template.
ARM Template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupLocation": {
"type": "string",
"defaultValue": "WestEurope",
"metadata": {
"description": "The name of the Resource Group location."
}
},
"resourceGroupName": {
"type": "string",
"metadata": {
"description": "The name of the Resource Group."
}
},
"appServicePlanName": {
"type": "string",
"metadata": {
"description": "The name of the App Service plan to use for hosting the web app."
}
},
"acrName": {
"type": "string",
"metadata": {
"description": "The Name of the Azure Container Registry"
}
},
"siteName": {
"type": "string",
"metadata": {
"description": "Name of azure web app"
}
},
"acrImageName": {
"type": "string",
"metadata": {
"description": "The name of the docker registry"
}
},
"acrUserName": {
"type": "string",
"metadata": {
"description": "User name of the docker registry"
}
},
"acrUserPassword": {
"type": "string",
"metadata": {
"description": "The password of the docker registry"
}
},
"port": {
"type": "string",
"defaultValue": "8585",
"metadata": {
"description": "The port of the Azure container Universal Dashboard Container."
}
},
"hostNameSslStates": {
"type": "array",
"defaultValue": []
}
},
"variables": {
"hostingPlanName": "[parameters('appServicePlanName')]",
"acrUrl": "[tolower(concat(parameters('acrName'), '.azurecr.io'))]",
"linuxFxVersion": "[concat('DOCKER|',variables('acrurl'), '/', parameters('acrImageName'), ':latest')]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('resourceGroupLocation')]",
"name": "[parameters('resourceGroupName')]"
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-05-10",
"name": "WebAppContainerDeployment",
"resourceGroup": "[parameters('resourceGroupName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('resourceGroupName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"comments": "This is the Linux web app with the Docker image from Azure Container Registry",
"type": "Microsoft.Web/sites",
"kind": "app,linux,container",
"name": "[parameters('siteName')]",
"apiVersion": "2016-03-01",
"location": "[parameters('resourceGroupLocation')]",
"properties": {
"name": "[parameters('siteName')]",
"serverFarmId": "[variables('hostingPlanName')]",
"hostingEnvironment": "",
"clientAffinityEnabled": true,
"httpsOnly": true,
"siteConfig": {
"AlwaysOn": true,
"minTlsVersion": "1.2",
"ftpsState": "Disabled",
"appCommandLine": "",
"linuxFxVersion": "[variables('linuxFxVersion')]"
},
"hostNameSslStates": "[parameters('hostNameSslStates')]"
},
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('siteName'))]"
],
"properties": {
"DOCKER_REGISTRY_SERVER_URL": "[variables('acrUrl')]",
"DOCKER_REGISTRY_SERVER_USERNAME": "[parameters('acrUserName')]",
"DOCKER_REGISTRY_SERVER_PASSWORD": "[parameters('acrUserPassword')]",
"WEBSITES_PORT": "[parameters('port')]"
}
}
]
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"name": "[concat(parameters('siteName'), '/' , if(empty(parameters('hostNameSslStates')),'dummy',parameters('hostNameSslStates')[copyIndex()].name))]",
"condition": "[not(empty(parameters('hostNameSslStates')))]",
"apiVersion": "2016-03-01",
"location": "[parameters('resourceGroupLocation')]",
"properties": {},
"dependsOn": [
"[parameters('siteName')]"
],
"copy": {
"name": "bindingsCopy",
"count": "[if(empty(parameters('hostNameSslStates')),1,length(parameters('hostNameSslStates')))]",
"mode": "serial",
"batchSize": 1
}
}
]
}
}
}
],
"outputs": {
"imageNameOutput": {
"value": "[parameters('acrImageName')]",
"type": "string"
},
"dockerRegistryUrlOutput": {
"value": "[variables('acrUrl')]",
"type": "string"
},
"linuxFxVersionOutput": {
"value": "[variables('linuxFxVersion')]",
"type": "string"
}
}
}
With the following PowerShell script we can deploy the ARM Template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Deploy-WebAppContainer.ps1
# Use this script to manually deploy the ARM Template with parameter input file.
# Change variables before running deployment
#region Variables
$Location = 'WestEurope'
$ResourceGroupName = 'WebAppContainer-rg'
$appServicePlanName = 'UDAppServiceLinuxPlan'
$acrName = 'UDContainerRegistry'
$siteName = 'udhelloworlddemo'
$acrImageName = 'udhelloworld'
#endregion
#region Connect to Azure
Add-AzureRmAccount
#Select Azure Subscription
$subscription =
(Get-AzureRmSubscription |
Out-GridView `
-Title 'Select an Azure Subscription ...' `
-PassThru)
Set-AzureRmContext -SubscriptionId $subscription.Id -TenantId $subscription.TenantID
#endregion
#region variables
$ARMTemplateFile = 'C:\Users\[username]\Source\Repos\Contoso\Products\WebAppContainer\Templates\WebAppContainer.json'
#endregion
#region get ACR Admin user credentials
$ContainerAdminUser = Get-AzureRmContainerRegistryCredential -ResourceGroupName $ResourceGroupName -Name $acrName
#endregion
#region create ARM Template Parameter object
$parametersARM = @{}
$parametersARM.Add('resourceGroupLocation', $Location)
$parametersARM.Add('resourceGroupName', $ResourceGroupName)
$parametersARM.Add('appServicePlanName', $appServicePlanName)
$parametersARM.Add('acrName', $acrName)
$parametersARM.Add('siteName', $siteName)
$parametersARM.Add('acrUserName', $ContainerAdminUser.Username)
$parametersARM.Add('acrUserPassword', $ContainerAdminUser.Password)
$parametersARM.Add('acrImageName', $acrImageName)
#endregion
#region Deploy ARM Template
#region Test ARM Template
Test-AzureRmDeployment `
-TemplateFile $ARMTemplateFile `
-TemplateParameterObject $parametersARM `
-Location $Location `
-OutVariable testarmtemplate
#endregion
#region Deploy ARM Template with local Parameter file
$result = (New-AzureRMDeployment `
-TemplateFile $ARMTemplateFile `
-Location $Location `
-TemplateParameterObject $parametersARM -Verbose -DeploymentDebugLogLevel All)
$result
#endregion
#endregion
Hope you learned something new with this blog post.
References:









