Even for someone who does not care about Microsoft Azure at all, I think the “Virtual Machine Extensions” concept is something pretty darn interesting and other cloud providers do not have an equivalent.

This article is about one of them: Azure Docker Extension.

First of all, you must be wondering what a VM Extension is:

What are Virtual Machine Extensions?

In Azure, we give you a way to install things or run scripts on the virtual machine instances from outside programmatically. We call these VM extensions.

Through an agent running on all Linux and Windows images, we can deliver extensions to the machines and run them to do the task they are designed for.

Extensions are often published by Microsoft or other software vendors and offered at no additional charge.

What is the use case?

Extensions are often used for:

  • installing software (security, monitoring etc.)
  • intervening the machine from outside (reset password/ssh key)
  • running some prep scripts on the machine.

You can explore some extensions on Azure website.

In a way, extensions are like cloud-init/cloud-config. However, unlike those, Azure gives you this flexibility to add/remove extensions on the machines at any time or change their configuration.

Power of Virtual Machine Extensions

For many of those use cases, you might be just fine by installing the software or running the script yourself. However this it not easily programmable or invokeable from outside the VM from a CLI or web UI. Extensions basically give you this expressive power.

You can declaratively express extensions as resources in your deployment scripts or Azure Resource Manager templates. Check out this example, or this example.

Enter “Docker Extension”

Azure Docker Extension has two main responsibilities:

  1. install docker-engine to a machine and configure it.
  2. if specified, start containers with docker-compose

Docker Extension can help you configure:

  • command-line arguments to docker-engine
  • TLS certificates for docker client authentication
  • login credentials for Docker Hub or other registries.

As of writing, Docker Extension supports many Linux distros on Azure, such as Ubuntu Server, CoreOS, CentOS and Red Hat Enterprise Linux.

Why is it useful?

(In other words, how is this different than docker-machine or just installing docker myself?)

Docker Extension comes really handy when you want to specify docker properties of a machine or containers a machine should run as part of your deployment model.

It is deeply integrated to Azure: Deployment of Docker Extension can be considered as a deployment failure in general and it will surface as an error on the API or CLI or the management portal if that becomes the case.

Esstentially, you can install docker and even start some containers without doing any SSH. If you want your deployment plane to be Azure API, you will not switch back and forth between Azure management tools and SSH.

Starting containers with Docker Compose is really useful: If you would like to bootstrap an orchestrator (Kubernetes, Docker Swarm) or have a base set of containers (such as monitoring, log collection) on all your machines.

You basically just convert a docker-compose.yml to JSON format and use it as configuration to the Docker Extension (example below) and it will start the containers you specified.

Sample Configuration

You can use Docker Extension with no configuration at all. In this mode it will only install the Docker engine and docker-compose on the machine. Here is an example.

However, let’s say you have a virtual machine on Azure that you would like to configure the docker daemon and run some containers, such as Google’s cAdvisor for monitoring your instance.

For that, create a config.json file:

{
	"docker" : {
		"options": ["--storage-driver=aufs", "--debug"],
	},
	"compose": {
		"monitoring" : {
			"image": "google/cadvisor",
			"ports": ["8080:8080"],
			"restart": "always",
			"volumes": [
				"/:/rootfs:ro", "/var/run:/var/run:rw",
				"/sys:/sys:ro", "/var/lib/docker/:/var/lib/docker:ro"
			]
		}
	}
}

and you just use this in the azure cross-platform CLI:

azure vm extension set <vm-name> DockerExtension Microsoft.Azure.Extensions 1.* \
     --public-config config.json

in a couple of minutes, your Linux VM on Azure will start installing docker and will eventually start the cAdvisor container as you requested.

You can make it part of your ARM templates and deploy with all instances you create or do a lot more creative things programmatically.

Storing Secrets

In addition to config.json, you can have an additional configuration file to store your secrets. These secrets could be:

Microsoft Azure infrastructure encrypts these fields and delivers to your instance in a secure fashion.

Secrets configuration is also json, and looks like this:

{
    "certs": {
        "ca":   "<<base64 encoded ~/docker/ca.pem>>",
        "cert": "<<base64 encoded ~/docker/cert.pem>>",
        "key":  "<<base64 encoded ~/docker/key.pem>>"
    },
    "login": {
        "username": "<<docker-hub-credentials>>",
        "password": "<<docker-hub-credentials>>",
        "email":    "<<docker-hub-credentials>>"
    },
    "environment" : {
        "MYSQL_ROOT_PASSWORD": "<<docker-compose-will-use-this>>"
    }
}

The secrets file can be specified on the azure vm extension set command with --private-config-path <file> argument. The secrets file itself and all its keys are optional.

Learn more

You can read the User Guide of the Docker Extension on GitHub.

To give a bit historical context, Azure Docker Extension was announced the day Docker 1.0 was released. It is older than almost anything in Docker ecosystem. It was initially developed by MS Open Tech.

Later on we took it over and did a rewrite in Go, added many features and made it a lot more robust. We are committed to improving it and delivering cutting edge features.

Let us know by opening issues on the GitHub repository if you have any feedback or creative use cases!