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:
vagrant init ubuntu/trusty64 vagrant up vagrant ssh
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.
sudo su # i'm no fan of typing sudo apt-get update apt-get install docker.io ln -sf /usr/bin/docker.io /usr/local/bin/docker
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:
docker run centos /bin/echo hello world
The output lists some downloads:
Unable to find image centos locally Pulling repository centos 0b443ba03958: Download complete 539c0211cd76: Download complete 511136ea3c5a: Download complete 7064731afe90: Download complete hello world
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
docker ps -a
CONTAINER ID IMAGE COMMAND STATUS 0a299d24fcb1 centos:centos6 /bin/echo hello world Exit 0 31d50a766f87 centos:centos6 /bin/echo hello world Exit 0
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.
docker run centos touch /test docker run centos ls /
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.
docker ps -a | grep 'touch /test' | awk '{print $1;}'
We are lazy and just interested in the first column of the line containing the string touch /test.
docker commit 20ed75725e46 centos:centos6_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:
docker run centos:centos6_test ls /
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.
docker run -i -t centos:centos6_test bash
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.
yum -y install httpd echo "This is our new homepage powered by Docker" > /var/www/html/index.html exit
After exiting the terminal session, the container gets closed and we can now create an image named webserver from it.
docker commit __CONTAINER_ID__ webserver
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:
config.vm.network "forwarded_port", guest: 80, host: 8080
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.
vagrant reload vagrant ssh sudo su
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.
docker run -i -t -p 80:80 webserver /bin/bash service httpd start
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.
exit
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
docker run -p 80:80 webserver httpd -DFOREGROUND
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.
docker ps
CONTAINER ID COMMAND CREATED STATUS PORTS eb014569ef6f httpd -DFOREGROUND 3 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp
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.
docker top eb014569ef6f
A full list can be found at the Docker homepage.
To close the running container we can run the docker stop command.
docker stop eb014569ef6f
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:
# My first webserver with Docker # # VERSION 1.0 FROM centos MAINTAINER Markus Klepp, me@mklepp.com RUN yum -y install httpd RUN echo "This is our new homepage powered by Docker" > /var/www/html/index.html ENTRYPOINT ["httpd", "-D", "FOREGROUND"] EXPOSE 80
We build the the image named webserver with the following command run in the directory containing the Dockerfile:
docker build -t webserver .
To run this image we just type:
docker run -p 80:80 webserver
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.
You must be logged in to post a comment.