Port forward on Docker Swarm overlay network - docker

I have a flask and a mysql service running under an overlay network, and each are publishing a port (8080 and 3306 respectively). Here's an inspection of my-network
"Containers": {
"4698a46d9748b802c74d3eb3cd47c76b9c8ff9fb2aa954338be3ec0ca6fba028": {
"Name": "mysql-app.1.bfoy8mz5ts9mb7jmuyaqy1ytu",
"EndpointID": "4c229598a84bc2a3488c24cf15f870bbaa7c48a9b67801558bc9c6382f0f8445",
"MacAddress": "02:42:0a:00:00:03",
"IPv4Address": "10.0.0.3/24",
"IPv6Address": ""
},
"4ca9811fe4e04d4ec9a8b0d887b7d971c7d6251e08702729487c2de531dc582f": {
"Name": "flask-app.1.56j825gcgfrfvv2vkj6e65seu",
"EndpointID": "260568e4f00aa596ed1fd2b68c51eaf9827d602f54d9d0573d6fcd1da038e899",
"MacAddress": "02:42:0a:00:00:06",
"IPv4Address": "10.0.0.6/24",
"IPv6Address": ""
}
},
I can connect to MySQL through Flask using 10.0.0.3. This isn't a guaranteed IP address and isn't able to be set manually. I want there to be a way where I can connect to MySQL without having to check its IP in the first place.
Here's my current command to create the service: docker service create -p 3306:3306 --network my-network --replicas 2 -e MYSQL_ROOT_PASSWORD=password --name mysql-app mysql. My assumption was publishing the port to 3306 would forward it to my-network and I could connect to my-network's gateway.

