引言

Traefik 在实质功能上与 Nginx 差不多,都是高性能的反向代理,也可以说是边缘路由。

我曾在很长一段时间内使用纯 Nginx 作为边缘的反向代理,容器编排工具使用的是Docker Swarm。Swarm 在某些场景下的支持没有 Kubernetes 那么完备,对于服务发布,k8s 用 Ingress Controller  + Ingress 就能解决的事情,Swarm下就得自行配置。 发布的所有服务,其配置都需要集中到 Nginx 下,而且配置文件也需要自行维护,配置稍微一改,Nginx 就得手动 reload 配置,另外做 log 也得自己手工操作……。作为一个标准的懒人,我对这种重复的劳动早已厌烦。

Traefik 是一款专门针对于微服务的边界路由,它能够解决开发者在服务发布时的大部分问题,而且配置都是自动感知、自动更新的,无需重启,不需要开发者手动维护配置文件,同时也提供了服务监控方法。相对于 Nginx ,它的维护成本低的很多。开发者只需要正确使用声明式配置发布自己的服务就可以了,剩下的工作都是 Traefik 自己去做。

Let's Encrypt

Let’s Encrypt 是一家免费、开放、自动化的证书颁发机构(CA),为公众的利益而运行。它是一项由 Internet Security Research Group(ISRG)提供的服务。 我们以尽可能对用户友好的方式免费提供为网站启用 HTTPS(SSL/TLS)所需的数字证书。这是因为我们想要创建一个更安全,更尊重隐私的 Web 环境。

关于 Let‘s Encrypt ,相信能看到这篇博客的朋友都会对它很熟悉了。在HTTPS走向主流的这段时间,Let’s Encrypt 起到了十分重要的作用。

在早期,SSL 证书都是收费的,而且价格不菲,那个时候尽管有一些免费证书,但是申请比较麻烦、且有效期也就几周到一两个月不等,没有任何保障,当初HTTPS也基本在企业或者银行系统上使用,搜索引擎也不太会收录这些网站。随着互联网的发展,信息安全意识的增强,HTTPS 已成为了主流,有非盈利组织开始免费提供SSL证书给个人使用,搜索引擎也开放对 HTTPS 站的收录并且给予更高的权重,在 HTTP2 中,已经开始强制要求使用HTTPS。

Traefik 对 Let's Encrypt 的支持

Traefik 支持 Let's Encrypt 的自动申请、自动部署、自动更新。这也许是我当初毅然决然地抛弃 Nginx 的重要原因。

SSL证书的签发、部署、更新、再部署是比较麻烦的事情,且Let's Encrypt 提供的 SSL 证书只有 90 天的有效期,一年内证书更新的次数就比较频繁了,而且随着服务、域名的规模逐渐扩大,其维护成本也会大大增加 ( 当然到了这个地步,也就不非得用Let’s Encrypt 了 )。尽管可以使用 cron 任务减轻自己的维护压力,但是感觉还是不太方便。

Traefik 对这一块的支持非常好,仅需要简单的声明就可以实现申请、部署、更新一条龙。

Traefik 配置 Let's Encrypt Resolver

我是在 Docker Swarm 下部署的 Traefik, 在k8s或者其他容器编排服务下,配置也是类似的,具体可以查看文档。


version: "3.8"

services:
  reserve-proxy:
    image: traefik:v2.0
    command:
      - --api.insecure=true
      - --providers.docker
      - --providers.docker.swarmMode=true
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      # 以下为配置 Let's Encrypt 
      - [email protected]
      - --certificatesresolvers.myresolver.acme.storage=acme.json
      - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
    networks:
      - traefik_app
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        mode: host
        published: 443
      - target: 8080
        published: 65080
        mode: host
    volumes:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock
      - type: bind
        source: /etc/localtime
        target: /etc/localtime
        read_only: true
    deploy:
      mode: global
      placement:
        constraints:
          - "node.role==manager"
      restart_policy:
        condition: on-failure
       
networks:
  traefik_app:
    driver: overlay
    attachable: true
traefik.yaml

其中的主要配置为

[email protected]
--certificatesresolvers.myresolver.acme.storage=acme.json
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web

具体配置可参照:https://docs.traefik.io/v2.3/https/acme/

邮箱需要设置为你自己的邮箱,一定要记住自己resolver为“myresolver”,后期配置服务的时候会用到,当然这个值是可以修改的。

在服务上配置证书以及http跳转https

version: "3.8"

services:
    ghost:
        image: ghost:3.31.5
        networks:
          - traefik_traefik_app
        environment:
          - "url=https://ibytes.cn"
        volumes:
          # ....
        expose:
          - "2368"
        deploy:
          mode: replicated
          replicas: 1
          labels:
            # for traefik
            - traefik.enable=true
            - traefik.http.routers.ghost-insecure.rule=Host(`www.ibytes.cn`,`ibytes.cn`)
            - traefik.http.routers.ghost.entrypoints=web
            - traefik.http.routers.ghost-insecure.middlewares=ghost-redirect
            - traefik.http.middlewares.ghost-redirect.redirectscheme.scheme=https
            - traefik.http.routers.ghost.rule=Host(`www.ibytes.cn`,`ibytes.cn`)
            - traefik.http.routers.ghost.entrypoints=websecure
            - traefik.http.routers.ghost.tls=true
            - traefik.http.routers.ghost.tls.certresolver=myresolver
            - traefik.http.services.ghost-blog-service.loadbalancer.server.port=2368

networks:
  traefik_traefik_app:
    external: true
ghost.yaml

配置项比较多,但是比较容易理解。

# for traefik
- traefik.enable=true
# 配置 80 端口上的服务
- traefik.http.routers.ghost-insecure.rule=Host(`www.ibytes.cn`,`ibytes.cn`)
- traefik.http.routers.ghost.entrypoints=web

# 配置中间件,用于跳转,注意中间件名称和下面定义的一致
- traefik.http.routers.ghost-insecure.middlewares=ghost-redirect
# 设置跳转到https
- traefik.http.middlewares.ghost-redirect.redirectscheme.scheme=https

# 配置 443 端口上的服务
- traefik.http.routers.ghost.rule=Host(`www.ibytes.cn`,`ibytes.cn`)
- traefik.http.routers.ghost.entrypoints=websecure
# 配置 tls 证书
- traefik.http.routers.ghost.tls=true
# 配置 CertResolver 要记得 resolver的名字
- traefik.http.routers.ghost.tls.certresolver=myresolver
# 配置服务的port
- traefik.http.services.ghost-blog-service.loadbalancer.server.port=2368

小结

使用Traefik 2 配置 Let's Encrypt 以及设置 http 跳转 https 总体上来说是十分方便的,不需要修改任何配置文件,只需要几个声明式的配置标签就可以了,后期也完全不需要开发者再次维护,申请、部署、更新都是自动进行的。

作者的个人博客以及其他服务使用的正是 Traefik + Swarm 的解决方案,总体性能稳定。在性能之外,最终要的是使用 Traefik 大大降低了我的维护成本。

我最早尝试 Traefik 的时候遇到了不少问题,大部分的问题都是配置与版本不兼容导致的,尤其注意的是 1.7 到 2.0 是破坏性更新,网上找到的一些配置不一定能对应上自己使用的版本,配置时要慎重。

一定要多翻翻文档,大部分问题可以从文档中找到答案。