Application virtualization with Docker

Order in the System

Web Server in Docker

The following example shows how to start a simple web server within a Docker container and make it accessible externally. To this end, first create the directory /opt/www on the host system and save the file index.html in this directory:

# mkdir /opt/www
# echo "Hello World..." > /opt/www/index.html

Then start a new container using the command:

# docker run -d -p 8080:8000 --name=webserver -w /opt -v /opt/www:/opt /bin/python -m SimpleHTTPServer 8000

A number of new features become apparent. You can see how to map a port within the container (here, 8000 ) on any host port. If you address the host on the mapped port (here, 8080 ), the request will be passed on to container port 8000. Furthermore, the container is assigned a fixed name in this example. The -w option sets the working directory for the container. You can make the host's volume available to the container using the -v option via a bind mount. In this case, roll out the host's previously generated directory /opt/www as /opt within the container.

Finally, start the Python interpreter within the container and access the web server module with network port 8000. The docker ps output now displays the container and points to the network port mappings. If you now run the

wget -nv -O -localhost:8080/index.html

command on the host, you will be presented with the web server's homepage within the container.

At this point, it is important to mention that Docker sets up a bridge device to the host by default and assigns it a private IP address on network 172.17.42.1/16. The network card of each container is associated with this bridge and is also assigned an IP from the private network. On the host, you can query this IP address using the command:

# docker inspect -f '{{.NetworkSettings.IPAddress}}' webserver
172.17.0.27

The docker inspect command is very useful for displaying information about a container: Run it with only the name of the container and without options. You can of course adjust the network configuration to suit your own environment. You will find more information about this online [3].

Creating Your Own Docker Image

We used the fedora image downloaded from Docker Hub up to this point in this workshop. You can now use this as a basis for your own image. You essentially have two choices to bind your changes to a container in a new image. Either you perform the changes interactively in a container and then commit them, or you create a Dockerfile in which you list all of the desired changes to an image and then initiate a build process. The first method does not scale particularly well and is only really suitable for initial testing or to create a new image quickly based on previously made changes; this is why only the Dockerfile-based version is presented here.

A Dockerfile must contain all the instructions necessary for creating a new image. This includes, for example, which basic image serves as a foundation, what additional software is needed, what the network port mappings should look like, and, of course, some meta-information, such as, who created this image. The man page for Dockerfile includes all permissible instructions. Take a quick look at these before creating more images.

Listing 3 shows a simple example of a Dockerfile that updates the existing Fedora image, installs a web server, and makes web server port 80 available to the outside world. Save the file under the name Dockerfile.

Listing 3

Dockerfile

### A Dockerfile for a simple web server based on the Fedora image.
# A Fedora image with an Apache web server on port 8080
# Version 1
# The fedora image serves as the base
FROM fedora
# Enter your name here
MAINTAINER Thorsten Scherf
# The image should include the last Fedora updates
RUN yum update -y
# Install the actual web server here
RUN yum install httpd -y
# Create a time index.html within the container this time
RUN bash -c 'echo "Hello again..." > /var/www/html/index.html'
# The web server port 80 should be accessible externally
EXPOSE 80
# Finally, the web server should start automatically
ENTRYPOINT [ "/usr/sbin/httpd" ]
CMD [ "-D", "FOREGROUND" ]

Start the build process using docker build. Make sure at this point that the command is accessed in the directory where you saved the Dockerfile (Listing  4).

Listing 4

Docker Build

# docker build -t fedora_httpd.
Uploading context 50.72 MB
Uploading context
Step 0 : FROM fedora
---> 7d3f07f8de5f
Step 1 : MAINTAINER Thorsten Scherf
---> Running in e352dfc45eb9
---> f66d1467b2c2
Removing intermediate container e352dfc45eb9
Step 2 : RUN yum update -y
---> Running in 259fb5959f4e
[...]
Step 3 : RUN yum install httpd -y
---> Running in 82dc46f6fc45
[...]
Step 4 : RUN bash -c 'echo "Hello again..." > /var/www/html/index.html'
---> Running in e1fdb6433117
---> d61972f4d053
Removing intermediate container e1fdb6433117
Step 5 : EXPOSE 80
---> Running in 435a7ee13c00
---> e480337fe56c
Removing intermediate container 435a7ee13c00
Step 6 : ENTRYPOINT [ "/usr/sbin/httpd" ]
---> Running in 505568685b0d
---> 852868a93e10
Removing intermediate container 505568685b0d
Step 7 : CMD [ "-D", "FOREGROUND" ]
---> Running in cd770f7d3a7f
---> 2cad8f94feb9
Removing intermediate container cd770f7d3a7f
Successfully built 2cad8f94feb9

You can now see how Docker executes the individual instructions from the Dockerfile and how each instruction results in a new temporary container. This is committed and then removed again. The final result is a new image consisting of a whole array of new layers. If you access Docker images, you will see a second image called fedora_httpd as well as the familiar fedora image. This is the name that you defined early on in the build process.

If you want to start a new container based on the image just created, call Docker as follows:

# docker run -d --name="www1" -P fedora_httpd -n "fedora_webserver"

The new option -P ensures that Docker binds the container's web server port to a random high network port on the host. To discover this port, again check the output from docker ps. Alternatively, you can also use the following call to figure out the network mappings used here:

# docker inspect -f '{{.Network-Settings.Ports}}' www1
map[80/tcp:[map[HostIp:0.0.0.0 HostPort:49154]]]

If you want to map to a static port instead, you can use the option -p 8080:80 when accessing docker run. Web server port 80 is tied to the host's port 8080 here. Run wget again to check that the web server is functioning correctly:

# wget -nv -O - localhost:49154
Hello again...

If everything works, you have succeeded in creating and testing your first Docker image. You can now export the successfully tested image, copy it to another host, and import it there. This portability is one of Docker's biggest advantages. You can export, for example, using the following command:

# docker save fedora_httpd > fedora_httpd.tar

Once the archive has been copied to the target host, you can import it there and assign a new name, if desired:

# cat fedora_httpd.tar | docker import - tscherf/fedora_httpd

This image is now available on an additional host and can immediately be used here. It is no longer possible to adapt the environment for another purpose. If you now create a new container based on the new image, the application runs on the second host in exactly the same way as on the host on which you tested the image. Incidentally, you can remove images you no longer require using docker rmi image. Just make sure that no containers use the image you are deleting.

Conclusions

After working your way through this Docker example, you should be able to install and configure a Docker environment. You can download existing images from the central Docker Hub. You should know how to start an image in a container and how to make it accessible externally. You can now also adapt existing images to suit your own environment and generate new images from them again. One interesting question is how to make self-generated images available on the central Docker Hub and how to create a connection between different containers using links. This is particularly interesting if, for example, you have a container running with a web server that needs to communicate with a database in another container over a secure connection. The Docker website [4] provides useful information on this topic.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus