You are here

Docker - a DNS server container

logoNow that I understand better how the Ubuntu image is assembled, I'll try to create a DNS server container, starting from scratch, but trying not to reinvent the wheel, or, in other words, looking at what has already been done by more experienced people. Why not simply relying on an existing DNS server image? Because I want to be sure about what will be inside my container.

I'll create two containers: one will host the code (bind & co), and the other one will be a data volume container, hosting configuration data. The two of them will be based on the same image, an Ubuntu one, assembled as described in the article referenced above. Using the Ubuntu image as a base for the data volume container could look like a waste of disk space. But this is not the case actually: the same image is used twice by Docker without taking up any extra space.

Note: all commands below are run as root user.

Creation of scratch image

  • create the image by importing an empty tar archive:
tar cv --files-from /dev/null | docker import - pascalbod/scratch
  • (image virtual size reported as 0 B). Default tag is used, as I don't plan to modify this image later Smile.

Creation of Ubuntu image

wget http://cdimage.ubuntu.com/ubuntu-core/trusty/daily/current/trusty-core-amd64.tar.gz
  • check downloaded file with md5sum.
  • create the docker/ubuntu directory, and move there the downloaded file.
  • go to docker/ubuntu directory. Create following Dockerfile, adapted from github:
FROM pascalbod/scratch
ADD trusty-core-amd64.tar.gz /

# a few minor docker-specific tweaks
# see https://github.com/docker/docker/blob/master/contrib/mkimage/debootstrap
RUN echo '#!/bin/sh' > /usr/sbin/policy-rc.d \
	&& echo 'exit 101' >> /usr/sbin/policy-rc.d \
	&& chmod +x /usr/sbin/policy-rc.d \
	\
	&& dpkg-divert --local --rename --add /sbin/initctl \
	&& cp -a /usr/sbin/policy-rc.d /sbin/initctl \
	&& sed -i 's/^exit.*/exit 0/' /sbin/initctl \
	\
	&& echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \
	\
	&& echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \
	&& echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \
	&& echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \
	\
	&& echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \
	\
	&& echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes

# delete all the apt list files since they're big and get stale quickly
RUN rm -rf /var/lib/apt/lists/*
# this forces "apt-get update" in dependent images, which is also good

# enable the universe
RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list

# upgrade packages for now, since the tarballs aren't updated frequently enough
RUN apt-get update && apt-get dist-upgrade -y && rm -rf /var/lib/apt/lists/*

# add my own stuff
RUN apt-get update \
&& apt-get install -y emacs \
&& rm -rf /var/lib/apt/lists/* # overwrite this with 'CMD []' in a dependent Dockerfile CMD ["/bin/bash"]

(instead of adding Emacs, I'll use Nano next time. Emacs adds something like 50 MB to the image... And, no, I don't know how to use Vi Smile)

  • create the image:
docker build -t pascalbod/ubuntu:14.04.1-20141130 .

Update: above image is now available on Docker Hub, as an automated build. See this article.

Creation of DNS data container

  • create the data volume container:
docker run --name dnsserverdata -v /data/bind pascalbod/ubuntu:14.04.1-20141130 true

Creation of DNS server container

  • create the directory docker/dnsserver. Create there following Dockerfile:
FROM pascalbod/ubuntu:14.04.1-20141130

RUN apt-get update \
 && apt-get install -y bind9 dnsutils \
 && rm -rf /var/lib/apt/lists/*

ADD start /start
RUN chmod 755 /start

EXPOSE 53/udp
VOLUME ["/data/bind"]
CMD ["/start"]
  • create following start file:
#!/bin/bash
# Ensure right ownership. chmod -R 775 /data/bind chown -R root:bind /data/bind # Copy configuration files. cp /data/bind/etc/* /etc/bind/ echo "Starting named..." mkdir -m 0775 -p /var/run/named chown root:bind /var/run/named touch /var/log/query.log chown bind /var/log/query.log exec /usr/sbin/named -u bind -g
  • build the image:
docker build -t pascalbod/dnsserver:20141130 .

DNS server configuration

Creation and/or modification of bind configuration files must be performed before running the DNS server container, as file ownership is set at start time.

  • access the data volume container, requesting removal of the newly created container after the run:
docker run --rm -it --volumes-from dnsserverdata \
    pascalbod/ubuntu:14.04.1-20141130 bash
  • configuration files are in /data/bind/etc/. Modify them according to your requirements.

DNS server start

  • run the server:
docker run --name dnsserver --volumes-from dnsserverdata -d \
    -p 53:53/udp -p 53:53 pascalbod/dnsserver:20141130

Now, you should have a working DNS server.

When I have some time, I'll put those images on Docker Hub...

Update: a new version of this container is described in this article.