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. .