DNSRR is a key concept of docker swarm mode: https://docs.docker.com/engine/swarm/key-concepts/#load-balancing
Because you're deploying your MySQL service with --name mysql-app and assign your flask-app in the same network --network my-network, both services can reach each other just by their name. There is no need to figure out the IP address.
Try
# create a test network
docker network create testnetwork
# start mariadb
docker run -d --name bettermysql --network testnetwork -e MYSQL_ROOT_PASSWORD=nomysql mariadb:latest
# start some other linux and ping mariadb by name
docker run -ti --network testnetwork alpine:3.7 /bin/sh
/ # ping bettermysql
PING bettermysql (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=1.661 ms
...
When you're developing in swarm mode, you'd like to use --attachable option in your docker network create command. Than you can access the overlay networks with normal docker container (docker run ...) for testing and debugging.
TL;DR
Use mysql-app as MYSQL_HOST in your flask-app config.

Related

Docker internals using IP address from the user’s IP address pool

Docker version 18.09.0, build 4d60db4
OS VERSION : Centos 7
Problem statement : -
I have a master machine and a worker machine on the same LAN. Both are connected by the docker-machine utility. The worker machine is expected to run 3 zookeeper standalone containers. I have created a docker overlay network, on my master machine, using -
docker network create --attachable --subnet 200.184.152.0/24 --gateway 200.184.152.254 --driver overlay my network
I want to bind zookeeper container with fixed IP address as follows : -
zoo1 : 200.184.152.2
zoo2: 200.184.152.3
zoo3: 200.184.152.4
After moving to the shell of the worker machine by using the command :
eval $(docker-machine env worker-1)
I run zookeeper’s first instancezoo1: 200.184.152.2. It successfully runs.
Then I try to run second Zookeeper instance zoo2: 200.184.152.3, but it fails to give a network error.
Then I inspect the network using docker network inspect my-network on worker machine and in the containers section it shows the results : -
"Containers": {
"1a2471c777c907dc05bb0f23e819919354669de699f862e4fdc093293d145b31": {
"Name": "zoo1",
"EndpointID": "8bb5eebd1cacf36dc7cdad7fc3d72c45047c66b455c568cc9e8911d2121fd8d6",
"MacAddress": "02:42:c8:b8:98:02",
"IPv4Address": "200.184.152.2/24",
"IPv6Address": ""
},
"lb-my-network": {
"Name": "my-network-endpoint",
"EndpointID": "8f747b26e921ee1543631b758b7dfaf8c7e820c47a95849608dc3568f9957e79",
"MacAddress": "02:42:c8:b8:98:03",
"IPv4Address": "200.184.152.3/24",
"IPv6Address": ""
}
},
This lb-my-network is using IP address required by my components, because of this the entire automatic deployment fails. The worst is, the IP address of lb-my-network changes it keeps clashing with IP address of other containers.
Is this expected? If yes, then how can I deploy a number of containers using automation when docker is using IP addresses randomly from the pool reserved by user’s logic.
In the documentation, it is stated that the docker needs three address for it’s working, a network address, a broadcast address, and a gateway address, so 253 addresses can be used by the user in /24 subnet. But here the lb-my-network is using IP address from the pool being expected to be used by user’s containers.
Help will be appreciated.

How to get all ip addresses on a docker network?

I have containers running in a swarm stack of services (on different docker-machines each) connected together on an overlay docker network.
How would it be possible to get all used ip adresses on the network associated with their services or container name from inside a container on this network?
Thank you
If you want to execute this command from inside containers, first you have to mount docker.sock for each service (assuming that docker is installed in the container)
volumes:
- /var/run/docker.sock:/var/run/docker.sock
then in each container you have to install jq and after that you can simply run docker network inspect <network_name_here> | jq -r 'map(.Containers[].IPv4Address) []' expected output something like:
172.21.0.2/16
172.21.0.5/16
172.21.0.4/16
172.21.0.3/16
Find the name OR ID of overlay network -
$ docker network ls | grep overlay
Do a inspect -
docker inspect $NETWORK_NAME
You will be able to find the container names & IPs allocated to them. You can do a fetch/grep the required values from the inspect output. You will find the output something as below -
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.23.0.0/16",
"Gateway": "172.23.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"183584efd63af145490a9afb61eac5db994391ae94467b32086f1ece84ec0114": {
"Name": "emailparser_lr_1",
"EndpointID": "0a9d0958caf0fa454eb7dbe1568105bfaf1813471d466e10030db3f025121dd7",
"MacAddress": "02:42:ac:17:00:04",
"IPv4Address": "172.23.0.4/16",
"IPv6Address": ""
},
"576cb03e753a987eb3f51a36d4113ffb60432937a2313873b8608c51006ae832": {
"Name": "emailparser",
"EndpointID": "833b5c940d547437c4c3e81493b8742b76a3b8644be86af92e5cdf90a7bb23bd",
"MacAddress": "02:42:ac:17:00:02",
"IPv4Address": "172.23.0.2/16",
"IPv6Address": ""
},
Assuming you're using the default VIP endpoint, you can use DNS to resolve the IP's of a service. Here's an example of using dig to get VIP IP using and then get the individual container IP's behind that VIP using tasks.
docker network create --driver overlay --attachable sweet
docker service create --name nginx --replicas=5 --network sweet nginx
docker container run --network sweet -it bretfisher/netshoot dig nginx
~~~
;; ANSWER SECTION:
nginx. 600 IN A 10.0.0.3
~~~
docker container run --network sweet -it bretfisher/netshoot dig tasks.nginx
~~~
;; ANSWER SECTION:
tasks.nginx. 600 IN A 10.0.0.5
tasks.nginx. 600 IN A 10.0.0.8
tasks.nginx. 600 IN A 10.0.0.7
tasks.nginx. 600 IN A 10.0.0.6
tasks.nginx. 600 IN A 10.0.0.4
~~~
for n in `docker network ls | awk '!/NETWORK/ {print $1}'`; do docker network inspect $n; done
First, find the name of the network which your swarm is using.
Then run docker network inspect <NETWORK-NAME>. This will give you a JSON output, in which you'll find an object with key "Containers". This object reveals all the containers in the network and their IP addresses respectively.

