本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 [署名 4.0 国际 (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/deed.zh) 本文作者: 苏洋 创建时间: 2024年08月04日 统计字数: 10293字 阅读时间: 21分钟阅读 本文链接: https://soulteary.com/2024/08/04/best-practices-for-traefik-3-in-docker-getting-started-quickly.html ----- # Docker 环境下使用 Traefik 3 的最佳实践:快速上手 Traefik 最近终于发布了大版本升级后的第一个修正版本,或许是时候正式迁移程序到新版本了。 ## 写在前面 ![Traefik 3 正式发布](https://attachment.soulteary.com/2024/08/04/traefik-3.jpg) 最近 Traefik [发布了 3.1 版本](https://traefik.io/blog/announcing-traefik-proxy-v3-1/)。作为从 Traefik 1.x 开始使用的用户,Traefik 每个大版本升级都会出现一些配置不兼容的情况,这次 3.x 的正式升级也不例外。 虽然早在 Traefik 3.0 beta 的时候,我就写过尽可能兼容 3.x 版本的上手内容《[Traefik v3.0 Docker 全面使用指南:基础篇](https://soulteary.com/2023/07/18/traefik-v3-docker-comprehensive-user-guide-basics.html)》,上个季度[正式发布 3.0](https://traefik.io/blog/traefik-3-0-ga-has-landed-heres-how-to-migrate/) 后,我们还是需要调整一些配置。 为了简化配置和上手的过程,我将我使用的基础配置开源在了 [soulteary/traefik-v3-example](https://github.com/soulteary/traefik-v3-example),有需要可以自取。 下面,让我们来了解 Traefik 3 正式版的使用。 ## 准备工作 为了上手简单,我们使用上面的开源项目代码为基础进行配置。 默认情况下,服务将运行在 `80` 和 `443` 端口,所以,需要确保这两个端口没有其他程序占用。 ### 获取基础配置代码 使用 `git` 将包含基础配置的项目下载到本地: ```bash git clone https://github.com/soulteary/traefik-v3-example.git ``` 然后进入代码目录: ```bash cd traefik-v3-example ``` ### Docker 环境 关于 Docker 环境的准备,非常简单。 ![Docker, Develop faster, Run anywhere.](https://attachment.soulteary.com/2024/08/04/docker.jpg) 如果你使用的是图形化界面,尤其是 Windows 或者 macOS,可以访问 “[Docker 官方网站](https://www.docker.com/)”,从网页下载安装程序,“一路下一步”,完成环境准备。 当然,你也可以参考之前的一些文章: - 如果你是 Windows 环境,可以参考《[基于 Docker 的深度学习环境:Windows 篇](https://soulteary.com/2023/07/29/docker-based-deep-learning-environment-under-windows.html)》中的“准备 Docker 虚拟化运行环境”来完成环境准备。 - 如果你是 Linux 操作系统,可以参考《[在笔记本上搭建高性价比的 Linux 学习环境:基础篇](https://soulteary.com/2022/06/21/building-a-cost-effective-linux-learning-environment-on-a-laptop-the-basics.html)》中的“更简单的 Docker 安装”来完成环境准备。 ### 准备 Traefik Docker 专用网络 在完成 Docker 的安装后,我们执行代码目录的脚本文件,就能够自动创建 Traefik 运行所需要的虚拟网络了: ```bash bash scripts/prepare-network.sh ``` 命令执行后,如果一切正常,我们能够看到类似下面的日志内容: ```bash # bash scripts/prepare-network.sh create docker network for traefik ok ``` ### 让 Traefik 支持使用 HTTPS 证书 Traefik 支持两种方式来使用 HTTPS 证书:一种是使用我们准备好的证书文件,另一种是为我们拥有的域名自动申请“Let’s Encrypt”免费证书。去年这家非盈利证书机构已经为 3.63 亿网站提供了 TLS 证书。 关于第一种方式,我们可以在各种云服务商处购买或者申请免费的 HTTPS 证书,将 HTTPS 证书下载到本地,放在项目目录的 `ssl` 目录中即可。 当然,我们也可以贯彻免费到底,根据自己需求,自己生成一套证书来使用。 ![快速生成一套自己的签名证书](https://attachment.soulteary.com/2024/08/04/certs-maker.jpg) 这里,推荐一个几年前写的开源证书生成小工具:[soulteary/certs-maker](https://github.com/soulteary/certs-maker)。如果你对自签名证书的基础知识、如何快速部署到系统感兴趣,可以阅读之前的文章:《[如何制作和使用自签名证书](https://soulteary.com/2021/02/06/how-to-make-and-use-a-self-signed-certificate.html#%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2)》。 如果你已经完成了 Docker 的安装,那么只需要使用下面的命令,就能够快速的完成自签名证书的生成了: ```bash docker run --rm -it -v `pwd`/ssl:/ssl soulteary/certs-maker:v3.5.0 "--CERT_DNS=lab.com,*.lab.com,*.data.lab.com" ``` 当命令执行后,就能够得到证书文件了。 ```bash [soulteary/certs-maker] v3.5.0 Flags: - CERT_COUNTRY= CN - CERT_STATE= BJ - CERT_LOCALITY= HD - CERT_ORGANIZATION= Lab - CERT_ORGANIZATIONAL_UNIT= Dev - CERT_COMMON_NAME= Hello World - CERT_DOMAINS= [lab.com *.lab.com *.data.lab.com] - APP_FOR_K8S= false - APP_FOR_FIREFOX= false - APP_OUTPUT_DIR= ./ssl ``` 上面的命令中,我们指定了本地系统目录的 `ssl` 目录和容器内的 `/ssl` 目录打通,所以只需要查看本地的 `ssl` 目录,就能够验收证书了: ```bash ls ssl lab.com.conf lab.com.crt lab.com.key ``` 不论是购买的证书还是自己生成的证书,我们只要放在 `ssl` 目录中就可以了,一会再用。 ### 更新 Traefik 配置文件 根据你想 Traefik 使用 HTTPS 证书方式的不同,我们需要对示例代码的配置进行一些调整。 如果你选择自签名证书(参考上面的方法生成),或者云服务商处购买的域名,我们需要修改项目中的 `.env` 配置文件和 `config/tls.toml` 配置。 在 `.env` 配置文件中,我们需要将 Traefik 管理界面的域名地址修改为适配证书的域名: ```bash # 服务域名 SERVICE_DOMAIN=traefik.example.com ``` 并在 `config/certs.toml` 配置中,更新相关的域名: ```bash [tls.stores.default.defaultCertificate] certFile = "/data/ssl/example.com.crt" keyFile = "/data/ssl/example.com.key" [[tls.certificates]] certFile = "/data/ssl/example.com.crt" keyFile = "/data/ssl/example.com.key" # others... # [[tls.certificates]] # certFile = "/data/ssl/lab.com.crt" # keyFile = "/data/ssl/lab.com.key" ``` 如果你拥有域名,希望使用免费申请的 HTTPS 证书,我们可以删除掉 `config/certs.toml` 配置文件,然后更新 `.env` 中的相关配置: ```bash # 服务域名 SERVICE_DOMAIN=traefik.example.com # 示例,使用 CloudFlare 来申请证书 ACME_PROVIDER=cloudflare ACME_EMAIL=your-email@company.ltd # CF DNS API Token CF_DNS_API_TOKEN=your-cf-dns-api-token # DNS Domain (main) DNS_MAIN=example.com # DNS Domain (list) DNS_LIST=example.com,*.example.com ``` 除了要和上面一样更新域名之外,我们还需要配置一些申请免费证书必须的配置,包括下面的内容(使用 CloudFlare DNS 申请证书为例): - `ACME_PROVIDER`:使用什么方式来申请免费证书。 - `ACME_EMAIL`:申请证书要使用的邮箱。 - `CF_DNS_API_TOKEN`:我使用 Cloudflare,这里需要配置 API Token 来操作 DNS 记录,完成域名所有权验证,进行证书申请。 - `DNS_MAIN` 和 `DNS_LIST` 我们想要申请的域名证书列表,需要拥有域名所有权,比如,你不能够申请 `www.google.com` 或者 `www.apple.com` 这种不属于你的域名。 至于 Cloudflare 的 API Key,我们可以在登录后的“[API 令牌](https://dash.cloudflare.com/profile/api-tokens)”页面获得,配置方式参考下面的图片: ![配置 CloudFlare API Key](https://attachment.soulteary.com/2024/08/04/cf-dns.jpg) ## 快速上手 下面来分别介绍两种启动并使用 Traefik ,支持使用 HTTPS 证书的方法。 ### 快速启动一个 Traefik 3 正式版程序 我们先来介绍配合购买或使用自签名的证书文件的使用方式。 想要使用这种方式,我们需要将目录中的 `docker-compose.local-certs.yml` 重命名为 `docker-compose.yml`,或者复制一份,将配置文件进行改名: ```bash cp docker-compose.local-certs.yml docker-compose.yml ``` 上面的准备工作结束后,在代码目录中,我们执行下面的命令,就能够自动启动 Traefik 来提供服务了。 ```bash docker compose down && docker compose up -d ``` 命令执行后,我们将看到类似下面的日志内容: ```bash # docker compose down && docker compose up -d [+] Building 0.0s (0/0) docker:desktop-linux [+] Running 1/1 ✔ Container traefik Started ``` 如果我们执行 `docker compose ps`,将能够看到 Traefik 健康运行: ```bash NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS traefik traefik:v3.1.1 "/entrypoint.sh --global.sendanonymoususage=false --global.checknewversion=false --entrypoints.http.address=:80 --entrypoints.https.address=:443 --entryPoints.https.asDefault=true --entryPoints.https.http3 --entryPoints.https.http3.advertisedport=443 --serverstransport.insecureskipverify=true --entryPoints.http.forwardedHeaders.trustedIPs=127.0.0.1/32,172.18.0.1/24 --entryPoints.https.forwardedHeaders.trustedIPs=127.0.0.1/32,172.18.0.1/24 --api=true --api.dashboard=true --ping=true --log.level=INFO --log.maxsize=100 --log.format=common --accesslog=false --providers.docker=true --providers.docker.watch=true --providers.docker.exposedbydefault=false --providers.docker.endpoint=unix:///var/run/docker.sock --providers.docker.useBindPortIP=false --providers.docker.network=traefik --providers.file=true --providers.file.watch=true --providers.file.directory=/etc/traefik/config --providers.file.debugloggeneratedtemplate=true" traefik 3 minutes ago Up 3 minutes (healthy) 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:443->443/udp ``` 当服务出现问题的时候,Docker 将会自动恢复程序的运行。 在这个示例代码中,默认的自签名证书支持 `example.com` 和 `*.exmaple.com` 相关的域名,而 Traefik 默认的管理界面域名是 `traefik.example.com`。 我们可以通过修改系统的 `/etc/hosts` 或者局域网 DNS 指向,将 `traefik.example.com` 指向启动 traefik 容器的 IP 地址。比如,我启动的容器在本地: ```bash 127.0.0.1 traefik.example.com ``` 使用浏览器访问 `https://traefik.example.com` ,我们就能够看到 Traefik 的管理界面了: ![Traefik 的管理界面](https://attachment.soulteary.com/2024/08/04/traefik-dash.jpg) 如果你使用的是购买的证书,那么图中的小红锁默认应该就是绿色的。 ![信任自签名的 HTTPS 证书后,锁子就变绿了](https://attachment.soulteary.com/2024/08/04/https-vaild.jpg) 如果你使用的是自签名证书,我们可以通过信任自签名证书,来解决浏览器中展示的“小红锁”,在不泄漏自签名证书的前提下,同样能够保证安全的访问,以及 HTTP2/3 请求特性。 ### 启动 Traefik 并自动申请 HTTPS 证书 如果我们拥有某个域名,并且希望 Traefik 能够自动从网上申请免费的 HTTPS 证书,可以使用下面的方式。 我们需要将目录中的 `docker-compose.acme.yml` 重命名为 `docker-compose.yml`,或者复制一份,将配置文件进行改名: ```bash cp docker-compose.acme.yml docker-compose.yml ``` 本文中,我使用的是 CloudFlare 的方式来申请证书,所以我们需要确保配置文件 `.env` 中的变量 `CF_DNS_API_TOKEN` 配置在 `docker-compose.yml` 中: ```yaml environment: - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN} ``` 和上文中一样,我们使用下面的命令,就能够创建干净的容器,来运行 Traefik 并自动申请证书了: ```bash docker compose down && docker compose up -d ``` 使用这种方式注册的证书,Traefik 会进行自动维护,在证书到期之前进行自动替换。不过,第一次注册的时候会比较漫长,如果我们打开 Traefik 可能看到它的申请或者证书续期的过程: ```bash # docker compose logs -f traefik | 2024-08-04T19:23:17+08:00 INF Traefik version 3.1.1 built on 2024-07-30T13:55:22Z version=3.1.1 traefik | 2024-08-04T19:23:17+08:00 INF traefik | Stats collection is disabled. traefik | Help us improve Traefik by turning this feature on :) traefik | More details on: https://doc.traefik.io/traefik/contributing/data-collection/ traefik | traefik | 2024-08-04T19:23:17+08:00 INF Starting provider aggregator aggregator.ProviderAggregator traefik | 2024-08-04T19:23:17+08:00 INF Starting provider *file.Provider traefik | 2024-08-04T19:23:17+08:00 INF Starting provider *traefik.Provider traefik | 2024-08-04T19:23:17+08:00 INF Starting provider *docker.Provider traefik | 2024-08-04T19:23:17+08:00 INF Starting provider *acme.ChallengeTLSALPN traefik | 2024-08-04T19:23:17+08:00 INF Starting provider *acme.Provider traefik | 2024-08-04T19:23:17+08:00 INF Testing certificate renew... acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=le.acme ... ``` 一般情况下,3~5 分钟证书就注册好了。 ## 快速启动一个服务,注册到 Traefik 上 接下来,使用一个简单的例子,来说明如何将一个运行在某个具体端口上的程序,注册到 Traefik 网关中,并支持 HTTPS 访问。 还是以之前写过的一个简单的开源程序 `flare` 为例,下面的命令将下载 `flare` 并运行它,最终允许我们使用 `5005` 端口来访问它: ```bash docker pull soulteary/flare:0.5.1 docker run --rm -it -p 5005:5005 soulteary/flare:0.5.1 ``` ![运行在指定端口上的 Flare 程序](https://attachment.soulteary.com/2024/08/04/flare.jpg) 如果我们访问 `http://localhost:5005` ,就能够看到上面的界面啦。 我们将上面的命令简化,去掉调试和自动清理容器的参数: ```bash docker run -p 5005:5005 soulteary/flare:0.5.1 ``` ![使用工具转换 Docker 命令为 Compose 配置](https://attachment.soulteary.com/2024/08/04/convert-docker-to-compose.jpg) 然后,我们将命令粘贴到在线转换 Docker 命令到 Compose 的工具里,可以得到最简单的 Docker Compose 配置文件: ```yaml name: flare services: flare: ports: - 5005:5005 image: soulteary/flare:0.5.1 ``` 我们可以对上面的配置进行一些修改,将上面的通过 `5005` 端口访问的程序,能够通过 `flare.example.com` 进行访问,并且支持自动将 HTTP 请求转换为 HTTPS 请求,并对访问内容自动进行 GZIP 压缩,提升访问加速: ```yaml name: flare services: flare: image: soulteary/flare:0.5.1 networks: - traefik labels: # 用于 Traefik 服务发现 - "traefik.enable=true" - "traefik.docker.network=traefik" # HTTP 相关 # 使用 HTTP 协议访问 Flare,将使用 `http`(80端口) 提供服务 - "traefik.http.routers.flare-http.entrypoints=http" # 并自动跳转至 HTTPS 协议(443端口) - "traefik.http.routers.flare-http.middlewares=redir-https" # 默认服务域名为 flare.example.com - "traefik.http.routers.flare-http.rule=Host(`flare.example.com`)" # 服务名称为 noop@internal,表示不提供任何服务 (因为自动跳转,没必要请求服务) - "traefik.http.routers.flare-http.service=noop@internal" # HTTPS 相关 # 使用 HTTPS 协议访问 Flare,将使用 `https`(443端口) 提供服务 - "traefik.http.routers.flare-https.entrypoints=https" # 在这个端口上使用 TLS 协议 - "traefik.http.routers.flare-https.tls=true" # 对响应内容启用 GZIP 压缩 - "traefik.http.routers.flare-https.middlewares=gzip" # 默认服务域名为 flare.example.com - "traefik.http.routers.flare-https.rule=Host(`flare.example.com`)" # (可选)HTTPS 服务名称为 flare-backend,使用 5005 端口提供服务 - "traefik.http.routers.flare-https.service=flare-backend" # 服务相关 # 声明服务名称为 flare-backend,使用 5005 端口提供服务 - "traefik.http.services.flare-backend.loadbalancer.server.scheme=http" - "traefik.http.services.flare-backend.loadbalancer.server.port=5005" networks: traefik: external: true ``` 我们将上面的内容保存为 `docker-compose.flare.yml` 后,使用 `docker compose -f docker-compose.flare.yml up -d` 启动容器后。使用浏览器访问 `flare.example.com` 就能够通过 HTTPS 的方式来访问到我们的程序啦。 ![使用域名来快速访问 Flare](https://attachment.soulteary.com/2024/08/04/flare-with-tls.jpg) 其他的程序也是如此,尤其是基于 Docker 运行的程序,都可以使用这个方式来处理,是不是非常简单? ## 最后 通过上面的介绍,相信你应该已经能够快速的将 Traefik 运行起来,完成一个支持 HTTPS 的网关服务的部署了。 并且,也应该能够快速的将原本只支持使用 HTTP 或者具体端口访问的程序,通过 Traefik 来统一管理和提供服务,告别需要为每一个程序都配置和管理证书的日子了。 --EOF