Skip to content

JonasAlfredsson/docker-kea

Repository files navigation

docker-kea

The ISC (Internet System Consortium) Kea DHCP server running inside a Docker container. Separate images for the IPv4 and IPv6 services, as well as an image for the Control Agent which exposes a RESTful API that can be used for querying/controlling the other services.

Available as both Debian and Alpine images and for multiple architectures. In order to facilitate the last part this repo needs to build Kea from source, so it might not be 100% identical to the official ISC package, which is unfortunate but it will probably have to remain like this until official packages are built for all architectures.

There is also an Ansible role using this image, if that is of interest.


Kea is the successor of the old ISC DHCP server which reached its end of life late 2022, so it is recommended to migrate to Kea now if you are still using the old service. Kea is built with the modern web in mind (intro presentation), and is more modular with separate packages for the different services along with a lot of documentation.

To keep the same modularity in the Docker case this repo produces four different images which are tagged with the same version as the Kea service running inside:

Just append -alpine to the tags above to get the Alpine image.

It is possible to define how strict you want to lock down the version so 2, 2.2 or 2.2.0 all work and the less specific tags will move to point to the latest of the more specific ones. One thing to be aware of is that even minor versions (2.2) are stable builds while odd (2.3) are development builds, therefore the major tagging of all the images built here will only track the stable releases. What this means is that 2 -> 2.2.0 even though 2.3.1 is available.

There is no :latest tag since Kea updates may break things.

Usage

Environment Variables

There are a couple of environment variables present in the container that allow for some customization, however, some of them should not be touched.

Executable Information

  • KEA_EXECUTABLE: Should not be modified, is used by entrypoint.sh.
  • KEA_USER: Currently does nothing, might be used in the future.

Data Directories

Because of strict path limitations these variables need to be defined in order to allow us to use the directory structure mentioned below. These can be changed if desired.

  • KEA_DHCP_DATA_DIR: Location of the leases "memfile" (Default: /kea/leases)
  • KEA_LOG_FILE_DIR: Output directory of log files (Default: /kea/logs)
  • KEA_LEGAL_LOG_DIR: Output directory of forensic log files (Default: /kea/logs)
  • KEA_CONTROL_SOCKET_DIR: Directory for any sockets created (Default: /kea/sockets)

Useful Directories

There are a few directories present inside the images that may be utilized if your usecase calls for it.

This image creates the user kea with uid:gid 101:101/100:101 (Debian/Alpine) which may be used for non-root execution in the future, however, Kea runs as root right now since it needs high privilege to open raw sockets.

  • /kea/config: Mount this to the directory with all your configuration files.
  • /kea/leases: Good location for the leases "memfile" if used.
  • /kea/logs: Good location to output any logs to.
  • /kea/sockets: Host mount this in order to share sockets between containers.
  • /entrypoint.d: Place any custom scripts you want executed at the start of the container here.

All the folders under kea/ may be mounted individually or you can just mount the entire kea/ folder, however, then you need to manually create the subfolders (with 750 permissions) since Kea is not able to do so itself. See the advanced docker-compose example for inspiration.

The DHCP Server

Each image/service needs its own specific configuration file, so you will need to create one for each service you want to run. There is a very simple config for the dhcp4 service in the simple/ folder, with more comprehensive ones for all services in the advanced/ folder. You may also look in the examples folder on the official repo to find stuff like all available keys for the DHCP4 config, or go to the documentation for the latest info.

The syntax used is extended JSON with another couple of addons which allows comments and file inclusion. This is very handy and makes it much easier to write well structured configuration files.

When starting the service you need to make sure that you point it to the correct configuration file. In the simple example we would provide the following command to have it find the correct file:

docker run -it --rm \
    -v $(pwd)/examples/simple:/kea/config \
    jonasal/kea-dhcp4:2 \
    -c /kea/config/dhcp4.json

This container will run inside a Docker network so it should not interfere with anything. You can test to see if it responds correctly by calling upon the test4 target from the Makefile.

make test4

To start the IPv6 service you just replace all instances of dhcp4 with dhcp6 in the command above. However, I would suggest you read the next section about the Docker network mode and how that affects these services before trying anything else.

Docker Network Mode

When you want to run your DHCP server for real you will need to make sure that the incoming DHCP packages can reach your service, and this will not happen in case you put the containers on a normal Docker network.

For basic home use I would recommend just setting the container to use the host network, since this will be the absolute easiest way to get around most issues. However, you could fiddle with a macvlan or an ipvlan (example) setup in case you have more advanced needs, but unless you know you need this I would not bother.

Additionally, IPv6 support in Docker is a little bit messy right now so if you want to deploy that your other choices are a bit limited either way.

Setting the host network is done by adding

--network host

to the command above, or look at the docker-compose file for how it is done there. Then you should be able to serve leases on the network the host machine is connected to.

The Control Agent

The DHCP services expose an API that may be used if the control-socket setting is defined in their configuration file:

"control-socket": {
    "socket-type": "unix",
    "socket-name": "/kea/sockets/dhcp4.socket"
},

