Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

docker swarm container connect to host port

I have a swarm cluster in which I created a global service to run on all docker hosts in the cluster.

The goal is to have each container instance for this service connect to a port listening on the docker host.

For further information, I am following this Docker Daemon Metrics guide for exposing the new docker metrics API on all hosts and then proxying that host port into the overlay network so that Prometheus can scrape metrics from all swarm hosts.

I have read several docker github issues #8395 #32101 #32277 #1143 - from this my understanding is the same as outlined in the Docker Daemon Metrics. In order to connect to the host from within a swarm container, I should use the docker-gwbridge network which by default is 172.18.0.1.

Every container in my swarm has a network interface for the docker-gwbridge network:

326: eth0@if327: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
    link/ether 02:42:0a:ff:00:06 brd ff:ff:ff:ff:ff:ff
    inet 10.255.0.6/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.255.0.5/32 scope global eth0
       valid_lft forever preferred_lft forever 
333: eth1@if334: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.4/16 scope global eth1
       valid_lft forever preferred_lft forever

Also, every container in the swarm has a default route that is via 172.0.0.1:

/prometheus # ip route show 0.0.0.0/0 | grep -Eo 'via \S+' | awk '{ print $2 }' 
172.18.0.1
/prometheus # netstat -nr | grep '^0\.0\.0\.0' | awk '{print $2}'
172.18.0.1
/prometheus # ip route
default via 172.18.0.1 dev eth1
10.0.1.0/24 dev eth2  src 10.0.1.9
10.255.0.0/16 dev eth0  src 10.255.0.6
172.18.0.0/16 dev eth1  src 172.18.0.4

Despite this, I cannot communicate with 172.18.0.1 from within the container:

/ # wget -O- 172.18.0.1:4999
Connecting to 172.18.0.1:4999 (172.18.0.1:4999)
wget: can't connect to remote host (172.18.0.1): No route to host

On the host, I can access the docker metrics API on 172.18.0.1. I can ping and I can make a successful HTTP request.

  1. Can anyone shed some light as to why this does not work from within the container as outlined in the Docker Daemon Metrics guide?
  2. If the container has a network interface on the 172.18.0.1 network and has routes configured for 172.18.0.1 why do pings fail to 172.18.0.1 from within the container?
  3. If this is not a valid approach for accessing a host port from within a swarm container, then how would one go about achieving this?

EDIT: Just realized that I did not give all the information in the original post. I am running docker swarm on a CentOS 7.2 host with docker version 17.04.0-ce, build 4845c56. My kernel is a build of 4.9.11 with vxlan and ipvs modules enabled.

After some further digging I have noted that this appears to be a firewall issue. I discovered that not only was I unable to ping 172.18.0.1 from within the containers - but I was not able to ping my host machine at all! I tried my domain name, the FQDN for the server and even its public IP address but the container could not ping the host (there is network access as I can ping google/etc).

I disabled firewalld on my host and then restarted the docker daemon. After this I was able to ping my host from within the containers (both domain name and 172.18.0.1). Unfortunately this is not a solution for me. I need to identify what firewall rules I need to put in place to allow container->host communication without requiring firewalld being disabled.

like image 400
Andrew Butler Avatar asked Apr 09 '17 14:04

Andrew Butler


People also ask

How do I access the host port in a Docker container?

Accessing the Host With the Default Bridge Mode You just need to reference it by its Docker network IP, instead of localhost or 127.0. 0.1 . Your host's Docker IP will be shown on the inet line. Connect to this IP address from within your containers to successfully access the services running on your host.

How do I map a Docker container port to a local port?

To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag. This creates a firewall rule which maps a container port to a port on the Docker host to the outside world.

Can Docker container communicate with host?

docker run --network="host" Alternatively you can run a docker container with network settings set to host . Such a container will share the network stack with the docker host and from the container point of view, localhost (or 127.0. 0.1 ) will refer to the docker host.

How do I assign a port to a container?

Let's first update the hostconfig. { ... ... "PortBindings": {}, ... ... } Let's now assign host port 82 to port 80 of the Docker container httpd-container by updating the PortBindings in the JSON file: { ... ... "PortBindings": {"80/tcp":[{"HostIp":"","HostPort":"82"}]}, ... ... }


1 Answers

Firstly, I owe you a huge THANK YOU. Before I read your EDIT part, I'd spent literally day and night to solve a similar issue, and never realized that the devil is the firewall.

Without disabling the firewall, I have solved my problem on Ubunt 16.04, using sudo ufw allow in on docker_gwbridge sudo ufw allow out on docker_gwbridge sudo ufw enable

I'm not much familiar with CentOS, but I do believe the following should help you, or at least serve as a hint sudo firewall-cmd --permanent --zone=trusted --change-interface=docker_gwbridge sudo systemctl restart firewalld You might have to restart docker as well.

like image 84
Aragorn Yang Avatar answered Oct 13 '22 18:10

Aragorn Yang