Deploying WordPress with ACI Container Groups
Azure Container Instances offer you a really easy way to run a single Docker container in the cloud. It's essentially serverless containers. But what if you wanted to use ACI to deploy an application that consists of multiple containers?
For example, to deploy a WordPress blog, you need two containers - one for the PHP website part of WordPress, and the other for the MySql database. Now it's perfectly possible to use ACI and deploy these as two separate containers (or more accurately "container groups"). First deploy the MySql container, exposing port 3306 and then deploy the WordPress container, giving it the IP address and credentials of the MySql container.
But that does mean I need to publicly expose the MySql port on the internet, where I could be vulnerable to people attempting to guess my password. Is there any way to deploy the MySql container so that only the WordPress container has access to it?
Container Groups
Well, as I mentioned in my post yesterday about Azure Container Instances, this is possible by using "Container Groups". If I declare that one or more containers are in a "container group", then they will get deployed on the same server,
There are some downsides to this approach, and container orchestrators like Kubernetes have better ways of solving this problem, but for a very simple serverless scenario where we might want to spin up two containers that can see each other for a short time, ACI container groups might be a good fit.
Currently, the Azure CLI container
command does not have much support for working with container groups. Instead, we need to create an ARM template.
Container Group ARM Template
Let's have a look at the template to deploy WordPress and MySql into a container group, and then we'll discuss how it works.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mysqlPassword": {
"type": "securestring",
"metadata": {
"description": "Root password password for the MySQL database."
}
},
"containerGroupName": {
"type": "string",
"defaultValue": "myContainerGroup",
"metadata": {
"description": "Name for the container group"
}
},
"dnsNameLabel": {
"type": "string",
"defaultValue": "aciwordpress",
"metadata": {
"description": "DNS Name Label for the container group"
}
}
},
"resources": [
{
"name": "[parameters('containerGroupName')]",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2018-02-01-preview",
"location": "[resourceGroup().location]",
"properties": {
"containers": [
{
"name": "front-end",
"properties": {
"image": "wordpress",
"resources": {
"requests": {
"cpu": 1,
"memoryInGb": 1.0
}
},
"ports": [
{
"port": 80
}
],
"environmentVariables": [
{
"name": "WORDPRESS_DB_PASSWORD",
"value": "[parameters('mysqlPassword')]"
},
{
"name": "WORDPRESS_DB_HOST",
"value": "127.0.0.1:3306"
}
]
}
},
{
"name": "back-end",
"properties": {
"image": "mysql:5.7",
"resources": {
"requests": {
"cpu": 1,
"memoryInGb": 1.0
}
},
"ports": [
{
"protocol": "tcp",
"port": "3306"
}
],
"environmentVariables": [
{
"name": "MYSQL_ROOT_PASSWORD",
"value": "[parameters('mysqlPassword')]"
}
]
}
}
],
"osType": "Linux",
"restartPolicy": "OnFailure",
"ipAddress": {
"type": "Public",
"dnsNameLabel": "[parameters('dnsNameLabel')]",
"ports": [
{
"protocol": "tcp",
"port": "80"
}
]
}
}
}
],
"outputs": {
"containerIPv4Address": {
"type": "string",
"value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', parameters('containerGroupName'))).ipAddress.ip]"
}
}
}
ARM Template Configuration
The template itself is straightforward enough, but the challenge with ARM templates is knowing what the names of all the various configuration options are. The documentation here proved helpful.
You can see that we've got one container group, with two containers in. Each container has its own environment variables. I allow the WordPress container to find the MySql container by using the WORDPRESS_DB_HOST
environment variable. In theory this could be set to localhost:3306
but because of some other issue to do with PHP I needed to use 127.0.0.1:3306
.
On the WordPress container I expose port 80 and on the MySql container port 3306, but the container group as a whole only exposes port 80, which helps keep the attack surface small.
I've also set up a restartPolicy
of OnFailure
as the WordPress container can exit if it can't talk to the MySql database, which might happen if it starts up first. And I configured a dnsNameLabel
for the container group to give us a nice friendly domain name to access our WordPress container through.
Deploying the template
Deploying the ARM template is nice and easy with the Azure CLI. Just create a resource group, deploy the template into it, and then query for the container group domain name:
# create a resource group for our
$resourceGroup = "AciGroupDemo"
$location="westeurope"
az group create -n $resourceGroup -l $location
# deploy the container group ARM template passing in custom parameters
$containerGroupName = "myWordpress"
$dnsNameLabel = "wordpressaci"
az group deployment create `
-n TestDeployment -g $resourceGroup `
--template-file "aci-wordpress.json" `
--parameters 'mysqlPassword=My5q1P@s5w0rd!' `
--parameters "containerGroupName=$containerGroupName" `
--parameters "dnsNameLabel=$dnsNameLabel"
# get the domain name of our wordpress container
az container show -g $resourceGroup -n $containerGroupName `
--query ipAddress.fqdn -o tsv
Summary
In this post I've been exploring the capabilities of container groups, rather than recommending best practices. As I said yesterday, they're not the best fit if you want long-running containers, as there are more cost-effective options. They're also not intended as a replacement for container orchestrators, but can be useful when you have a group of containers that work together and need to be deployed as a logical group. The need for ARM templates means they're not super easy to work with at the moment, but hopefully that will change as the tooling improves.
The code for this demo, along with a bunch of my other Azure Docker demos can be found here on GitHub.
Comments
Hi, I get this error: DNS name label for container group is not supported before version '2018-02-01-preview'
CristianAny ideas?
hmm, not sure, will have to try this again myself. Probably there's a non-preview version available now anyway. Also make sure you've got the latest Azure CLI
Mark HeathJust tried deploying this and I get "Error establishing a database connection" The db container appears to be up and running so I'm wondering if msft have changed something.
Chris Ainsleyshame, not sure what's changed - it's been a while since I tried running this deom
Mark Heathsame error here. You should create your db first. create database wordpress;
Felipe RochaI also get the error "Error establishing a database connection" does anyone solve this issue ?
Wisdom as a Service