Install Traefik in Docker Swarm

by Thomas Urban

This tutorial is providing brief example for setting up traefik in a freshly established Docker Swarm. It closely follows official descriptions found in Traefik's documentation, but adopts those examples to work in a Docker Swarm.

Prerequisites

This tutorial applies to a Docker Swarm. It's installation usually consists of setting up Docker Engine on three or more servers, run docker swarm init and docker swarm join-token manager on one of the servers and whatever command is displayed by the latter on every other server.

Persistent Volumes

Traefik works just fine in such a basic swarm. And that's what this tutorial is about. However, some additional features such as automatic maintenance of TLS certificates fetched from Letsencrypt require access on a persistent filesystem. This applies to further services you might want to set up in your swarm.

In a Docker Swarm persistent filesystems require additional setup. One option is to establish a GlusterFS cluster for sharing part of either server's filesystem.

Encrypt Ingress Networking

This isn't required by Traefik, but you should always make sure to encrypt any overlay network to prevent unencrypted traffic between your services from being eavesdropped. This includes your swarm's ingress network as it is an overlay network and it isn't encrypted by default.

Encrypting overlay networks may be beneficial in case of encountering basic communication issues between your swarm's nodes for encrypted networks are established via TCP-based IPSec instead of UDP-based VXLAN.

Due to starting with a fresh swarm we assume there is no running service right now. Otherwise you'll need to stop it for fixing the ingress network, at least.

  1. Remove the existing ingress network using

    docker network rm ingress
    

    and confirm the warning popping up.

  2. Re-create the ingress network using

    docker network create --ingress --driver overlay \
        --opt encrypted ingress
    

    As an option you might want to increase the possible size of ingress network by defining its subnet explicitly:

    docker network create --ingress --driver overlay \
        --opt encrypted --subnet 10.10.0.0./16 ingress
    

Expose Docker API the Safer Way

Following this example you should put your Docker API behind proxy to limit requests available to Traefik. Let's adopt it for use in a swarm.

  1. Create a file socket-proxy.yml containing this:

    version: "3.8"
    
    services:
      socket-proxy:
        image: tecnativa/docker-socket-proxy
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
        environment:
          CONTAINERS: 1
          NETWORKS: 1
          SERVICES: 1
          TASKS: 1
        networks:
          cloud-socket-proxy:
            aliases:
              - socket-proxy
    
    networks:
      cloud-socket-proxy:
        external: true
    

    Additional environment variables are set to enable access on /networks/*, /services/* and /tasks/* which is required when setting up Traefik in swarm mode.

  2. This file declares to access some existing network, so let's create it:

    docker network create --driver overlay --scope swarm \
        --opt encrypted --attachable cloud-socket-proxy
    

    This command is creating another overlay network. Its name is cloud-socket-proxy. The prefix cloud- is chosen here to serve as a kind of namespace grouping every network and stack related to commonly manage your swarm. The --attachable option may introduce a security risk, but on the other hand it as enabling you to have custom containers using this Docker API filter as well.

  3. Start the stack described by file created before.

    docker stack deploy -c socket-proxy.yml cloud-socket-proxy
    

Install Traefik

Now it's time for setting up Traefik in its most basic way.

  1. Start with creating file edge.yml defining your Traefik-based reverse proxy in a swarm-compliant way:

    version: "3.8"
    
    services:
      reverse-proxy:
        image: traefik:v2.1
        deploy:
          placement:
            constraints:
              - node.role == manager
        ports:
          - "80:80"
          - "443:443"
          - "8080:8080"
        networks:
          - cloud-edge
          - cloud-socket-proxy
        configs:
          - source: traefik
            target: /etc/traefik/traefik.yaml
    
    configs:
      traefik:
        file: ./traefik.yml
    
    networks:
      cloud-edge:
        external: true
      cloud-socket-proxy:
        external: true
    

    This stack is attached to the cloud-socket-proxy network for accessing the Docker API via filtered TCP socket.

  2. There is another network named cloud-edge which is assumed to exist prior to starting the stack defined before:

    docker network create --driver overlay --scope swarm \
        --opt encrypted --attachable --subnet 10.20.0.0/16 \
        cloud-edge
    

    This network is meant to have all the containers and services attached which are exposed for public access via Traefik. It is managed externally so other stacks in your swarm can attach to it as well.

  3. Next create a static configuration file for Traefik named traefik.yml with this content:

    api:
      insecure: true
      dashboard: true
      debug: false
    
    entryPoints:
      http:
        address: ":80"
      https:
        address: ":443"
    
    providers:
      docker:
        endpoint: "tcp://socket-proxy:2375"
        swarmMode: true
        watch: true
        exposedByDefault: false
        network: cloud-edge
    

    By using a Docker configuration this file is implicitly exposed to any service container of reverse proxy as /etc/traefik/traefik.yaml. Whenever you adjust this file the stack started next must be restarted by tearing it down before re-starting again.

  4. Now, start this stack:

    docker stack deploy -c edge.yml cloud-edge
    

Check it out!

Open your favourite browser to visit http://node.of.your.swarm:8080. Replace node.of.your.swarm with hostname referring to any node of your swarm. Using either node's IP address is fine here, as well.

Now create another file test.yml containing

version: "3.8"

services:
  whoami:
    image: containous/whoami
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.whoami.rule=Host(`foo.example.com`)"
        - "traefik.http.services.whoami.loadbalancer.server.port=80"
    networks:
      - cloud-edge

networks:
  cloud-edge:
    external: true

Replace foo.example.com with name you've set up in DNS to refer to either node of your swarm. Start it with command

docker stack deploy -c test.yml test

It takes a few moments but eventually you can see the new route in dashboard URL provided before. In addition, when accessing http.//foo.example.com/ the service is invoked to show some information on your actual HTTP request.

Your Next Steps

  • Set up TLS encryption with LetsEncrypt.
  • Switch dashboard from insecure to secure mode.
  • Add some actual service exposed via your new edge router.

Troubleshooting

If something does not work you should start checking the logs of either service created before.

docker service logs -f cloud-socket-proxy_socket-proxy

This is showing the log of socket proxy which is probably listing failed requests by Traefik.

docker service logs -f cloud-edge_reverse-proxy

This command is showing the log of Traefik and it might also show errors regarding communication with Docker API. In addition it should log discovered services.

Go back