0%

Traefik-V2.x & Docker-Compose & Https 最佳实践

介绍说明

先记录,其他后面补!

具体部署文档

./traefik/docker-compose.yaml

version: '3.7'
services:
  traefik:
    image: traefik:v2.3.4
    restart: always
    environment:
    # https://developer.aliyun.com/endpoints#service_alidns
    # https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/README-CN.md
    - ALICLOUD_REGION_ID=cn-hangzhou
    - ALICLOUD_ACCESS_KEY=XXXXXXXX
    - ALICLOUD_SECRET_KEY=XXXXXXXX
    command:
    - "--log.level=INFO"
    - "--api.insecure=true"
    - "--api.dashboard=true"
    - "--providers.docker.swarmMode=false"
    - "--providers.docker.useBindPortIP=true"
    - "--providers.docker.network=net-traefik"
    - "--providers.docker.exposedbydefault=false"
    - "--providers.file.directory=/etc/traefik/"
    - "--providers.file.watch=true"
    - "--entrypoints.http.address=:80"
    - "--entrypoints.https.address=:443"
    # 配置 ACME 相关
    # https://doc.traefik.io/traefik/https/acme/
    - "--certificatesresolvers.acme-resolver.acme.email=username@domain.org"
    - "--certificatesresolvers.acme-resolver.acme.storage=/etc/traefik/acme.json"
    # - "--certificatesresolvers.acme-resolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
    - "--certificatesresolvers.acme-resolver.acme.preferredchain=ISRG Root X1"
    - "--certificatesresolvers.acme-resolver.acme.keytype=RSA4096"
    - "--certificatesresolvers.acme-resolver.acme.dnschallenge.provider=alidns"
    - "--certificatesresolvers.acme-resolver.acme.dnschallenge.delaybeforecheck=0"
    - "--certificatesresolvers.acme-resolver.acme.dnschallenge.resolvers=223.5.5.5:53,114.114.114.114:53,8.8.8.8:53"
    - "--certificatesresolvers.acme-resolver.acme.dnschallenge.disablepropagationcheck=true"
    logging:
      driver: json-file
      options:
        max-size: "200k"
        max-file: "10"
    labels:
    - "traefik.enable=true"
    - "traefik.http.routers.traefik_http.rule=Host(`traefik.domain.org`)"
    - "traefik.http.routers.traefik_http.entrypoints=http"
    - "traefik.http.routers.traefik_http.middlewares=gzip,auth"
    - "traefik.http.routers.traefik_https.rule=Host(`traefik.domain.org`)"
    - "traefik.http.routers.traefik_https.entrypoints=https"
    - "traefik.http.routers.traefik_https.middlewares=gzip,auth"
    - "traefik.http.routers.traefik_https.tls=true"
    # 定义共享证书
    - "traefik.http.routers.traefik_https.tls.certresolver=acme-resolver"
    - "traefik.http.routers.traefik_https.tls.domains[0].main=domain.org"
    - "traefik.http.routers.traefik_https.tls.domains[0].sans=domain.org,*.domain.org"
    # 使用 Swarm 模式要显式定义 service 否则不会被路由
    - "traefik.http.services.traefik.loadbalancer.server.port=8080"
    # 定义共享中间件
    - "traefik.http.middlewares.gzip.compress=true"
    - "traefik.http.middlewares.ssl.headers.sslRedirect=true"
    - "traefik.http.middlewares.auth.basicauth.users=XXXXXXXX"
    networks:
    - traefik
    ports:
    - '80:80'
    - "443:443"
    volumes:
    - "/var/run/docker.sock:/var/run/docker.sock:ro"
    - "/path/:/etc/traefik/:rw"
networks:
  traefik:
    name: net-traefik

./service/docker-compose.yaml

