In this guide I’ve tested a number of different commands and configurations using Docker to run a container with dhcpd (+macvlan driver) to serve my clients in my home network. In the end i’ll migrate from my Windows 2012 R2 Server running DHCP to a much more lightweight Docker container (7.42 MB in total). Wow.
- Firewall (Juniper)
- I’m running IP helper for bootp which in this case means that i relay DHCP requests from various VLANs into one where i've placed my Windows 2012 R2 server. This is also where my container will live. See the FW configuration below:
forwarding-options {
helpers {
bootp {
description "Global DHCP relay service";
server 10.0.99.6;
maximum-hop-count 4;
interface {
ge-0/0/x.XX;
ge-0/0/x.XX;
}
}
}
}
- ESXi v6.5
- Running a VM (Debian Jessie) where I’ve installed Docker. The VM have two network interfaces assigned to it, one in a “DMZ” zone and one which I will trunk all VLANs to via ESXi and a port group with VLAN id 4095 (trunk all VLANs).
- On the port group that will be used for trunking VLANs i had to enable Promiscuous mode via the Security-settings.
FROM alpine:latest
RUN set -xe \
&& apk add --update --no-progress dhcp \
&& rm -rf /var/cache/apk/*
RUN ["touch", "/var/lib/dhcp/dhcpd.leases"]
CMD ["/usr/sbin/dhcpd", "-4", "-f", "-d", "--no-pid", "-cf", "/etc/dhcp/dhcpd.conf"]
version: '3'
services:
dhcpd:
build: .
restart: unless-stopped
networks:
internal_network:
ipv4_address: 10.0.99.6
volumes:
- ./dhcpd.conf:/etc/dhcp/dhcpd.conf
networks:
internal_network:
external:
name: macvlan0
- Create a VLAN interface on the Docker host and give it an address in the subnet
iface ens192.99 inet static
address 10.0.99.5
netmask 255.255.255.0
- Create a network using the macvlan driver.
docker network create -d macvlan --subnet=10.0.99.0/24 --gateway=10.0.99.1 -o parent=ens192.30 macvlan0
- Here's the Docker container repo: docker-dhcpd
- My dhcpd.conf that have worked for me, remember that i'm using a DHCP relay between the client and server
authoritative;
default-lease-time 86400;
max-lease-time 86400;
# This is a workaround to let this dhcpd server serve requests to other subnets
# then it's own.
# If this is not present then the dhcpd daemon will throw an error and exit.
subnet 10.0.99.0 netmask 255.255.255.0 {
}
# This is my WLAN subnet
subnet 10.0.100.0 netmask 255.255.255.0 {
option routers 10.0.100.1;
option subnet-mask 255.255.255.0;
range 10.0.100.150 10.0.100.200;
option broadcast-address 10.0.100.255;
option domain-name-servers 8.8.8.8, 8.8.4.4;
}
- Build the Docker image (from within project directory)
docker build . -t dhcpd
- Run the container
docker run -d --restart unless-stopped --ip 10.0.99.6 --net=macvlan0 dhcpd
or simply
docker-compose up -d
- Copy the dhcpd.lease file from the container to your local filesystem to check if you have any active leases
docker cp <Container ID>:/var/lib/dhcp/dhcpd.leases .
The way the DHCP helper statements work is top-down. If you had two DHCP servers running and one went down, L3 device would recognize that the DHCP server is unavailable and send the request to the next server in the list. All you need to do is make sure that the DHCP server checks if the IP is in use before creating a lease. With dhcpd, this is done by default see here. Essentially the "failover" DHCP server will start handing out new leases, and the devices that got DHCP from the pervious server retain their IP config for the duration of the lease. When they request a new address, it will certainly change, because the lease table is different on server 2. You could do some RSYNC magic to make sure the lease tables are matched up, but honestly I don't think this is a big deal. If you are using DDNS, just make sure both DHCP servers update BIND correctly, and you're all set. The one part I'm unsure about here is having the old DNS entry removed...
There are HA options with DHCP servers... windows for example has a DHCP failover feature, but really it's more like the range is split 80/20 between the two servers. It's not like LB with HAProxy and two Apache servers for example.