Rabbitmq connection refused from Docker container to local host

I have a docker container running a java process that I am trying to connect to rabbitmq running on my localhost.
Here are the steps I've done so far:
On my Local machine (macbook running Docker version 1.13.0-rc3, build 4d92237 with firewall turned off)
I've updated my rabbitmq_env.conf file to remove RABBITMQ_NODE_IP_ADDRESS so I am not tied to connect via localhost and i have an admin rabbitmq user. (not trying with guest user)
I tested this via telnet on my local machine and have no issues telnet <local-ip> 5672
Inside my docker container
able to ping local-ip and curl rabbitmq admin api
curl -i -u username:password http://local-ip:15672/api/vhosts returns sucessfully
[{"name":"/","tracing":false}]
When i try to telnet from inside the container I get
"Connection closed by foreign host"
looking at the rabbitmq.logs
=ERROR REPORT====
closing AMQP connection <0.30526.1> (local-ip:53349 -> local-ip:5672):
{handshake_timeout,handshake}
My java stacktrace incase helpful
Caused by: java.net.ConnectException: Connection refused (Connection >refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at >java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at >java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.>java:206)
at >java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at >com.rabbitmq.client.impl.FrameHandlerFactory.create(FrameHandlerFactory.ja>va:32)
at >com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory.newCon>nection(RecoveryAwareAMQConnectionFactory.java:35)
docker network inspect bridge
[
{
"Name": "bridge",
"Id": "716f935f19a107225650a95d06eb83d4c973b7943b1924815034d469164affe5",
"Created": "2016-12-11T15:34:41.950148125Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {
"9722a49c4e99ca5a7fabe56eb9e1c71b117a1e661e6c3e078d9fb54d7d276c6c": {
"Name": "testing",
"EndpointID": "eedf2822384a5ebc01e5a2066533f714b6045f661e24080a89d04574e654d841",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
What am I missing?
for me this works fine!
I have been installed the image docker pull rabbitmq:3-management
and run
docker run -d --hostname haroldjcastillo --name rabbit-server -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin2017 -p 5672:5672 -p 15672:15672 rabbitmq:3-management
the most important is to add the connection and management ports -p 5672:5672 -p 15672:15672
See you host in docker
docker-machine ip
return in my case:
192.168.99.100
Go to management http://192.168.99.100:15672
For Spring Boot you can configure this or works good for another connections
spring.rabbitmq.host=192.168.99.100
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin2017
spring.rabbitmq.port=5672
Best wishes
For anyone else searching for this error, I'm using spring boot and rabbitmq in docker container, starting them with docker compose. I kept getting org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused from the spring app.
The rabbitmq hostname was incorrect. To fix this, I'm using the container names in the spring app configuration. Either put spring.rabbitmq.host=my-rabbit in spring's application.properties (or yml file), or in docker-compose.yaml add environment: SPRING_RABBITMQ_HOST: my-rabbit to the spring service. Of course, "my-rabbit" is the rabbitmq container name described in the docker-compose.yaml
I am using docker with linux container with rabbitmq:3-management and have created a dotnet core based web api. While calling from We API action method I faced the same issue and changed the value to "host.docker.internal"
following scenario worked for me
"localhost" on IIS Express
"localhost" on Docker build from Visual Studio
"host.docker.internal" on Docker build from Visual Studio
"Messaging": {
"Hostname": "host.docker.internal",
"OrderQueue": "ProductQueue",
"UserName": "someuser",
"Password": "somepassword" },
But facing the same issue when, the container created via docker build command, but not when container created using Visual Studio F5 command.
Now find the solution there are two ways to do it:
by default all the containers get added into "bridge" network go through with these steps
Case1: If you have already containers (rabbitmq and api) in the docker
and running then first check their ip / hostname
docker network ls
docker network inspect bridge # from this step you'll get to know what containers are associated with this
find the rabbitmq container and internal IP, apply this container name or IP and then run your application it will work from Visual Studio and Docker build and run command
Case2: if you have no containers running then you may like to create
your network in docker then follow these steps:
docker network create givenetworknamehere
add your container while using "docker run" command or after
Step2.1: if using docker run command for your container then;
docker run --network givenetworknamehere -d -p yourport:80 --name givecontainername giveyourimagename
Step2.2 if adding newly created network after container creation then use below
command docker network connect givenetworknamehere givecontainername
with these step you bring your container in your newly created same network and they can communicate.
Note: by default "bridge" network type get created
After a restart, all was working. I don't think Rabbit was using respecting .config changes

docker 1.12 swarm mode: how to connect to another container on overlay network and how to use loadbalance?

I used docker-machine on mac os. and create the swarm mode cluster like:
➜ docker-machine create --driver virtualbox docker1
➜ docker-machine create --driver virtualbox docker2
➜ docker-machine create --driver virtualbox docker3
➜ config docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
docker1 - virtualbox Running tcp://192.168.99.100:2376 v1.12.0-rc4
docker2 - virtualbox Running tcp://192.168.99.101:2376 v1.12.0-rc4
docker3 - virtualbox Running tcp://192.168.99.102:2376 v1.12.0-rc4
➜ config docker-machine ssh docker1
docker#docker1:~$ docker swarm init
No --secret provided. Generated random secret:
b0wcyub7lbp8574mk1oknvavq
Swarm initialized: current node (8txt830ivgrxxngddtx7k4xe4) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --secret b0wcyub7lbp8574mk1oknvavq \
--ca-hash sha256:e06f5213f5c67a708b2fa5b819f441fce8006df41d588ad7823e5d0d94f15f02 \
10.0.2.15:2377
# on host docker2 and host docker3, I run cammand to join the cluster:
docker#docker2:~$ docker swarm join --secret b0wcyub7lbp8574mk1oknvavq --ca-hash sha256:e06f5213f5c67a708b2fa5b819f441fce8006df41d588ad7823e5d0d94f15f02 192.1
68.99.100:2377
This node joined a Swarm as a worker.
docker#docker3:~$ docker swarm join --secret b0wcyub7lbp8574mk1oknvavq --ca-hash sha256:e06f5213f5c67a708b2fa5b819f441fce8006df41d588ad7823e5d0d94f15f02 192.1
68.99.100:2377
This node joined a Swarm as a worker.
# on docker1:
docker#docker1:~$ docker node ls
ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS
8txt830ivgrxxngddtx7k4xe4 * docker1 Accepted Ready Active Leader
9fliuzb9zl5jcqzqucy9wfl4y docker2 Accepted Ready Active
c4x8rbnferjvr33ff8gh4c6cr docker3 Accepted Ready Active
then I create the network mynet with overlay driver on docker1.
The first question: but I cann`t see the network on other docker hosts:
docker#docker1:~$ docker network create --driver overlay mynet
a1v8i656el5d3r45k985cn44e
docker#docker1:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5ec55ffde8e4 bridge bridge local
83967a11e3dd docker_gwbridge bridge local
7f856c9040b3 host host local
bpoqtk71o6qo ingress overlay swarm
a1v8i656el5d mynet overlay swarm
829a614aa278 none null local
docker#docker2:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
da07b3913bd4 bridge bridge local
7a2e627634b9 docker_gwbridge bridge local
e8971c2b5b21 host host local
bpoqtk71o6qo ingress overlay swarm
c37de5447a14 none null local
docker#docker3:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
06eb8f0bad11 bridge bridge local
fb5e3bcae41c docker_gwbridge bridge local
e167d97cd07f host host local
bpoqtk71o6qo ingress overlay swarm
6540ece8e146 none null local
the I create the nginx service which echo the default hostname on index page on docker1:
docker#docker1:~$ docker service create --name nginx --network mynet --replicas 1 -p 80:80 dhub.yunpro.cn/shenshouer/nginx:hostname
9d7xxa8ukzo7209r30f0rmcut
docker#docker1:~$ docker service tasks nginx
ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE
0dvgh9xfwz7301jmsh8yc5zpe nginx.1 nginx dhub.yunpro.cn/shenshouer/nginx:hostname Running 12 seconds ago Running docker3
The second question: I cann`t access from the IP of docker1 host to the service. I only get the response to access the IP of docker3 .
➜ tools curl 192.168.99.100
curl: (52) Empty reply from server
➜ tools curl 192.168.99.102
fda9fb58f9d4
So I think there have no loadbalance. How do I to use the build-in loadbalance ?
Then I create another service on the same network with busybox image to test ping :
docker#docker1:~$ docker service create --name busybox --network mynet --replicas 1 busybox sleep 3000
akxvabx66ebjlak77zj6x1w4h
docker#docker1:~$ docker service tasks busybox
ID NAME SERVICE IMAGE LAST STATE DESIRED STATE NODE
9yc3svckv98xtmv1d0tvoxbeu busybox.1 busybox busybox Running 11 seconds ago Running docke1
# on host docker3. I got the container name and the container IP to ping test:
docker#docker3:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fda9fb58f9d4 dhub.yunpro.cn/shenshouer/nginx:hostname "sh -c /entrypoint.sh" 7 minutes ago Up 7 minutes 80/tcp, 443/tcp nginx.1.0dvgh9xfwz7301jmsh8yc5zpe
docker#docker3:~$ docker inspect fda9fb58f9d4
...
"Networks": {
"ingress": {
"IPAMConfig": {
"IPv4Address": "10.255.0.7"
},
"Links": null,
"Aliases": [
"fda9fb58f9d4"
],
"NetworkID": "bpoqtk71o6qor8t2gyfs07yfc",
"EndpointID": "98c98a9cc0fcc71511f0345f6ce19cc9889e2958d9345e200b3634ac0a30edbb",
"Gateway": "",
"IPAddress": "10.255.0.7",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:0a:ff:00:07"
},
"mynet": {
"IPAMConfig": {
"IPv4Address": "10.0.0.3"
},
"Links": null,
"Aliases": [
"fda9fb58f9d4"
],
"NetworkID": "a1v8i656el5d3r45k985cn44e",
"EndpointID": "5f3c5678d40b6a7a2495963c16a873c6a2ba14e94cf99d2aa3fa087b67a46cce",
"Gateway": "",
"IPAddress": "10.0.0.3",
"IPPrefixLen": 24,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:0a:00:00:03"
}
}
}
}
]
# on host docker1 :
docker#docker1:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b94716e9252e busybox:latest "sleep 3000" 2 minutes ago Up 2 minutes busybox.1.9yc3svckv98xtmv1d0tvoxbeu
docker#docker1:~$ docker exec -it b94716e9252e ping nginx.1.0dvgh9xfwz7301jmsh8yc5zpe
ping: bad address 'nginx.1.0dvgh9xfwz7301jmsh8yc5zpe'
docker#docker1:~$ docker exec -it b94716e9252e ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
90 packets transmitted, 0 packets received, 100% packet loss
The third question: How to communicate with each container on the same network?
and the network mynet as:
docker#docker1:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5ec55ffde8e4 bridge bridge local
83967a11e3dd docker_gwbridge bridge local
7f856c9040b3 host host local
bpoqtk71o6qo ingress overlay swarm
a1v8i656el5d mynet overlay swarm
829a614aa278 none null local
docker#docker1:~$ docker network inspect mynet
[
{
"Name": "mynet",
"Id": "a1v8i656el5d3r45k985cn44e",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "10.0.0.0/24",
"Gateway": "10.0.0.1"
}
]
},
"Internal": false,
"Containers": {
"b94716e9252e6616f0f4c81e0c7ef674d7d5f4fafe931953fced9ef059faeb5f": {
"Name": "busybox.1.9yc3svckv98xtmv1d0tvoxbeu",
"EndpointID": "794be0e92b34547e44e9a5e697ab41ddd908a5db31d0d31d7833c746395534f5",
"MacAddress": "02:42:0a:00:00:05",
"IPv4Address": "10.0.0.5/24",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.driver.overlay.vxlanid_list": "257"
},
"Labels": {}
}
]
docker#docker2:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
da07b3913bd4 bridge bridge local
7a2e627634b9 docker_gwbridge bridge local
e8971c2b5b21 host host local
bpoqtk71o6qo ingress overlay swarm
c37de5447a14 none null local
docker#docker3:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
06eb8f0bad11 bridge bridge local
fb5e3bcae41c docker_gwbridge bridge local
e167d97cd07f host host local
bpoqtk71o6qo ingress overlay swarm
a1v8i656el5d mynet overlay swarm
6540ece8e146 none null local
docker#docker3:~$ docker network inspect mynet
[
{
"Name": "mynet",
"Id": "a1v8i656el5d3r45k985cn44e",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "10.0.0.0/24",
"Gateway": "10.0.0.1"
}
]
},
"Internal": false,
"Containers": {
"fda9fb58f9d46317ef1df60e597bd14214ec3fac43e32f4b18a39bb92925aa7e": {
"Name": "nginx.1.0dvgh9xfwz7301jmsh8yc5zpe",
"EndpointID": "5f3c5678d40b6a7a2495963c16a873c6a2ba14e94cf99d2aa3fa087b67a46cce",
"MacAddress": "02:42:0a:00:00:03",
"IPv4Address": "10.0.0.3/24",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.driver.overlay.vxlanid_list": "257"
},
"Labels": {}
}
]
So The fourth question: Is there have build-int kv store?
Question 1: the networks on other hosts are created on demand, when swarm allocate task on that host, the network will be created.
Question 2: The load balancing works out of box, there's maybe some problem with you docker swarm cluster. you need to check the iptables and ipvs rules
Question 3: containers on the same overlay network (mynet in your case) can talk with each other, and docker has a buildin dns server which can resolve container name to ip address
Question 4: yes they do.

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