version: '3.7'
services:
  service1:
    image: 6xyun/whoami
    restart: always
    labels:
    - "traefik.enable=true"
    - "traefik.http.routers.traefik_http.entrypoints=http"
    - "traefik.http.routers.traefik_http.rule=Host(`service.domain.org`)"
    - "traefik.http.routers.traefik_http.middlewares=gzip"
    - "traefik.http.routers.traefik_https.entrypoints=https"
    - "traefik.http.routers.traefik_https.rule=Host(`service.domain.org`)"
    - "traefik.http.routers.traefik_https.middlewares=gzip"
    # - "traefik.http.routers.cltfile_https.tls.certresolver=acme-resolver"
    - "traefik.http.routers.traefik_https.tls=true"
    - "traefik.http.services.service.loadbalancer.server.port=80"
    - "traefik.http.services.service.loadbalancer.healthCheck.path=/"
    - "traefik.http.services.service.loadbalancer.healthCheck.port=80"
    - "traefik.http.services.service.loadbalancer.healthCheck.interval=10s"
    - "traefik.http.services.service.loadbalancer.healthCheck.timeout=3s"
    networks:
    - traefik
  service2:
    image: 6xyun/whoami
    restart: always
    labels:
    - "traefik.enable=true"
    - "traefik.http.routers.traefik_http.entrypoints=http"
    - "traefik.http.routers.traefik_http.rule=Host(`service.domain.org`)"
    - "traefik.http.routers.traefik_http.middlewares=gzip"
    - "traefik.http.routers.traefik_https.entrypoints=https"
    - "traefik.http.routers.traefik_https.rule=Host(`service.domain.org`)"
    - "traefik.http.routers.traefik_https.middlewares=gzip"
    # - "traefik.http.routers.cltfile_https.tls.certresolver=acme-resolver"
    - "traefik.http.routers.traefik_https.tls=true"
    - "traefik.http.services.service.loadbalancer.server.port=80"
    - "traefik.http.services.service.loadbalancer.healthCheck.path=/"
    - "traefik.http.services.service.loadbalancer.healthCheck.port=80"
    - "traefik.http.services.service.loadbalancer.healthCheck.interval=10s"
    - "traefik.http.services.service.loadbalancer.healthCheck.timeout=3s"
    networks:
    - traefik
networks:
  traefik:
    name: net-traefik
    external: true

关于 HTTPS 配置

证书池

  • 先说一下 Traefik 证书大概的规则吧,Traefik 只有一个证书池。
  • 虽然每个服务都定义了 tls 配置, 但最终获得/生成的证书都被 Traefik 加载并全局使用,例如上面的例子,Traefik 的配置里面配置了 Let's Encrypt 的泛域名证书支持,其他的服务里面就不必在写 certresolver 属性, 只需要配置 tls=true 开启 TLS 就可以了,Traefik 检测到服务需要 TLS支持会在全局的证书池里面去寻找并匹配,匹配上了就能直接使用,没有匹配到就会使用默认证书(开启 Let's Encrypt 后如果没匹配上会自动进行签发)。

使用 Let's Encrypt 证书

  • 完全可以参照官方文档进行配置,但是有一点小细节还是需要记录一下。
  • Let's Encrypt 是免费的,并且理论上支持无限续期。
  • Let's Encrypt 只允许通过 dnschallenge 方式认证的域名申请泛域名证书。
  • 2021年10月 之后颁发的证书由于 Root CA 切换可能在一些低版本系统中不被信任(例如:Windows XP、Android 7以下)。

使用本地证书

  • 这个问题由于我没有仔细阅读文档导致我踩坑踩了两天。
  • 如同我上面贴出来的服务,注意里面的 providers.file.directory 属性,这就是关键了。
  • 原始文档里面说明了:除了 k8s 环境以外,其他环境使用本地证书只能通过 file provider 的方式加载。

https://doc.traefik.io/traefik/https/tls/#user-defined

  • 而在 Docker/Swarm 中开启 Traefikfile provider 就需要配置 providers.file.directory,让 Traefik 能够从这个配置对应的目录中去读取配置。

https://doc.traefik.io/traefik/providers/file/#provider-configuration

  • 完成上面的操作之后, 只需要在对应的目录中创建好配置文件,就能让 Traefik 加载上本地证书了。附一份配置示例:
# filename:cert.yaml
tls:
  certificates:
  - certFile: /path/to/domain.cert
    keyFile: /path/to/domain.key
  - certFile: /path/to/other-domain.cert
    keyFile: /path/to/other-domain.key

本地证书链配置方式

  • 这个文档里面好像确实没有。本人也是依照别的组件配置试验出来的。
  • 用常用的 .pem 格式证书举例子:
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(A:服务证书)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(B:签发A证书的CA证书)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(C:签发B证书的CA证书)
-----END CERTIFICATE-----
...
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(ROOT CA)
-----END CERTIFICATE-----

如上内容所示,这就是一个证书链格式了,其中需要注意的是证书顺序,按照级别从低到高的顺序进行排序(第一个是服务证书,最后一个一般是 ROOT CAROOT CA 的下一级证书)。

警告:证书文件当中不要包含私钥。

  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/85
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!