Running treafik in docker swarm in non-manager node (only in worker node)

When deploying traefik in docker swarm, it is a challenge of running Traefik on worker nodes rather than manager nodes due to the limitation that Traefik needs access to the Swarm mode API, which is only available on manager nodes. There is a work around using socat to create a bidirectional byte stream between a TCP socket and the Docker Unix socket.

So my questions are

  1. Is is mandatory to start traefik container in manager node with respect to docker swarm?
  2. What are the industry standard when running traefik in docker swarm?
  3. Is there any other way that we can spin up traefik in non manager node?

For Traefik Configuration Discovery you need access to the Docker Socket on at least one Swarm manager.

For improved security some run a docker-socket-proxy. If you constrain that to the Swarm managers, Traefik can run anywhere.

Be aware that introducing additional components like that also increases the risk of security issues, IMHO especially when they are maintained by a single person.

We created our own tiny docker-socket-proxy solution to avoid that. Simple NodeJS or Python script or a simple nginx config to only allow GET on necessary URLs will do.

There is also a recent docker socket proxy project that enables multi-tenancy in a Docker Swarm (link).

Hi, can you please provide docker-socket-proxy solution. How to create that script and how to leverage that.

There are Docker images available. Usual suspects are socket-proxy and docker-socket-proxy. For the latter, make sure you don't use the image without a tag, as latest is really old (link).

Or you can create your own docker-socket-proxy. This inline version is rather a dirty hack:

services:
  dockersock:
    image: nginx:alpine-slim
    hostname: '{{.Node.Hostname}}'
    #user: "0"
    #user: dockersocket:docker
    security_opt:
      - no-new-privileges:true
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
      - NET_BIND_SERVICE
    cap_drop:
      - ALL
    networks:
      - dockersock
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        ln -sf /dev/stdout /var/log/nginx/access.log
        ln -sf /dev/stderr /var/log/nginx/error.log

        #su - nginx

        cat <<'EOF' > /etc/nginx/nginx.conf
        user root;
        events { worker_connections  1024; }
        http {
            server {
                listen 2375;
                location ~ ^/(v1\.24/events|v1\.24/containers|v1\.24/services|v1\.24/version|v1\.24/networks|v1\.24/tasks) {
                    if ($$request_method != GET) { return 405; }
                    proxy_pass http://unix:/var/run/docker.sock;
                    proxy_set_header Host $$host;
                    proxy_set_header X-Real-IP $$remote_addr;
                    proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $$scheme;
                }
                location / { return 405; }
            }
        }
        EOF

        echo ID
        id

        echo Starting nginx
        nginx -g "daemon off;"
    expose:
      - 2375