in DevOps

Playtime with Docker.io

Today we are gonna dip our toes into Docker. To everyone who never heard of Docker, I recommend reading the introduction at their website.

Everytime I start fiddling around with new software and the possibility of breaking my computer I learned to love using virtual machines. You should do the same 😉

First, we need a new virtual machine – I prefer Vagrant:

The parameter ubuntu/trusty64 is important, because Docker needs an up-to-date system. trusty64 is shorthand for Ubuntu 14.04 (Trusty Tahr). Installation instructions for your favourite system can be found here.

We install Docker using the built in package manager.

Be careful to type apt-get install docker.io and not just docker.
To use the Docker command we symlink docker.io to /usr/local/bin/docker. Believe me, it simplifies copy/paste from samples around the web 😉

Let the fun begin

Without any further explanation type this command:

The output lists some downloads:

A nice little hello world at the end tells us it worked. But what exactly has worked?
Docker downloaded the CentOS-image, started a container from it and ran /bin/echo hello world in it. That’s it. With one little command.
If you are interested in the deeper mechanics of what happened, there is another blog post for that.
Run this command again – now it immediately returns hello world. Docker stored the downloaded image and could immediately start a container. Take a closer look at the created containers

We ran an echo command which returned immediately, so we need to use the -a flag (shows all containers, including closed ones) to display our containers. Looking at the STATUS column, we see our containers Exiting with status code 0, which is good. Now what is a container?
A Docker image is a read only blueprint to create containers. Containers run your application.
Let’s clarify this with an example.

What happened here is important to understand. The second call listed no file named test in the root directory. That is because Docker created two different containers from the CentOS image.
But we can create a new image with the first container as base and run the second command on it. Every started container gets an id. This is what you see in the CONTAINER ID column.

We are lazy and just interested in the first column of the line containing the string touch /test.

The commit command takes the container id as first argument. With the second argument you can name your new image. Looking at the output of docker images it has this format: REPOSITORY:TAG.
Now take a look at the content of our first image:

Bingo! It contains our previously created file named test.
It gets even more exciting. The Docker run command gives us the possibility to start interactively and with a terminal attached.

This opens a terminal connection to the container and we can work like in a “real” system.

Get our application inside

We create a simple web server presenting our homepage.
Inside our newly created terminal session, we install an apache web server and create our index.html.

After exiting the terminal session, the container gets closed and we can now create an image named webserver from it.

To expose the ports used by apache we have to do some port mapping to our host system. We want to use our favourite browser to see the whole beauty of our new homepage 🙂
If you are using vagrant, like you really should, exit your vagrant machine and add the following line to your Vagrantfile:

It simply exposes port 80 of the virtual machine to port 8080 on the host machine.
To apply our new Vagrantfile we have to reload the virtual machine. After the successful reload enter the vm and become root again.

A quick recap:
We created a Docker image with a webserver.
We exposed port 80 of our virtual machine to our host system.
What we need to do now is to start a new container from our webserver image and expose the port of the apache running inside this container to port 80 on our virtual machine.

Do not start the container with the service https start as argument, cause the service command returns immediately and the container therefore closes.
When we visit http://localhost:8080 with our browser of choice, we are greeted with a wonderful “This is our new homepage powered by Docker”. Isn’t that nice?
Let’s close the terminal session – and with it our container.

The web server is gone. This is another important concept of Docker. A Docker container is run in single process and should run a single process in the foreground. No services or daemons. Therefore we have to start the apache server in foreground

The command immediately returned, but after reloading our browser pointing to http://localhost:8080 we are greeted with our homepage.
A quick look at the output at the list of the running containers shows as our first running container.

It even shows the mapped ports and how long this container has been running. Docker provides us with a basic set of monitoring commands like top to see the running processes.

A full list can be found at the Docker homepage.
To close the running container we can run the docker stop command.

Dockerfiles

Commits are one – but not the preferred – way of creating Docker images. The standard way is a text file called Dockerfile describing the creation steps. For a detailed tutorial I really recommend the official [Dockerfile tutorial] (https://www.docker.io/learn/dockerfile/).

This is the Dockerfile to create the above image:

We build the the image named webserver with the following command run in the directory containing the Dockerfile:

To run this image we just type:

A visit to http://localhost:8080 with our host machines browser loads our website. This is much easier and more maintainable than our previous approach.