Why does a man climb a mountain? Because it’s there.
Docker is great. Kubernetes is great. Communication between the two? Not so much. This post will explain how to easily solve this problem using dnsmasq. Your skepticism is noted.
Run dnsmasq in Docker
dnsmasq is awesome. You can use it to run a local DNS server while developing your applications.
log-queries
no-resolv
cache-size=1000
server=/.docker/127.0.0.11 # Docker internal DNS
server=/.k8s.local/10.43.0.10 # CoreDNS (mDNS uses .local, this must be accounted for)
server=/.cluster.local/10.43.0.10 # CoreDNS (mDNS uses .local, this must be accounted for)
server=1.1.1.1 # Cloudflare
server=8.8.4.4 # Google
address=/.test/{HOST_IP} # localhost IP
The config above will cause any domains ending in .test
to resolve to the IP
of your local computer. Any domain matching the server rules will be handled by
the specified DNS server.
docker network create --subnet=172.20.0.0/16 dns
docker run -d --restart unless-stopped --name dnsmasq -v \
./dnsmasq.conf:/etc/dnsmasq.conf --network dns --ip 172.20.0.1 <the dnsmasq
image> \
dnsmasq -k --log-queries --log-facility=-
Configure Host DNS
The Docker container for this config should not be bound to a host port.
Instead, update your Linux host (I use Arch, by the way)
/etc/systemd/resolved.conf
.
[Resolve]
DNS={DNSMASQ_IP}
# By default, systemd-resolved treats the .local domain as a special-use
# domain for Multicast DNS (mDNS) and doesn't forward these queries to your
# configured DNS servers. `Domains=~local` overrides that behavior
Domains=~local
# Disable MulticastDNS (mDNS)
MulticastDNS=no
# Listen on 127.0.0.53 (where /etc/resolv.conf usually points)
DNSStubListener=yes
Then run sudo systemctl restart systemd-resolved
.
Double-check that /etc/resolv.conf
is configured with nameserver 127.0.0.53
. The IP 127.0.0.53
is where systemd-resolved
listens for DNS
queries.
Now run dig +short foo.test
and you should see {HOST_IP}
returned. If not,
try dig @{DNSMASQ_IP} foo.test
to verify that dnsmasq is properly configured.
Now run:
docker run -d --rm --name nginx --network dns --network-alias nginx.docker
And curl nginx.docker
Note:
Docker will not resolve subdomains for nginx.docker
because it only knows
how to resolve Docker hostnames. So you’ll have to add more network-alias
es
or update dnsmasq with address=/.nginx/{NGINX_IP}
if you need that.
Configure Kubernetes DNS
This should be the easy part, but that will depend on your Kubernetes cluster.
If you’re using CoreDNS, simply update the config with forward . {DNSMASQ_IP}
and restart CoreDNS.
Now test everything with:
kubectl run curl --image=curl --restart=Never -- sleep infinity
kubectl exec curl -- curl nginx.docker
Check out this repo for a no-guarantees example of this configuration.