Zaher Ghaibeh
PHP Backend developer
I've experience in a few PHP Frameworks, such as Laravel, Lumen and Slim (The last two are used for building Microservices/API services).
Snippet Running Traefik with Docker Swarm
Published at Saturday, January 6, 2018

The other day, I wanted to try using Traefik in real world scenario where I'll have a docker instance running and Traefik will do the routing/proxying based on the domain name that I will provide, sadly this was not so easy, so after few hours of searching I found the solution.

You may ask, why it didnt work, it should work with no problem, and I agree so am going to list the problem I faced and the solution I found. To work with swarm, I created three servers and joined them in one swarm network, where I had one manager and two workers, then I used this simple docker-compose.yml file to create the app

version: "3.1"

services:

  api:
    image: emilevauge/whoamI:latest
    labels:
      - "traefik.backend=api"
      - "traefik.frontend.rule=Host:api.app.zah.me"
      - "traefik.enable=true"
      - "traefik.port=80"
      - "traefik.backend.loadbalancer.method=drr"
      - "traefik.docker.network=traefik"
    deploy:  
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
    networks:
      - traefik        

  proxy:
    image: traefik:latest
    command: --web --docker --docker.domain=app.zah.me --logLevel=DEBUG
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik
    labels:
      - "traefik.backend=proxy"
      - "traefik.frontend.rule=Host:proxy.app.zah.me"
      - "traefik.enable=true"
      - "traefik.port=8080"
      - "traefik.docker.network=traefik"
    deploy:
      placement:
        constraints:
          - node.role == manager
      replicas: 1
      restart_policy:
        condition: on-failure

networks:
  traefik:
    driver: overlay

But sadly didnt work, after a small search I found out that I need to activate the swarm mode within traefik, either via the command section or via the config file, I chose the command, so the command is now :

  proxy:
    image: traefik:latest
    command: --web --docker --docker.domain=testing.zah.me --docker.swarmmode --docker.watch --logLevel=DEBUG

now it worked, the proxy will response but the api was unreliable, I checked the labels section and I can confirm it works nice in my local machine (yes, it works on my machine ;) ), after a small search I found out that the labels sections which is so important for traefik to work and communicate with the other services should be within the deploy section not outside as I use, as a result of my above code, traefik only communicates with the services which are on the same machine, which mean that my request will not always routed correctly, so the new improved code is:

version: "3.1"

services:

  api:
    image: nginx:latest
    deploy:
      labels:
        - "traefik.backend=api"
        - "traefik.frontend.rule=Host:api.testing.zah.me"
        - "traefik.enable=true"
        - "traefik.port=80"
        - "traefik.backend.loadbalancer.method=drr"
        - "traefik.docker.network=traefik"    
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.role != manager        
    networks:
      - traefik        

  proxy:
    image: traefik:latest
    command: --web --docker --docker.domain=testing.zah.me --docker.swarmmode --docker.watch --logLevel=DEBUG
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      #- ./traefik.toml:/traefik.toml
    networks:
      - traefik      
    deploy:
      labels:
        - "traefik.backend=proxy"
        - "traefik.frontend.rule=Host:proxy.testing.zah.me"
        - "traefik.enable=true"
        - "traefik.port=8080"
        - "traefik.docker.network=traefik"
      placement:
        constraints:
          - node.role == manager
      replicas: 1
      restart_policy:
        condition: on-failure          

networks:
  traefik:
    driver: overlay

But still the communication was unstable, and sometimes I dont get a response at all, so another search shows that I need to modify the networks section to either:

  1. Create the traefik network manually, and specify the external : true option in my docker-compose.yml file.
  2. Change the value of the traefik.docker.network label to be _traefik as am naming my network traefik in the networks section.

So I chose the section option, since am calling my service web I have changed the network to `` , check the following code:

version: "3.1"

services:

  api:
    image: nginx:latest
    deploy:
      labels:
        - "traefik.backend=api"
        - "traefik.frontend.rule=Host:api.testing.zah.me"
        - "traefik.enable=true"
        - "traefik.port=80"
        - "traefik.backend.loadbalancer.method=drr"
        - "traefik.docker.network=web_traefik"    
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.role != manager        
    networks:
      - traefik        

  proxy:
    image: traefik:latest
    command: --web --docker --docker.domain=testing.zah.me --docker.swarmmode --docker.watch --logLevel=DEBUG
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      #- ./traefik.toml:/traefik.toml
    networks:
      - traefik      
    deploy:
      labels:
        - "traefik.backend=proxy"
        - "traefik.frontend.rule=Host:proxy.testing.zah.me"
        - "traefik.enable=true"
        - "traefik.port=8080"
        - "traefik.docker.network=web_traefik"
      placement:
        constraints:
          - node.role == manager
      replicas: 1
      restart_policy:
        condition: on-failure          

networks:
  traefik:
    driver: overlay
    external: true

so now I issued the following command and everything worked as planned.

docker stack deploy -c docker-compose.yml web

Just a small note, remember to add the DNS records for your domain/subdomains to point to all the servers you have created.