I have finally got around to experimenting with Docker this week. Thanks to the hard work of many wonderful hackers, since late last year we’ve had Docker packages working in Fedora (under the package name “docker-io”). Matt Miller has also been pushing Fedora images to the Docker index.
How can we use Apache httpd with Docker in Fedora? One simple use-case might be serving a mostly static web site which you want to isolate inside a Docker container. This is what you might aim for if you have a server hosting a bunch of different web sites for unrelated customers, but you want isolation between those servers. If one httpd gets compromised, you don’t want them all to go down.
Most of the hard work is already done here. We need two things:
- A Docker image which can launch httpd, serving our web site.
- A way to control that Docker container from the host side.
A Dockerfile is a script which describes how to create a docker image. Here’s my Dockerfile:
# Clone from the Fedora 20 image FROM fedora:20 # Install httpd RUN yum install -y httpd # Change the default docroot RUN sed -i 's|^DocumentRoot.*|DocumentRoot "/srv"|' /etc/httpd/conf/httpd.conf # Add in our custom httpd configuration. ADD extra.conf /etc/httpd/conf.d/root.conf # Start up httpd. ENTRYPOINT /usr/sbin/httpd -DFOREGROUND
The first line means this image begins as a clone of the standard Fedora 20 installation. We only make a few modifications: we install the httpd package, change the default docroot to /srv, and add in a custom configuration file. The “ENTRYPOINT” line means that httpd is the process invoked by default when containers are created from this image. The custom configuration file, “extra.conf” I use is this, which relaxes httpd’s access control for the /srv directory:
<Directory /srv> Require all granted </Directory>
Combining that and the change to the DocumentRoot, this image is set up to serve whatever is mounted at /srv. Placing the two files described above in an empty directory I create a new Docker image as follows – note the argument passed tags the image with the name “httpd-test1”:
# docker build -t httpd-test1 . Uploading context 10.24 kB Uploading context Step 1 : FROM fedora:20 ---> 6572f78e5fa5 Step 2 : RUN yum install -y httpd ---> Using cache ---> 44b5498e707a Step 3 : RUN echo > /etc/httpd/conf.d/welcome.conf ---> Running in c91f82b99bce ---> c5a629660e53 Step 4 : RUN sed -i 's|^DocumentRoot.*|DocumentRoot "/srv"|' /etc/httpd/conf/httpd.conf ---> Running in 67fe1b96bf51 ---> 26ad2ac0ebf8 Step 5 : ADD extra.conf /etc/httpd/conf.d/root.conf ---> cfe43ce7417a Step 6 : ENTRYPOINT /usr/sbin/httpd -DFOREGROUND ---> Running in 05a4a1154fb7 ---> f7d8712877b8 Successfully built f7d8712877b8
The remaining piece of the puzzle is integration on the host side. We could rely on standard Docker tools for this, but let’s do it properly. I’m going to place my example site, imaginatively named “example.com”, in /srv/example.com, as follows:
# mkdir /srv/example.com # echo '<h1>Hello, World</h1>' > /srv/example.com/index.html
Now I can set up a systemd service file which launches a Docker container using my image, and launch the container:
# cat > /etc/systemd/system/example.com.service <<EOF [Unit] Description=example.com Container After=docker.service [Service] Type=simple ExecStart=/usr/bin/docker run -v /srv/example.com:/srv httpd-test1 Restart=on-failure [Install] WantedBy=multi-user.target EOF # systemctl daemon-reload #
And that’s it! The “docker run” command will create a container using that “httpd-test1” image built earlier, and mounts the host’s /srv/example.com as /srv in the container. I can control this new service like any other systemd service:
# systemctl start example.com # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 91e770b4d61f httpd-test1:latest /bin/sh -c /usr/sbin 1 seconds ago Up Less than a second kickass_franklin6 # docker inspect 91e770b4d61f | grep IPAddr "IPAddress": "172.17.0.25", # curl http://172.17.0.25/ <h1>Hello, World</h1> #