Wednesday, March 4, 2015

Dockerfiles

Starting a container, doing manual changes to it and committing into a new image is error-prone and does not scale for handling many images. In this post, I will show a powerful and more precise way of shaping new images.

This method uses a file called Dockerfile to control how new images are built. It is placed in a directory and consists of keyword-parameter lines. Let's take a look:
[root@r1745042 ~]# cat apache/Dockerfile
FROM rhel7-yum
RUN yum -y install httpd
COPY index.html /var/www/html/index.html

FROM defines an image to base on. In our case, it's the yum-enabled RHEL image.
RUN statements specify, which commands are to be executed in the course of building the new image. We want to install a web server.
COPY statements copy files into the new image. In our case, we're providing an index.html file into what is httpd's default DocumentRoot directory:

[root@r1745042 ~]# cat apache/index.html
this is our new homepage
A simple command builds a new image. -t specifies the name of the new image, and the last parameter (apache) specifies the directory that contains Dockerfile:
[root@r1745042 ~]# docker build -t apache apache
Sending build context to Docker daemon 3.072 kB
Sending build context to Docker daemon
Step 0 : FROM rhel7-yum
 ---> 63d2b40384d1
Step 1 : RUN yum -y install httpd
 ---> Running in 9cd13a5307e7
Loaded plugins: product-id, subscription-manager
  [... I left out a lot of yum output ...]
Installed:
  httpd.s390x 0:2.4.6-17.el7

Dependency Installed:
  apr.s390x 0:1.4.8-3.el7                  apr-util.s390x 0:1.5.2-6.el7
  httpd-tools.s390x 0:2.4.6-17.el7         mailcap.noarch 0:2.1.41-2.el7

Complete!
 ---> 43567f371ee3
Removing intermediate container 9cd13a5307e7
Step 2 : COPY index.html /var/www/html/index.html
 ---> 9d385cb26584
Removing intermediate container 2b635f816d59
Successfully built 9d385cb26584
You can see that every step of the Dockerfile processing creates a new container. At the end, apache has been created:
[root@r1745042 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
apache              latest              9d385cb26584        54 seconds ago      594 MB
rhel7-yum           latest              63d2b40384d1        3 minutes ago       539.3 MB
rhel7               latest              7228aca22f66        11 minutes ago      539.3 MB
sles12              latest              91e78dd3f4f5        16 minutes ago      1.537 GB
Let's start the web server, and use a simple way to not run it as a daemon, but in the foreground. Also, we'll give it a name "webserver", so that we can reference it when fetching files from the webserver:
[root@r1745042 ~]# docker run -i -t --rm --name webserver apache httpd -D FOREGROUND
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.6. Set the 'ServerName' directive globally to suppress this message
Appearently there is some warning about a configuration issue. Let's fix that by specifying ServerName in the httpd.conf file. To do that, Dockerfile looks like this:
[root@r1745042 ~]# cat apache/Dockerfile
FROM rhel7-yum
RUN yum -y install httpd
COPY index.html /var/www/html/index.html
RUN echo ServerName localhost >> /etc/httpd/conf/httpd.conf
When we build apache again, it will collide with the existing image. Let's use a different tag for our image we have built initially:
[root@r1745042 ~]# docker tag 9d385cb26584 apache:initial
[root@r1745042 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
apache              latest              9d385cb26584        6 minutes ago       594 MB
apache              initial             9d385cb26584        6 minutes ago       594 MB
rhel7-yum           latest              63d2b40384d1        9 minutes ago       539.3 MB
rhel7               latest              7228aca22f66        17 minutes ago      539.3 MB
sles12              latest              91e78dd3f4f5        22 minutes ago      1.537 GB
docker tag will simply add another human-readable link to an image. Therefore we can delete the default apache one (with the latest tag):
[root@r1745042 ~]# docker rmi apache
Untagged: apache:latest
[root@r1745042 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
apache              initial             9d385cb26584        7 minutes ago       594 MB
rhel7-yum           latest              63d2b40384d1        9 minutes ago       539.3 MB
rhel7               latest              7228aca22f66        18 minutes ago      539.3 MB
sles12              latest              91e78dd3f4f5        23 minutes ago      1.537 GB
So we can build our new apache image -- note the tag now contains another identifier. Very often, the TAG field is used for versioning.
[root@r1745042 ~]# docker build -t apache:improved apache
Sending build context to Docker daemon 3.072 kB
Sending build context to Docker daemon
Step 0 : FROM rhel7-yum
 ---> 63d2b40384d1
Step 1 : RUN yum -y install httpd
 ---> Using cache
 ---> 43567f371ee3
Step 2 : COPY index.html /var/www/html/index.html
 ---> Using cache
 ---> 9d385cb26584
Step 3 : RUN echo ServerName localhost >> /etc/httpd/conf/httpd.conf
 ---> Running in 13ee4e90197a
 ---> 00e8f7420243
Removing intermediate container 13ee4e90197a
Successfully built 00e8f7420243
Note all intermediate steps are still cached, so this will run through very quickly. We have now our two flavors of apache:
[root@r1745042 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
apache              improved            00e8f7420243        26 seconds ago      594 MB
apache              initial             9d385cb26584        8 minutes ago       594 MB
rhel7-yum           latest              63d2b40384d1        10 minutes ago      539.3 MB
rhel7               latest              7228aca22f66        19 minutes ago      539.3 MB
sles12              latest              91e78dd3f4f5        23 minutes ago      1.537 GB
Starting the web server, again giving it the name webserver:
[root@r1745042 ~]# docker run -i -t --rm --name webserver apache:improved httpd -D FOREGROUND
Now let's fetch a page from the web server -- of course from a container. We run curl to download the home page (index.html we provided). The --link statement associates serveraddr to the identifier webserver. serveraddr can then be used in the curl command:
[root@r1745042 ~]# docker run -i -t --rm --link webserver:serveraddr rhel7 curl serveraddr
this is our new homepage
In summary of the two recent posts, Docker provides a powerful and simple to use tool to create, modify, run and manage containers and images. Efficiency is achieved through automatic deduplication of files. This also allows the host kernel to use this level of efficiency on shared libraries. Dockerfiles are a convenient, reproducible, and well-defined way to create new images.

With this small introduction, enjoy the world of containers.

No comments:

Post a Comment