Search code examples
dockerdocker-composetraefikdocker-swarm-modeportainer

Portainer in Docker swarm stack with Traefik refuses to connect


I am trying to include Portainer in a docker-compose swarm, consisting of WordPress + MySQL and Traefik (reverse proxy). I am using the following definition:

version: '3'

services:
  traefik:
    image: "traefik:v2.0.0-rc3"
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.swarmmode=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik
    deploy:
      mode: global
      placement:
        constraints: [node.role==manager]

  portainer:
    image: portainer/portainer:latest
    command: -H unix:///var/run/docker.sock
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer:/data
    networks:
      - traefik
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role==manager]
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.portainer.entrypoints=web"

  db:
    image: mysql:5.7
    volumes:
      - ./db/initdb.d:/docker-entrypoint-initdb.d
    networks:
      - traefik
    environment:
      MYSQL_ROOT_PASSWORD: <root_password>
      MYSQL_DATABASE: <db_name>
      MYSQL_USER: <db_user>
      MYSQL_PASSWORD: <user_password>
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3

  app:
    image: my-repo/wordpress:latest
    networks:
      - traefik
    deploy:
      replicas: 2
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.app.rule=Host(`example.org`)"
        - "traefik.http.routers.app.entrypoints=web"
        - "traefik.http.services.app.loadbalancer.server.port=80"

networks:
  traefik:

Everything works except portainer. When I visit localhost:9000 I just get a refused connection. The following non-swarm-mode docker-compose works, however:

version: '3'

services:
  traefik:
    image: "traefik:v2.0.0-rc3"
    container_name: "traefik"
    restart: always
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik

  portainer:
    image: portainer/portainer
    command: -H unix:///var/run/docker.sock
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer:/data
    ports:
      - "9000:9000"
      - "8000:8000"
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=web"

  db:
    image: mysql:5.7
    restart: always
    volumes:
      - ./db/initdb.d:/docker-entrypoint-initdb.d
    networks:
      - traefik
    environment:
      MYSQL_ROOT_PASSWORD: <root_password>
      MYSQL_DATABASE: <db_name>
      MYSQL_USER: <db_user>
      MYSQL_PASSWORD: <user_password>

  app:
    image: my-repo/wordpress:latest
    restart: always
    depends_on:
      - db
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`example.org`)"
      - "traefik.http.routers.app.entrypoints=web"

networks:
  traefik:

What am I doing wrong? The logs in each case are the same. In non-swarm-mode I can log in to the Portainer UI and see all my containers running, etc. But the swarm version simply refuses to connect, even when I pass Host rule (portainer.example.org). I have only been using Traefik for a few days, and am very likely to be making a simple configuration error (hopefully!).


Solution

  • Port Detection

    Docker Swarm does not provide any port detection information to Traefik.

    Therefore you must specify the port to use for communication by using the label traefik.http.services.<service_name>.loadbalancer.server.port (Check the reference for this label in the routing section for Docker).