Running a DNS Server with Docker Compose

I decided I need a DNS server so I don’t need to remember all my IPs, I just want to be able to ping daniels-desktop, and have it work. I decided on bind9 to do this. This isn’t about bind9 though, this is about me fighting with Docker. I thought it was going to be a quick and easy setup, however I ran into an issue: the Linux Docker server I was using needed the DNS port, and if I tried to use it take it over then the servers DNS wouldn’t work anymore. So I decided to setup the container on it’s own “docker network” that was actually attached to the physical network: exposing this container. The container will also be assigned a static IP, and the default DNS server for the network as this container as a DNS server it can contact, so all the network devices will still be contacting my home router so if the container goes down my internet still works.

The docker-compose.yml file

Here is the docker-compose.yml file that we will be using:

services:
  bind9:
    container_name: dns_server_bind9
    image: ubuntu/bind9:latest
    networks:
      my-macvlan-network:
        ipv4_address: 192.168.0.5
    environment:
      - BIND9_USER=root
      - TZ=America/New_York
    ports:
      - '192.168.0.5:53:53/tcp'
      - '192.168.0.5:53:53/udp'
    volumes:
      - ./config:/etc/bind
      - ./cache:/var/cache/bind
      - ./records:/var/lib/bind
    restart: unless-stopped

networks:
  outside_network:
    driver: macvlan
    driver_opts:
      parent: ens18
    ipam:
      config:
        - subnet: 192.168.0.0/24
          gateway: 192.168.0.1

Let’s break down what each section of this file does.

services section

The services section defines the containers that will be created and run by Docker Compose.

bind9

The first and only container defined in this file is called bind9. This container is based on the ubuntu/bind9:latest image, which provides a pre-configured BIND9 DNS server.

container_name

The container_name parameter specifies a custom name for the container. In this case, we have set it to dns_server_bind9. So when you run docker container ls this is the name that will show up, and this is the name we will be referencing this container by.

networks

The networks section defines the networks that the container will be attached to.

my-macvlan-network

The my-macvlan-network network is a custom network created using the macvlan driver. This allows the container to be assigned a static IP address on the network.

ipv4_address

The ipv4_address parameter specifies the static IP address that will be assigned to the container on the my-macvlan-network network. In this case, we have set it to 192.168.0.5.

environment

The environment section defines environment variables that will be set in the container.

BIND9_USER

The BIND9_USER environment variable specifies the user that the BIND9 daemon should run as. In this case, we have set it to root.

TZ

The TZ environment variable specifies the timezone that the container should use. In this case, we have set it to America/New_York.

ports

The ports section maps ports from the container to the host system.

In this case, we are mapping the container’s port 53 (both TCP and UDP) to the host’s IP address 192.168.0.5 on the same port. This allows non-Docker devices on the network to query the DNS server. Generally it’s just 53:53, however because we are using an IP that isn’t the Docker server’s IP we need to specify the IP that it will be listening on.

volumes section

The volumes section specifies the volumes that will be mounted in the container.

./config:/etc/bind

The ./config directory on the host system will be mounted as /etc/bind in the container. This allows you to provide a custom configuration file for BIND.

./cache:/var/cache/bind

The ./cache directory on the host system will be mounted as /var/cache/bind in the container. This allows you to persist the DNS cache across container restarts.

./records:/var/lib/bind

The ./records directory on the host system will be mounted as /var/lib/bind in the container. This allows you to persist the DNS zone files across container restarts.

Nestart

The restart parameter specifies the restart policy for the container. In this case, we have set it to unless-stopped, which means that the container will be automatically restarted if it crashes or is stopped.

Networks Section

The networks section defines the custom network that the container will be attached to. In this case, we are defining a network called outside_network.

Driver

The driver parameter specifies the network driver to use. In this case, we are using the macvlan driver, which allows us to assign a static IP address to the container.

Driver_Opts

The driver_opts section provides additional options for the network driver. In this case, we are using the parent option to specify the parent network interface that the macvlan network should be created on. The parent option is set to ens18, which is the name of the interface on our host system.

IPAM

The ipam section is used to configure the IP address management for the network.

Config

The config section under ipam specifies the IP address range for the network. In this case, we’re using a subnet of 192.168.0.0/24 and a default gateway of 192.168.0.1. This means that any containers connected to this network will have an IP address within the 192.168.0.0/24 range.

Subnet

The subnet parameter in the config section specifies the IP address range for the network. In this case, we’re using a subnet of 192.168.0.0/24.

Gateway

The gateway parameter in the config section specifies the default gateway for the network. In this case, the default gateway is set to 192.168.0.1. This means that any traffic that doesn’t match a specific route will be sent to this default gateway.

That’s it! With this configuration, we can create a container that will be attached to the outside_network network and will have a static IP address within the 192.168.0.0/24 range. This is useful if we want to expose the container to the outside world and have it be accessible via a specific IP address.

Conclusion

In this blog post, we have walked through a docker-compose.yml file that can be used to run a BIND9 DNS server in a Docker container. The container is assigned a static IP address on the network and is accessible from non-Docker devices on the same network. .