aacebedo / dnsdock

DNS service discovery for Docker containers
MIT License
606 stars 91 forks source link

Build Status

dnsdock

DNS server for automatic docker container discovery. Simplified version of crosbymichael/skydock.

This project was initially created and maintained by tonistiigi.

Differences from skydock

Build

There are two ways to build the tool

Building with devbox:

Install devbox on your host and execute the following commands:

$> devbox run test
$> devbox run --env GOARCH=[amd64|arm] build
Building using a devcontainer:

Install VSCode devcontainer extension or devpod and execute the following commands:

$> go get ./...
$> mkdir -p build && GOARCH=[amd64|arm] go build -o build/dnsdock ./cmd/dnsdock

Usage

Dnsdock connects to Docker Remote API and keeps an up to date list of running containers. If a DNS request matches some of the containers their local IP addresses are returned.

Format for a request matching a container is: <anything>.<container-name>.<image-name>.<environment>.<domain>.

You can always leave out parts from the left side. If multiple containers match then they are all returned. Wildcard requests are also supported.

> dig *.docker
...
;; ANSWER SECTION:
docker.         0   IN  A   172.17.0.5
docker.         0   IN  A   172.17.0.3
docker.         0   IN  A   172.17.0.2
docker.         0   IN  A   172.17.0.7

> dig redis.docker
...
;; ANSWER SECTION:
redis.docker.       0   IN  A   172.17.0.3
redis.docker.       0   IN  A   172.17.0.2

> dig redis1.redis.docker
...
;; ANSWER SECTION:
redis1.redis.docker.        0   IN  A   172.17.0.2

> dig redis1.*.docker
...
;; ANSWER SECTION:
redis1.*.docker.        0   IN  A   172.17.0.2
OSX Usage

Original tutorial: http://www.asbjornenge.com/wwc/vagrant_skydocking.html

If you use docker on OSX via Vagrant you can do this to make your containers discoverable from your main machine.

In your Vagrantfile add the following to let your virtual machine accept packets for other IPs:

config.vm.provider :virtualbox do |vb|
  vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
end

Then route traffic that matches you containers to your virtual machine internal IP:

sudo route -n add -net 172.17.0.0 <VAGRANT_MACHINE_IP>

Finally, to make OSX use dnsdock for requests that match your domain suffix create a file with your domain ending under /etc/resolver (for example /etc/resolver/myprojectname.docker) and set its contents to nameserver 172.17.0.1.

coreos-vagrant usage

You can autostart the dnsdock service in the user-data file of coreos-vagrant. Everytime you vagrant up this CoreOs vagrant instance the dnsdock service will be running and start discovering your other services.

Add the following snippet under the units part:

- name: dnsdock.service
      enable: true
      command: start
      content: |
        [Unit]
        Description=dnsdock
        After=docker.service
        Requires=docker.service

        [Service]
        EnvironmentFile=/etc/environment
        ExecStartPre=/bin/sh -c '/usr/bin/docker rm -f dnsdock || ls > /dev/null'
        ExecStartPre=/bin/sh -c '/usr/bin/docker pull aacebedo/dnsdock'
        ExecStart=/usr/bin/docker run -v /var/run/docker.sock:/var/run/docker.sock --name dnsdock -p ${COREOS_PRIVATE_IPV4}:53:53/udp aacebedo/dnsdock
        ExecStop=/bin/sh -c '/usr/bin/docker stop dnsdock  || ls > /dev/null'
Container images usage

DNSDock is also available as official docker images. There are several images for different processor architectures:

Simply add the architecture to the requested tag.

Setup

DNS listening port needs to be bound to the docker0 inferface so that its available to all containers. To avoid this IP changing during host restart add it to the docker default options.

Restart docker daemon after you have done that (sudo service docker restart).

Now you only need to run the dnsdock container:

docker run -d -v /var/run/docker.sock:/var/run/docker.sock --name dnsdock -p 172.17.0.1:53:53/udp aacebedo/dnsdock [--opts]

Additional configuration options to dnsdock command:

--dns=":53": Listen DNS requests on this address
--docker="unix://var/run/docker.sock": Path to the docker socket
--domain="docker": Domain that is appended to all requests
--environment="": Optional context before domain suffix
--help: Show this message
--http=":80": Listen HTTP requests on this address
--nameserver="8.8.8.8:53": DNS server for unmatched requests
--ttl=0: TTL for matched requests
--verbose: Verbose output
--tlsverify: enable mutual TLS between dnsdock and Docker
--tlscacert="$HOME/.docker/ca.pem": Path to CA certificate
--tlscert="$HOME/.docker/cert.pem": Path to client certificate
--tlskey="$HOME/.docker/key.pem": Path to client certificate private key
--all: Process all container even if they are stopped
--forcettl: Change TTL value of responses coming from remote servers

