Install Traefik

Introduction

Traefik is a high performance reverse proxy and load balancer, written in golang. It’s designed to integrate with service catalogs such as Consul. Other popular reverse proxies such as NGINX could be used but you will see how Traefik works much better for this particular solution.

If you choose to pursue a different solution, you taking it upon yourself to figure out how to make it work. Do not expect that any other product to slot in as an exact replacement.

Environment

For the sake of this guide, assume there are three cluster nodes with addressing such as:

node1 - 10.0.3.101
node2 - 10.0.3.102
node3 - 10.0.3.103

Performing actions as root

The ideal security model dictates that interactively operating as root is incorrect, and that operations should run as a user, using ‘sudo’ to elevate permissions where necessary. Unfortunately, almost everything that needs to be done here will require ‘sudo’, so it will be faster to just become root and run everything as root:

sudo su -

Perform the following steps on one node until instructed otherwise

Install Traefik

First, determine what the current Traefik version is that is available. Visit the following page and note the latest specific version. Do not use ‘latest’ or ‘stable’, always pull the most recent and most specific version (at the time of this writing, it was ‘2.10.7’).

DO NOT install use Traefik 3.x which was recently released. This configuration will not work. Use the latest Traefik 2.x for the time being. This chapter will be updated in the future to support the newer Traefik version.

https://hub.docker.com/_/traefik/tags

With that information, execute the following to create the directory structure for building the new container (and replace any version reference if a newer one exists):

mkdir -p /mnt/vagabond/docker/_build/traefik/2.10.7
cd /mnt/vagabond/docker/_build/traefik/2.10.7

Create the build script (and replace any version reference if a newer one exists):

cat << EOF > build.sh
#!/bin/bash
export DOCKER_SOURCE=traefik:2.10.7
export DOCKER_REGISTRY=registry.home.digitaldann.net:8443/traefik:2.10.7
docker pull \${DOCKER_SOURCE}
docker tag \${DOCKER_SOURCE} \${DOCKER_REGISTRY}
docker image push \${DOCKER_REGISTRY}
docker image rm \${DOCKER_SOURCE}
docker image rm \${DOCKER_REGISTRY}
EOF
chmod u+x build.sh

Now publish it to the local registry (removing future dependency on the internet-based registry):

./build.sh

Create Traefik configuration

Create the directory structure for the container bind mounts:

mkdir -p /mnt/vagabond/docker/traefik/certs

Create the default Traefik configuration:

cd /mnt/vagabond/docker/traefik
cat << EOF > traefik.yml
tls:
  options:
    default:
      minVersion: VersionTLS12
  certificates:
    - certFile: /etc/traefik/dynamic/certs/wildcard.pem
      keyFile: /etc/traefik/dynamic/certs/wildcard.key
  stores:
    default:
      defaultCertificate:
        certFile: /etc/traefik/dynamic/certs/wildcard.pem
        keyFile: /etc/traefik/dynamic/certs/wildcard.key
EOF

Copy the TLS certificates to the Traefik configuration:

cp /mnt/vagabond/ca/certs/wildcard.pem /mnt/vagabond/docker/traefik/certs/
cp /mnt/vagabond/ca/certs/wildcard.key /mnt/vagabond/docker/traefik/certs/

Create Nomad job file for Traefik

If you want to read the official documentation for the Nomad job file spec, here it is: https://developer.hashicorp.com/nomad/docs/job-specification/job

Create the directory structure for the Nomad jobs:

mkdir /mnt/vagabond/nomad
cd /mnt/vagabond/nomad

Now create the Nomad job file:

nano traefik.2.10.7.nomad

Write the following content and save the file:

job "traefik" {
  datacenters = ["dc1"]
  type        = "service"
  constraint {
    operator = "distinct_hosts"
    value = "true"
  }
  group "traefik" {
    count = 3
    network {
      mode = "bridge"
      port "http" {
         static = 80
      }
      port "https" {
         static = 443
      }
      port "http-ext" {
         static = 81
      }
      port "https-ext" {
         static = 444
      }
    }
    service {
      name = "dashboard"
      provider = "consul"
      port = "https"
      tags = [
        "traefik.enable=true",
        "traefik.http.routers.dashboard-${attr.unique.hostname}.entrypoints=websecure",
        "traefik.http.routers.dashboard-${attr.unique.hostname}.rule=Host(`dashboard.home.digitaldann.net`)",
        "traefik.http.routers.dashboard-${attr.unique.hostname}.service=api@internal",
        "traefik.http.routers.dashboard-${attr.unique.hostname}.tls=true"
      ]
    }
    service {
      name = "traefik"
      provider = "consul"
      port = "http"
    }
    task "traefik" {
      driver = "docker"
      config {
        image = "registry.home.digitaldann.net:8443/traefik:2.10.7"
        ports = ["http", "https", "http-ext", "https-ext"]
        volumes = [
          "/mnt/vagabond/docker/traefik:/etc/traefik/dynamic"
        ]
        args = [
          "--providers.docker=false",
          "--api.dashboard=true",
          "--entrypoints.web.address=:80",
          "--entrypoints.websecure.address=:443",
          "--entrypoints.web-ext.address=:81",
          "--entrypoints.websecure-ext.address=:444",
          "--entrypoints.web-ext.http.redirections.entrypoint.to=websecure",
          "--entrypoints.web-ext.http.redirections.entrypoint.scheme=https",
          "--providers.file.directory=/etc/traefik/dynamic",
          "--providers.consulcatalog=true",
          "--providers.consulcatalog.requireConsistent=true",
          "--providers.consulcatalog.cache=true",
          "--providers.consulcatalog.endpoint.address=http://${attr.unique.network.ip-address}:8500",
          "--providers.consulcatalog.endpoint.scheme=http",
          "--serversTransport.insecureSkipVerify=true"
        ]
      }
    }
  }
}

Deploy the Traefik job

This will deploy Traefik to the appropriate number of nodes (as defined by the job property ‘count’):

cd /mnt/vagabond/nomad
nomad job run traefik.2.10.7.nomad

You should see output that looks like:

==> 2023-12-21T01:47:34Z: Monitoring evaluation "7e6d80f6"
    2023-12-21T01:47:34Z: Evaluation triggered by job "traefik"
    2023-12-21T01:47:35Z: Evaluation within deployment: "c13539c4"
    2023-12-21T01:47:35Z: Allocation "0127c059" created: node "4b37faff", group "traefik"
    2023-12-21T01:47:35Z: Allocation "050c601e" created: node "32d39aab", group "traefik"
    2023-12-21T01:47:35Z: Allocation "d30a6a7e" created: node "f7d98ba8", group "traefik"
    2023-12-21T01:47:35Z: Evaluation status changed: "pending" -> "complete"
==> 2023-12-21T01:47:35Z: Evaluation "7e6d80f6" finished with status "complete"
==> 2023-12-21T01:47:35Z: Monitoring deployment "c13539c4"
  ✓ Deployment "c13539c4" successful
    
    2023-12-21T01:47:51Z
    ID          = c13539c4
    Job ID      = traefik
    Job Version = 0
    Status      = successful
    Description = Deployment completed successfully
    
    Deployed
    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
    traefik     3        3       3        0          2023-12-21T01:57:49Z

Validate registration with Consul

You will want to validate that the Traefik service registered with Consul. Consul has it’s own DNS service (running on port 8600), and querying <service-name>.service.consul should resolve to the addresses of the nodes running the service. In the case of Traefik, it will be all nodes. Run the following:

dig dashboard.service.consul @localhost -p 8600

You should see:

; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> dashboard.service.consul @localhost -p 8600
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16211
;; flags: qr aa rd; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;dashboard.service.consul.	IN	A

;; ANSWER SECTION:
dashboard.service.consul. 0	IN	A	10.0.3.101
dashboard.service.consul. 0	IN	A	10.0.3.102
dashboard.service.consul. 0	IN	A	10.0.3.103

Wrapping Up

You have deployed your first Nomad job. That’s great! Once the infrastructure is setup, deploying jobs is really straight forward.

Next, we’ll look at how to add DNS to enable custom local domains with Traefik!