A unix socket is the only method available, and while you can push commands directly through this with the help of socat the ctrl-agent service provides a RESTful API that may be interfaced with instead. You just need to make sure this service can communicate with the control-socket of the DHCP service, and an example of how to do this can be found in the advanced/ folder along with the docker-compose.yaml file.

When that is all up and running you should be able to make queries like this:

curl -X POST -H "Content-Type: application/json" \
    -d '{ "command": "config-get", "service": [ "dhcp4" ] }' \
    http://localhost:8000/

More information about this may be found in the Management API section of the documentation.

Kea Admin

The kea-admin binary is a small program meant to help perform administrative tasks like initializing the database backends, or retrieving all current leases.

More information about how this tool is to be used may be found in the the official documentation, but an example how a lease dump from a MySQL backend may look something like this:

docker run -ti jonasal/kea-admin:3.0.0-alpine \
    lease-dump mysql -h <mysql_container> -P 3306 \
    -n keatest -u keatest -p 1234 \
    -4 --output lease-dump.csv

Kea Hooks

Kea has some extended features that are available as "hooks" which may be imported in those cases when they are specifically needed. Some are available as free open source while others require a premium subscription in order to get them, a table exists here with more info.

These hooks enable advanced functionality, like High Availability and BOOTP, which means most people will probably never use these, and which is why we provide dhcp4-slim and dhcp6-slim images which don't have any hook libraries included at all.

However, if you want to make your own specialized image we do provide an additional image from where individual hooks may be imported. In the example below we just import the HA hooks into the dhcp4-slim service image.

FROM jonasal/kea-dhcp4-slim:2.2.0
COPY --from=jonasal/kea-hooks:2.2.0 /hooks/libdhcp_ha.so /hooks/libdhcp_lease_cmds.so /usr/local/lib/kea/hooks

It could also be necessary to run the linker after this, so just to be safe I would add one of the following lines afterwards.

RUN ldconfig  # <--- Debian
or
RUN ldconfig /usr/local/lib/kea/hooks  # <--- Alpine

Further Reading

In this part you will find additional information about Kea that might be useful for you, read at your own leisure.

Backups

⚠️ This is only relevant if you use the "memfile" leases storage.

TL;DR: Best method is to stop Kea and copy all files in KEA_DHCP_DATA_DIR, but you should be able to just to a "live" copy of dhcp4.csv and dhcp4.csv.2 IF dhcp4.csv.1 is currently NOT present, else wait a minute and try again.

Unless you have changed the KEA_DHCP_DATA_DIR from the default value, you should be able to see the following two files in the /kea/leases directory:

  1. dhcp4.csv
  2. dhcp4.csv.2

The first one is the "journal" file, where Kea will quickly (in an append only fashion) write any new lease that happens or any changes to the existing ones. This means that this file is always growing, and to handle this problem the kea-lfc process will run periodically which then results in the final "clean" dhcp4.csv.2 file.

The dhcp4.csv.2 file is free of any redundant information, and is the state you would end up in if you iterated over the dhcp4.csv file and could go back and apply later changes to the original lease entry.

The dhcp4.csv file is emptied after each kea-flc run, which means that "the current state" of Kea is actually the "base" dhcp4.csv.2 file along with all of the changes that has happened since it was created (i.e. what is written in the dhcp4.csv "journal" file).

However, this is the simplified explanation, and the kea-lfc process actually makes use of the following intermediary files:

  • dhcp4.csv.1: The original dhcp4.csv file atomically renamed in order to work on a static file.
  • dhcp4.csv.output: The output file that will become the next dhcp4.csv.2 file.
  • dhcp4.csv.completed: Intermediary rename after lfc process completed, but before rename to dhcp4.csv.2.

During the time dhcp4.csv is renamed to dhcp4.csv.1, and a new dhcp4.csv file is created, Kea will not process any DHCP requests. However, this should be really quick, and the kea-lfc can then continue the cleanup process asynchronously in the background. It is robust to failures, and knows how to resume in case a crash mid-cleanup.

What we can conclude from this is that the safest way to perform a backup is to stop the Kea process, so we know no cleanup is in process or any new leases are being written, and then make a copy of all the dhcp4.csv* files in the KEA_DHCP_DATA_DIR directory. This way we can guarantee a good state of all relevant files.

However, it is not always reasonable to have this downtime, so another solution would be to check for the existence of the dhcp4.csv.1 file, to assert no cleanup is in progress, and then make a copy of just the dhcp4.csv and dhcp4.csv.2 files.

To reduce the critical time spent between the two copy commands, one could first create hard links before copying them:

for f in "dhcp4.csv" "dhcp4.csv.2"; do
    if [ -f "${KEA_DHCP_DATA_DIR}/dhcp4.csv.1" ]; then
        echo "It looks like the kea-lfc process is running, try again later"
        exit 1
    fi
    ln "${KEA_DHCP_DATA_DIR}/${f}" "${KEA_DHCP_DATA_DIR}/${f}.bak"
done
cp "${KEA_DHCP_DATA_DIR}"*.bak /secure/location/
rm -v "${KEA_DHCP_DATA_DIR}*.bak"