If you also want to let the host machine discover the containers add nameserver 172.17.0.1 to your /etc/resolv.conf.

SELinux and Fedora / RHEL / CentOS

Mounting docker daemon’s unix socket may not work with default configuration on these platforms. Please use selin-dockersock to fix this. More information in #11.

TLS Authentication

Instead of connecting to the Docker daemon’s UNIX socket, you may prefer to connect via a TLS-protected TCP socket (for example, if you are running Swarm). The -tlsverify option enables TLS, and the three additional options (-tlscacert, -tlscert and -tlskey) must also be specified. Alternatively, you may set the DOCKER_TLS_VERIFY environment variable to a non-empty value and the DOCKER_CERTS to a directory containing files named ca.pem, cert.pem and key.pem.

You may build this into your own container with this example Dockerfile:

FROM aacebedo/dnsdock

ENV DOCKER_TLS_VERIFY 1
ENV DOCKER_CERTS /certs

CMD ["-docker=tcp://172.17.0.1:2376"]

Use a volume (-v /path/to/certs:/certs) to give the container access to the certificate files, or build the certificates into the image if you have access to a secure private image registry.

HTTP Server

For easy overview and manual control dnsdock also includes HTTP server that lets you configure the server using a JSON API.

# show all active services
curl http://dnsdock.docker/services

# show a service
curl http://dnsdock.docker/services/serviceid

# add new service manually
curl http://dnsdock.docker/services/newid -X PUT --data-ascii '{"name": "foo", "image": "bar", "ip": "192.168.0.3", "ttl": 30}'

# remove a service
curl http://dnsdock.docker/services/serviceid -X DELETE

# change a property of an existing service
curl http://dnsdock.docker/services/serviceid -X PATCH --data-ascii '{"ttl": 0}'

# set new default TTL value
curl http://dnsdock.docker/set/ttl -X PUT --data-ascii '10'
Overrides from ENV metadata (DEPRECATED)

If you wish to fine tune the DNS response addresses you can define specific environment variables during container startup. This overrides the default matching scheme from container and image name.

Supported ENV variables are DNSDOCK_NAME, DNSDOCK_IMAGE, DNSDOCK_ALIAS, DNSDOCK_TTL.

docker run -e DNSDOCK_NAME=master -e DNSDOCK_IMAGE=mysql -e DNSDOCK_TTL=10 \
           --name mymysql mysqlimage
# matches master.mysql.docker
docker run -e DNSDOCK_ALIAS=db.docker,sql.docker -e DNSDOCK_TTL=10 \
           --name mymysql mysqlimage
# matches db.docker and sql.docker
Overrides with docker labels

If you wish to fine tune the DNS response addresses you can define specific labels during container creation. This overrides the default matching scheme from container and image name.

Supported labels are com.dnsdock.ignore, com.dnsdock.alias, com.dnsdock.name, com.dnsdock.tags, com.dnsdock.image, com.dnsdock.ttl, com.dnsdock.region, and com.dnsdock.ip_addr

docker run -l com.dnsdock.name=master -l com.dnsdocker.image=mysql -l com.dnsdock.ttl=10 \
           --name mymysql mysqlimage
# matches master.mysql.docker
docker run -l com.dnsdock.alias=db.docker,sql.docker -l com.dnsdock.ttl=10 \
           --name mymysql mysqlimage
# matches db.docker and sql.docker

Service metadata syntax by progrium/registrator is also supported.

docker run -l com.dnsdock.tags=master -l com.dnsdock.name=mysql -l com.dnsdock.region=us2 \
           --name mymysql mysqlimage
# matches master.mysql.us2.docker

If you want dnsdock to skip processing a specific container set its com.dnsdock.ignore label.

You can force the value of the IP address returned in the DNS record with the com.dnsdock.ip_addr label. This can be useful if you have a reverse proxy such as traefik in a container with mapped port and you want to redirect your clients to the front server instead of an internal docker container ip address.


Lots of code in this repo is directly influenced by skydns and skydock. Many thanks to the authors of these projects.