We’ll play a little with Docker Containers. In our container overview we’ve done a tour of the different container managed services.
For a first hands on trial, we’ll go a little more low level and use Docker on a VM. We’ll play with Docker on a single VM: no cluster, no orchestrator, just containers.
In Azure the easiest is to install a ready-made VM image. We can either use an image from the Azure Marketplace (e.g. Docker CE) or the Docker extension on any VM. We recommend trying the templates we’ve put forward in our last article. They spin a VM with Docker installed and ready to use for dev purposes with least parameters. The template is available on GitHub (with the Click to deploy button).
We can also install Docker on a laptop. We prefer not to clutter laptops with too many dev tools. Hence we recommend the VM route.
It is important to note that Docker won’t work on Ubuntu for Windows. It can be installed on Windows though.
For a first tutorial we recommend reading the Getting started in 6 steps from the Docker’s site. Only the first two steps are mandatory reading. Starting from step 3 are elements unique to Docker’s orchestrator, i.e. Docker Swarm. Docker Swarm is a container orchestrator. In future article, we’ll look at Kubernetes (as we discussed in our overview with AKS). Kubernetes is a more feature complete container orchestrator tool than Docker Swarm. It is also more widely adopted.
Here we’re going to follow the tutorial.
Part two (second step) is the crucial one. It invites us to author our first container. It is a simple enough web app built on the Python Flask Framework.
Let’s pause here.
In our VM, let’s execute the following command:
sudo docker image ls
We should get at least the following images:
REPOSITORY TAG IMAGE ID CREATED SIZE friendlyhello latest fd88801c252a 2 minutes ago 150MB python 2.7-slim b16fde09c92c 10 days ago 139MB
friendlyhello is the image we just built in the tutorial.
The first line in the Docker File we authored, i.e. FROM python:2.7-slim, states the image is based on the python:2.7-slim image. Docker transparently downloaded that image from the public Docker Hub.
We can go on the Docker Hub and find the Python repository. If we look for the 2.7-slim tag , we can click through and find its Docker File on GitHub. We can see it is based on the debian:jessie-slim image.
This illustrates the hierarchical nature of Docker images.
Running the App
Following the tutorial, we can now run the app.
The container we defined in previous section exposes port 80. We need to make sure the mapped port is open in Azure. If we are using the VM we built in our last article, we did open port 22 (SSH) but also 80 to 89. So if we execute the following command:
sudo docker run -d -p 81:80 friendlyhello
This maps the port 80 inside the container to the port 81 on the VM. The –d parameter also let the container run in the background. We can therefore do the following command in the VM:
We should see something like:
<h3>Hello World!</h3> <b>Hostname:</b> effb80f5a3d2 <b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>
The request takes a few seconds because of the redis error. This is on purpose as Redis is connected in a later part of the tutorial…
As shown in the tutorial, we can list the running containers and stop the one we created to run in the background. But let’s keep the container running for now.
Look inside the Container
We know the theory. Docker creates a user space in order to isolate the container runtime from the rest of the VM. Part of this is the file system virtualization where the container doesn’t see the entire VM file system.
We can explore that by looking at what the container sees. For that, let’s first find the container ID by listing all running containers:
sudo docker container ls --filter "ancestor=friendlyhello"
This should only list running containers using the friendlyhello image. In our case:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES effb80f5a3d2 friendlyhello "python app.py" 6 hours ago Up 6 hours 0.0.0.0:81->80/tcp compassionate_shtern
So we found the ID is effb80f5a3d2. We can now execute an interactive shell within that container:
sudo docker exec -it effb80f5a3d2 sh
We now have an interactive shell within the context of the container.
If we type pwd, we’ll find out we are in /app. That is conform to the Dockerfile working directory command.
If we type ls /, we’ll see the container has access to the OS libraries (e.g. /lib, /dev, etc.). If we explore further we’ll see the container’s view on those is limited.
Let’s go back to /app and execute the following command:
echo "New file within a running container" > abc.123
Now let’s exit the shell to go back to the VM. Let’s find the file within the VM:
sudo find -iname "abc.123"
This should yield result similar to:
If we look at the content of those files (e.g. sudo cat), we’ll find the content of the file we just created.
It is interesting to see a container at work. Although the image is read only, a container could be written into. Those files are ephemeral but they live on the host VM.
The rest of the step 2 tutorial goes on publishing the image we built into Docker Hub.
We’ll see in a future article how to do that with Azure Container Registry. As we have seen in our overview, Azure Container Registry is a private Docker Registry. It is a fully managed service in Azure.
We parallel Docker’s good tutorial on containers.
Running that in Azure isn’t much different than running it elsewhere. It is faster and more isolated.
In future article we’ll look at how to use other Azure services to run containers.