dockerdocker-composedocker-swarmdocker-swarm-mode

Docker Swarm Routing Mesh


Assuming that I have 2 nodes in the swarm (Node 1 is a manager, node2 is a worker), and using the following compose to launch

version: "3.9"
services:
  app1:
    image: app1image
    ports:
      - 8080:8080
    deploy:
      mode: global
  app2:
    image: app2image
    ports:
      - 9080:9080
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - "node.role==manager"

My questions are:

  1. If I try to access app1 through node1 could I be routed to the app1 container in node2?
  2. Since the app2 only deploys to node1, if I try to access it through node2 on port 9080 will I be able to?
  3. Besides ports referenced by the docker documentation(TCP port 2377 for cluster management communications TCP and UDP port 7946 for communication among nodes UDP port 4789 for overlay network traffic) are there any other ports that need to be opened? Like in case app1 wants to call app2

Solution

  • So, to understand whats actually going on:

    version: "3.9"
    
    networks:
      default:
        driver: overlay
      ingress:
        external: true
    
    services:
      app1:
        image: app1image
        ports:
          - 8080:5000
        deploy:
          mode: global
        networks:
          - default
    
      app2:
        image: app2image
        ports:
          - 9080:5000
        networks:
          - default
        deploy:
          placement:
            constraints:
              - node.role==manager
    

    In this configuration my expectation is that the app is listening on 0.0.0.0:5000.

    So, what docker has done is created two networks: an ingress network that is used to bridge ports on each host, to each container:

    node1:8080 node2:8080 will be routed and loadbalanced to app1 containers. and node1:9080, nod2:9080 will be routed and loadbalanced to app2 containers.

    The service containers, or tasks, also have been attached to an implicit default network for the compose stack. Its an overlay - or software defined - network so each container has an ip on that network that is unrelated to the node its on. I have decided that the actual listen port is port :5000 for both services, so any services attached to {stack}_default will be able to use the servicename, and the actual port address:

    app1:5000 will route via a vip to loadbalance traffic to instances of app1, and app1.tasks is a dnsrr record that will return each container ip.

    Likewise app2:5000 will route to the app2 container on the manager node.

    The app1 and app2 dns names are entirely private to services that are part of the stack / attached to the {stack_default} network so the app1:5000 names are not available external to the swarm, or even to other stacks or containers that are not explicitly attached.

    So:

    1. yes.
    2. yes.
    3. no but:

    If you ports: to publish ports, those ports are external to docker and do not go through the overlay network. You would need to add every port published to the firewalls if required for node to node comms. e.g. 8080 and 9080 need to be open.

    However, because overlay network allows connections, uses 4789 at the physical link layer, the traffic goint to app1, and app2 ips (the :5000 traffic) on the overlay is tunneled and does not need to be opened.