djbdns docker

I’m a huge fan of djbdns, a DNS server/resolver written by D.J. Bernstein, author of qmail. Albeit a bit special to set up, it is simple yet powerful enough to not offload my DNS needs to an external service provider: it basically consists of a single data textfile, easily readable by humans, which is transformed by a tinydns-data executable.

Current DNS deployment: not elegant, but it works

DNS changes don’t occur very often for me, but I have always been unhappy with my deployment strategy … if it deserves that name, anyway:

  1. SSH into DNS machine, cd into tinydns’s root directory
  2. Backup the current data file and edit it
  3. Run make to build the binary data file and scp it to secondary + tertiary DNS
# Makefile on DNS machine
data.cdb: data
	/usr/local/bin/tinydns-data
	scp data* tinydns@other.host:/service/tinydns/root/
	scp data* tinydns@another.host:/var/service/tinydns/root/

Improvements I wanted to make:

  1. Elimate the backup copies by having data under version control
  2. Deploy from my *NIX workstation instead of SSH’ing into a prod system

The first part was trivial and is not covered here.

The second part entailed having a local copy of the tinydns-data binary and that meant two problems: I installed the djbdns suite from source and applied some (battle-hardened) community patches; I shall like to avoid unpleasant surprises by using a stock tinydns-data that creates different *.cdb files. Secondly, I will deploy from both a Linux and a Mac workstation, potentially FreeBSD as well, and I would like to spare me maintaining 2-3 different binaries in SCM.

Looking for a portable env to run a single command in

I felt this was a good use case for Vagrant or Docker. Since spinning up a full VM to run a single command felt like overkill and I’ve never actively worked with Docker, I went with the latter.

I ended up with this Dockerfile to bundle the tinydns-data executable that I copied from my DNS machine:

# Dockerfile
FROM alpine:3.7
WORKDIR /app
COPY bin/tinydns-data-linux-x86_64 /usr/local/bin/tinydns-data

To create/prepare the image:

docker build -t tinydns-data-builder .

make it so!

To tie it all together, I modified the remote Makefile to automate this sequence on my local workstation:

  1. Launch the container image
  2. Copy the local tinydns data file into the containter
  3. Run tinydns-data within the Docker instance to create the data.cdb file
  4. Copy said file back to the Docker host
  5. Stop and remove the container

The resulting Makefile:

container_workdir := /app
deployables := data data.cdb

all: deploy

data.cdb: data
	@echo -n "Building data.cdb in Docker container … "
	$(eval TINYDNS_CONTAINER_ID=$(shell docker run -it -d tinydns-data-builder /bin/sh))
	@docker cp ./data $(TINYDNS_CONTAINER_ID):$(container_workdir)
	@docker exec -it $(TINYDNS_CONTAINER_ID) tinydns-data
	@docker cp $(TINYDNS_CONTAINER_ID):$(container_workdir)/data.cdb .
	@docker stop -t 0 $(TINYDNS_CONTAINER_ID) >/dev/null
	@docker rm $(TINYDNS_CONTAINER_ID) >/dev/null
	@echo ✅ Done

deploy: data.cdb
	scp $(deployables) tinydns@primary.dns.host:/service/tinydns/tinydns/
	scp $(deployables) tinydns@secondary.dns.host:/var/service/tinydns/tinydns/
	scp $(deployables) tinydns@tertiary.dns.host:/etc/tinydns-ipv6/tinydns/

It could do with a make target to check a REVISION file (e.g. generated after each deployment) if scp’ing the data files is required, but why bother when copying over the unchanged files only takes 2-3 seconds.

I’m happy with this setup now. Also, can’t wait to play around with FreeBSD on Docker.

comments powered by Disqus