- C 95.9%
- CMake 4.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Added: - `--port=` flag. --- Example usage: ``` ./containerdns --port=12345 ``` Reviewed-on: #1 |
||
| examples/dnsmasq | ||
| .gitignore | ||
| CMakeLists.txt | ||
| docker_api.c | ||
| docker_api.h | ||
| LICENSE | ||
| main.c | ||
| parse.c | ||
| parse.h | ||
| README.md | ||
containerdns
A tiny DNS server that answers A queries with the IP of local
Docker/Podman containers. The first label of the query name is matched
against running container names, so mycontainer.internal.docker
resolves to that container.
Build
Requires libcurl and json-c.
cmake -S . -B build
cmake --build build
Run
./build/containerdns [--bind-addr=127.0.0.1] \
[--docker-sock=/var/run/docker.sock] \
[--port=5353]
--bind-addr(default127.0.0.1): address to listen on. Use the container bridge IP to serve containers directly.--docker-sock(default/var/run/docker.sock): engine API socket. For rootless Podman use$XDG_RUNTIME_DIR/podman/podman.sock.--port(default5353): port to bind to DNS server. If default port is already in use.
The container table loads at startup and refreshes lazily on a lookup miss, at most once per second.
Test
dig @127.0.0.1 -p 5353 mycontainer.internal.docker
Setup
systemd service
Install the binary and run it on boot with
/etc/systemd/system/containerdns.service:
[Unit]
Description=containerdns
After=network.target docker.service
Wants=docker.service
[Service]
ExecStart=/usr/local/bin/containerdns --bind-addr=127.0.0.1
Restart=on-failure
[Install]
WantedBy=multi-user.target
install -m755 build/containerdns /usr/local/bin/containerdns
systemctl daemon-reload
systemctl enable --now containerdns
systemd-resolved delegation
Forward a domain to containerdns without touching your global
resolver. Create
/etc/systemd/dns-delegate.d/docker.dns-delegate:
[Delegate]
DNS=127.0.0.1:5353
Domains=internal.docker
Then reload and verify:
systemctl restart systemd-resolved
resolvectl query mycontainer.internal.docker
Only names below internal.docker are sent to containerdns; everything
else keeps using the normal upstream servers. See
systemd.dns-delegate(5) for DefaultRoute and FirewallMark.
Without systemd-resolved
systemd.dns-delegate only exists in systemd-resolved (258+). Elsewhere,
run a local forwarder for the internal.docker zone.
dnsmasq
/etc/dnsmasq.d/containerdns.conf:
server=/internal.docker/127.0.0.1#5353
Unbound
/etc/unbound/unbound.conf.d/containerdns.conf:
forward-zone:
name: "internal.docker"
forward-addr: 127.0.0.1@5353
BIND
In named.conf:
zone "internal.docker" {
type forward;
forward only;
forwarders { 127.0.0.1 port 5353; };
};
Test with Alpine dnsmasq
examples/dnsmasq/ contains a minimal Containerfile, a dnsmasq.conf
pointing at the Docker bridge gateway, and test.sh, which runs the whole
chain (dig -> dnsmasq -> containerdns -> Docker API):
cmake -S . -B build && cmake --build build
./examples/dnsmasq/test.sh