Run this sample

You also need the following command-line tools, which are probably standard on Linux and OS X systems, but may need to be installed specially on Windows. (For this purpose, you might want to use the bash emulation included in git-for-windows, with cmder if you want a more featureful console as well. Using the Windows Subsystem for Linux is an option too, but there are some potential difficulties you should be aware of.) - Standard POSIX tools, specifically chmod - The OpenSSH suite of tools, specifically ssh, scp, ssh-agent and ssh-add

We recommend that you use a Python virtual environment to run this example, but it's not mandatory. You can initialize a virtualenv this way:

Retrieve the application ID (a.k.a. client ID), authentication key (a.k.a. client secret), tenant ID and subscription ID from the Azure portal for use in the next step. This document describes where to find them (besides the subscription ID, which is in the "Overview" section of the "Subscriptions" blade.)

container.py requires a local Docker image. To get a sample one, use the following command:

docker pull mesosphere/simple-docker

Run the sample. The basic version just deploys the local image to ACS:

python example.py

The advanced version will push the image to ACR before deploying it:

python example.py --use-acr

What does example.py do?

example.py goes through all the necessary steps to take a Docker container, optionally add it to a private registry using Azure Container Registry, and then deploy it to a cluster in the cloud using Azure Container Services.

At a high level, those steps are as follows. The ones marked with [ACR] are optional and happen only if you use an Azure Container Registry by specifying the --use-acr option.

Create a resource group.

The process that container.py implements requires creating several different resources in Azure. The ResourceHelper class creates a resource group to keep them organized and separate from other resources you may have, as well as allowing you to clean up after it easily by deleting the resource group.

[ACR] Create a storage account.

Several steps of this process require an Azure storage account, one of the resources mentioned in the previous step, to hold persistent data. The StorageHelper class can be used to manage a storage account with a specific name (and create one if it doesn't exist already).

[ACR] Create an Azure Container Registry.

An Azure Container Registry is private storage for you or your organization's Docker containers. The ContainerHelper class creates one for you.

[ACR] Create a file share and upload ACR credentials into it.

To allow all the VMs in your cluster to access your Docker login credentials, you can put them in a file share in an Azure storage account. StorageHelper creates a share in the resource group from the first step. See this documentation for information on other ways of doing this.

Please also see this note to make sure this step does the right thing!

[ACR] Push your Docker image to the container registry.

By default, container.py attempts to push the local image mesosphere/simple-docker that you pulled in Run this sample above. If you'd rather use a different one, you can specify it using the --image option.

Create a container service.

To go along with the registry mentioned in the previous step, ContainerHelper also creates a container service, with DC/OS as the orchestrator, to manage deployment of containers to a cluster of virtual machines.

[ACR] Mount the file share with the Docker credentials in the cluster.

To make sure every machine in the cluster can access the Docker credentials, they must have access to the file share they were uploaded to. To do this, container.py connects to the cluster's master machine, and from there to each other node in the cluster, and runs a script from each to mount the share. See this documentation for details on this process.

Deploy the image into the cluster.

The final step in the process is the actual deployment of the image. This requires a SSH tunnel, as described in this documentation. Once the tunnel is set up, deployment requires only a single POST request against the Marathon REST API. The request contents are derived from the example in this documentation.

Connect to the cluster.

For demonstration purposes, container.py makes a simple request against the cluster's public IP address and prints the output. If you used the sample Docker container mesosphere/simple-docker, that output should be a basic HTML string:

<html>
<body>
<h1> Hello brave new world! </h1>
</body>
</html>

If you see this, it means the tutorial ran successfully. You just connected to a Docker container running a Web server on a cluster in the Azure cloud!

How is the code laid out?

The top-level script example.py is just the entry point for this example. Most of the logic is in two deployers and several helpers. The simple example uses the deployers.container_deployer.ContainerDeployer class and the top-level helper classes in the deployers.helpers package.

The advanced example using --use-acr, which adds Azure Container Registry support, uses the deployers.acr_container_deployer.ACRContainerDeployer class and the helpers in deployers.helpers.advanced as well as those from deployers.helpers.

Additionally, there are some helper scripts in the deployers/scripts subdirectory. These are used only by the advanced example.

Notes and troubleshooting

Running a container from ACR locally

If you have an image in an Azure Container Registry and want to run it on your local machine, you can do so using the Docker command line interface:

To resolve this, ssh to <SOME_URL> manually and confirm the connection after doing any necessary verification. Then the host will be stored in your known_hosts file and you should be able to connect non-interactively in the future.

Docker credential storing

In the "Upload Docker credentials into the file share" step, the example zips up the .docker directory so that it can be used in deployment of the Docker container. This works because the docker login command edits .docker/config.json to add the login credentials to it, so that they can be used to pull the image for the container from the private registry.

On Windows, at least, and probably OS X as well, Docker will attempt to use the OS's credential store for your container registry login information, rather than storing it in your .docker/config.json file. This is probably more secure in general, but it prevents the credential upload from working correctly since it expects the credentials to be in config.json.

To make this work, you must edit .docker/config.json and remove the "credsStore" entry from the JSON there. (Make sure that what you leave is still valid JSON!)

File share mounting

The cifsMount.sh script described in this document and used to mount the Azure file share in the cluster may give mount error(13): Permission denied. We are looking into the cause of this and how to resolve it.

Docker and WSL (Windows Subsystem for Linux)

In principle, container.py should work on WSL (a.k.a. "Bash on Ubuntu on Windows") but in practice there are some difficulties.

The following are some issues you might run into, with less-than-thoroughly-detailed possible solutions. If you're not comfortable implementing those solutions based on the descriptions given, using WSL might not be the right route for you.

The Docker daemon does not work with WSL, but the client does. So you can install Docker for Windows as if you were not using WSL, and then install just the client binary for WSL. (The Windows binary is not compatible with WSL.)

As of this writing, the best way to obtain the Docker client alone is to download a binary release and put it somewhere on your PATH. For example, to get version v17.05.0-ce, do the following:

Builds of WSL prior to 14936 have an issue preventing SSH tunnelling into the cluster's master node from working. As a workaround, you can add an entry for the master node in ~/.ssh/config with the parameter AddressFamily inet.

Cleaning up

This example does not clean up after itself: after it finishes running, all the Azure entities it created will still exist. To clean up, simply delete the resource group it created. By default that group is named 'containersample-group'.