1

I don't understand how to ping a service running in Docker Swarm which is deployed in global mode. Let's say I have 2 nodes in my Swarm cluster (example below). I deploy some service in global mode, so 2 instances running on its own node. Both services expose the same port like in the example below.

version: '3.7'

services:
  cadvisor:
    image: google/cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - 8080:8080
    networks:
      - monitor-net
    deploy:
      mode: global
      restart_policy:
          condition: on-failure

networks:
  monitor-net:

I run another container on the same network and I try to ping the services. Docker can resolve the service by its service name:

root@bdc091e9f4d1:/# ping cadvisor
PING cadvisor (10.0.16.165) 56(84) bytes of data.
64 bytes from 10.0.16.165 (10.0.16.165): icmp_seq=1 ttl=64 time=0.049 ms
64 bytes from 10.0.16.165 (10.0.16.165): icmp_seq=2 ttl=64 time=0.065 ms
64 bytes from 10.0.16.165 (10.0.16.165): icmp_seq=3 ttl=64 time=0.044 ms

But it just chooses one of the services. How can I reach one from each node ? I tried to use the hostname

services:
  cadvisor:
    image: google/cadvisor
    hostname: "{{.Node.Hostname}}.{{.Service.Name}}"

It sets the hostname as expected. docker container inspect ...

 "Config": {
            "Hostname": "node01.mon_cadvisor",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,

If I ping node01.mon_cadvisor, Docker doesn't seem to resolve the address of the service by its hostanme

So how to do it ?

Alexandre A.
  • 1,619
  • 18
  • 29

1 Answers1

3

What you observed is not limited to global mode deployments. A deployed service will default to use deploy.endpoint_mode: vip.

In endpoint_mode: vip the service will use a virtual ip. The service name will resolve to the ip of the virtual ip. The vip is responsible to balance traffic to the containers.

The only thing wrong in your "ping test" was the expectation. If you put the default vip behavior into account, it makes sense why you observed what you observed.

if you deploy your service with endpoint_mode: dnsrr name resolution will return the container ips in round robin mode. Even if you stick with endpoint_mode: vip, you can force dnsrr behavior by communicating to tasks.{servicename} instead of the servicename... in your case this would be tasks.cadvisor.

Metin
  • 661
  • 3
  • 15
  • I don't understand why having a VIP prevents accessing individual services. As you said, it's possible with *tasks.{servicename}*, as well as with the complete container name, but not with custom container hostnames. Concerning dnsrr, it seems it is not possible with global mode. – Herve Nicol Jan 22 '21 at 17:52
  • Can you elaborate more on your first sentence? It is kind of ambigous. Regarding dnsrr and global mode: it is not going to work with `ports[].mode: ingress` (which is the default), though with `host` it works just fine and you can be sure that if you access the publised port from the node port, that the request will be processed on the task of that node. – Metin Jan 22 '21 at 19:42
  • Trying to elaborate in a short comment with limited paging... let's say I have a `web` container with `deploy: replicas: 2` (so it's an ingress VIP, right?), I can access each instance individually by `test_web.1.pd6z2i4zshlj4m5030pjnsmlm` or its direct IP. Or go through the VIP with `test_web` or `web` names. However, if I have set hostnames like `hostname: "{{.Service.Name}}.{{.Task.Slot}}"`, I can't request them with `test_web.1`. `curl` command actually resolves the IP, but the HTTP request fails for a reason I don't understand yet. – Herve Nicol Feb 03 '21 at 10:07