Docker 1.10 access a container by its hostname from a host machine

╄→гoц情女王★ 提交于 2019-11-28 03:57:49

Here's what I do.

I wrote a Python script called dnsthing, which listens to the Docker events API for containers starting or stopping. It maintains a hosts-style file with the names and addresses of containers. Containers are named <container_name>.<network>.docker, so for example if I run this:

docker run --rm --name mysql -e MYSQL_ROOT_PASSWORD=secret  mysql

I get this:

172.17.0.2 mysql.bridge.docker

I then run a dnsmasq process pointing at this hosts file. Specifically, I run a dnsmasq instance using the following configuration:

listen-address=172.31.255.253
bind-interfaces
addn-hosts=/run/dnsmasq/docker.hosts
local=/docker/
no-hosts
no-resolv

And I run the dnsthing script like this:

dnsthing -c "systemctl restart dnsmasq_docker" \
  -H /run/dnsmasq/docker.hosts --verbose

So:

  • dnsthing updates /run/dnsmasq/docker.hosts as containers stop/start
  • After an update, dnsthing runs systemctl restart dnsmasq_docker
  • dnsmasq_docker runs dnsmasq using the above configuration, bound to a local bridge interface with the address 172.31.255.253.
  • The "main" dnsmasq process on my system, maintained by NetworkManager, uses this configuration from /etc/NetworkManager/dnsmasq.d/dockerdns:

    server=/docker/172.31.255.253
    

    That tells dnsmasq to pass all requests for hosts in the .docker domain to the docker_dnsmasq service.

This obviously requires a bit of setup to put everything together, but after that it seems to Just Work:

$ ping -c1  mysql.bridge.docker
PING mysql.bridge.docker (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.087 ms

--- mysql.bridge.docker ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.087/0.087/0.087/0.000 ms
deFreitas

As answered here there is a software solution for this, copying the answer:


There is an open source application that solves this issue, it's called DNS Proxy Server

It's a DNS server that resolves container hostnames, and when it can't resolve a hostname then it can resolve it using public nameservers.

Start the DNS Server

$ docker run --hostname dns.mageddo --name dns-proxy-server -p 5380:5380 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /etc/resolv.conf:/etc/resolv.conf \
defreitas/dns-proxy-server

It will set as your default DNS automatically (and revert back to the original when it stops).

Start your container for the test

docker-compose up

docker-compose.yml

version: '2'
services:
  redis:
    container_name: redis
    image: redis:2.8
    hostname: redis.dev.intranet
    network_mode: bridge # that way he can solve others containers names even inside, solve elasticsearch, for example
  elasticsearch:
    container_name: elasticsearch
    image: elasticsearch:2.2
    hostname: elasticsearch.dev.intranet

Now resolve your containers' hostnames

from host

$ nslookup redis.dev.intranet
Server:     172.17.0.2
Address:    172.17.0.2#53

Non-authoritative answer:
Name:   redis.dev.intranet
Address: 172.21.0.3

from another container

$ docker exec -it redis ping elasticsearch.dev.intranet
PING elasticsearch.dev.intranet (172.21.0.2): 56 data bytes

As well it resolves Internet hostnames

$ nslookup google.com
Server:     172.17.0.2
Address:    172.17.0.2#53

Non-authoritative answer:
Name:   google.com
Address: 216.58.202.78

The easiest way to do this is to add entries to your hosts file

  • for linux: add 127.0.0.1 docker_a docker_b to /etc/hosts file
  • for mac: similar to linux but use ip of virtual machine docker-machine ip default

To specifically solve this problem I created a simple "etc/hosts" domain injection tool that resolves names of local Docker containers on the host. Just run:

docker run -d \
    -v /var/run/docker.sock:/tmp/docker.sock \
    -v /etc/hosts:/tmp/hosts \
    --name docker-hoster \
    dvdarias/docker-hoster

You will be able to access a container using the container name, hostname, container id and vía the network aliases they have declared for each network.

Containers are automatically registered when they start and removed when they are paused, dead or stopped.

Similar to @larsks, I wrote a Python script too but implemented it as service. Here it is: https://github.com/nicolai-budico/dockerhosts

It launches dnsmasq with parameter --hostsdir=/var/run/docker-hosts and updates file /var/run/docker-hosts/hosts each time a list of running containers was changed. Once file /var/run/docker-hosts/hosts is changed, dnsmasq automatically updates its mapping and container become available by hostname in a second.

$ docker run -d --hostname=myapp.local.com --rm -it ubuntu:17.10
9af0b6a89feee747151007214b4e24b8ec7c9b2858badff6d584110bed45b740

$ nslookup myapp.local.com
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   myapp.local.com
Address: 172.17.0.2

There are install and uninstall scripts. Only you need is to allow your system to interact with this dnsmasq instance. I registered in in systemd-resolved:

$ cat /etc/systemd/resolved.conf

[Resolve]
DNS=127.0.0.54
#FallbackDNS=
#Domains=
#LLMNR=yes
#MulticastDNS=yes
#DNSSEC=no
#Cache=yes
#DNSStubListener=udp
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!