I have the Docker version 1.10 with embedded DNS service.
I have created two service containers in my docker-compose file. They are reachable each other by hostname and by IP, but when I would like reach one of them from the host machine, it doesn't work, it works only with IP but not with hostname.
So, is it possible to access a docker container from the host machine by it's hostname in the Docker 1.10, please?
Update:
docker-compose.yml
version: '2'
services:
service_a:
image: nginx
container_name: docker_a
ports:
- 8080:80
service_b:
image: nginx
container_name: docker_b
ports:
- 8081:80
then I start it by command: docker-compose up --force-recreate
when I run:
docker exec -i -t docker_a ping -c4 docker_b - it works
docker exec -i -t docker_b ping -c4 docker_a - it works
ping 172.19.0.2 - it works (172.19.0.2 is docker_b's ip)
ping docker_a - fails
The result of the docker network inspect test_default is
[
{
"Name": "test_default",
"Id": "f6436ef4a2cd4c09ffdee82b0d0b47f96dd5aee3e1bde068376dd26f81e79712",
"Scope": "local",
"Driver": "bridge",
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1/16"
}
]
},
"Containers": {
"a9f13f023761123115fcb2b454d3fd21666b8e1e0637f134026c44a7a84f1b0b": {
"Name": "docker_a",
"EndpointID": "a5c8e08feda96d0de8f7c6203f2707dd3f9f6c3a64666126055b16a3908fafed",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16",
"IPv6Address": ""
},
"c6532af99f691659b452c1cbf1693731a75cdfab9ea50428d9c99dd09c3e9a40": {
"Name": "docker_b",
"EndpointID": "28a1877a0fdbaeb8d33a290e5a5768edc737d069d23ef9bbcc1d64cfe5fbe312",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
}
},
"Options": {}
}
]
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
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
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.
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
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

Resources