Traefik是Go语言开发的一个开源“边界路由器(Edge Router)”,对部署微服务(Microservices)非常方便。

此文主要讨论和Docker的结合用法。以后会讨论和kubernetes结合的用法。

Traefik和Docker结合使用示意图

Traefik 2 配置文件

Traefik支持多种类型的文件配置:YAML, TOML, CMD Line。本文使用YAML格式配置。其他格式可参考官方文档:Traefik 官方文档

  • 例子中HTTPS只使用TLS1.3,可以根据自己的需要进行调整

## traefik.yml

api:
  insecure: false

providers:
  docker: {}

tls:
  options:
    default:
      minVersion: VersionTLS13
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
      curvePreferences:
        - CurveP521
        - CurveP384

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entrypoint:
          to: https
          scheme: https

  https:
    address: ":443"

certificatesResolvers:
  rip996_resolver:
    acme:
      email: "<邮箱必填>" [1]
      storage: "acme.json"
      tlsChallenge: {}

[1] 根据letsencrypt的要求,邮箱为必填项。

docker-compose.yml 部署在docker swarm环境中


下面的docker-compose.yml基于以下假设:

  • 访问HTTP会自动跳转到HTTPS网页
  • 假设系统中docker swarm已启用
  • 假设API网址为traefik_api_demo.996.rip
  • 假设HTTPS使用Letsencrypt提供的证书
  • Docker overlay network起名为traefik-public

创建外部的 docker overlay network

docker network create --driver=overlay traefik-public --opt encrypted=true


采用--opt encrypted=true flag, docker会创建一个IPSec VPN通道

在相同docker overlay网络中的服务直接无需暴露端口。

docker-compose.yml

为了尽可能展示多的traefik操作,下面的compose文件也展示了使用command作为参数来传入traefik。其优先级高于上面的traefik.yml配置文件。

version: '3.8'

services:
  traefik:
    image: traefik:2.3
    volumes:
      - $PWD/traefik.yml:/etc/traefik/traefik.yml
      - /var/run/docker.sock:/var/run/docker.sock:ro # [1]
      # Mount the volume to store the certificates
      - traefik-public-certificates:/certificates

    command:
      - --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`)
      - --providers.docker.exposedbydefault=false
      - --providers.docker.swarmmode
      - --entrypoints.http.http.middlewares=traefik-forward-auth
      - --certificatesresolvers.le.acme.storage=/certificates/acme.json
      - --accesslog
      - --log
      - --api
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
    networks:
      - traefik-public
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik-public
      - traefik.constraint-label=traefik-public
      - traefik.http.middlewares.admin-auth.basicauth.users=api_demo:api_salt    # [2]
      - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
      - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
      - traefik.http.routers.traefik-public-http.rule=Host(`traefik_api_demo.996.rip`) # [3]
      - traefik.http.routers.traefik-public-http.entrypoints=http
      - traefik.http.routers.traefik-public-http.middlewares=https-redirect
      - traefik.http.routers.traefik-public-https.rule=Host(`traefik_api_demo.996.rip`) # [3]
      - traefik.http.routers.traefik-public-https.entrypoints=https
      - traefik.http.routers.traefik-public-https.tls=true
      - traefik.http.routers.traefik-public-https.service=api@internal
      - traefik.http.routers.traefik-public-https.tls.certresolver=rip996_resolver # [4]
      - traefik.http.routers.traefik-public-https.middlewares=admin-auth # [5]
      # Define the port inside of the Docker service to use
      - traefik.http.services.traefik-public.loadbalancer.server.port=8080
    deploy:
      mode: global
      placement:
        constraints:
          - node.role == manager
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.labels.traefik-public.traefik-public-certificates == true 
         # [6]

networks:
  traefik-public:
    external: true

volumes:
  traefik-public-certificates:

[1] 和Portainer不同,Traefik只需docker API的读权限。此处使用:ro更加安全

[2] API面板的用户名和Hash过的密码(可以使用salt);下文会介绍如何生成。

[3] 需要改为自己的域名

[4] 名字需要与traefik.yml配置文件里面定义的相对应

[5] 声明使用的Traefik中间件

[6] 对Traefik部署的节点进行限制

使用openssl生成hash后的密码(下面的密码实例为密码生成器随机生成)

假设密码为:9ffcpU9Slq8IgI7xCSsBdcO8icCSh5HXhEhg4UfrCF3XdkqFML3faXf

salt 为:mvKllv8WLho2482riUnh6Zpb7ZpZyqaDl6dfzmlL6IOqd4rebxifuN31lL8v1Z4o

openssl passwd -apr1 \
-salt mvKllv8WLho2482riUnh6Zpb7ZpZyqaDl6dfzmlL6IOqd4rebxifuN31lL8v1Z4o \
9ffcpU9Slq8IgI7xCSsBdcO8icCSh5HXhEhg4UfrCF3XdkqFML3faXf

输出为:

$apr1$mvKllv8W$Uhn21qk0cRzMFyejdkRmi.

上述方法仅建议个人网站使用,工业生产环境中建议使用更安全的基于Argon2或者Scrypt的密钥生成算法(key derivation algorithm)。

Traefik部署命令

docker stack deploy -c docker-compose.yml traefik_996_rip_demo

总结

Traefik在实际使用中很少从头写起。很多配置对不同的部署环境中是通用的,大部分情况基本就是复制粘贴。

与Nginx不同,通常是先部署Traefik服务,然后其他需要被反代的服务随后添加。添加被反代的服务基本无需调整Traefik的配置。

Last modification:September 6th, 2020 at 01:19 pm