Docker 环境下使用 Traefik 3 的最佳实践:快速上手

2024-08-05 15:17:18 浏览数 (2)

Traefik 最近终于发布了大版本升级后的第一个修正版本,或许是时候正式迁移程序到新版本了。

写在前面

Traefik 3 正式发布

最近 Traefik 发布了 3.1 版本[1]。作为从 Traefik 1.x 开始使用的用户,Traefik 每个大版本升级都会出现一些配置不兼容的情况,这次 3.x 的正式升级也不例外。

虽然早在 Traefik 3.0 beta 的时候,我就写过尽可能兼容 3.x 版本的上手内容《Traefik v3.0 Docker 全面使用指南:基础篇[2]》,上个季度正式发布 3.0[3] 后,我们还是需要调整一些配置。

为了简化配置和上手的过程,我将我使用的基础配置开源在了 soulteary/traefik-v3-example[4],有需要可以自取。

下面,让我们来了解 Traefik 3 正式版的使用。

准备工作

为了上手简单,我们使用上面的开源项目代码为基础进行配置。

默认情况下,服务将运行在 80443 端口,所以,需要确保这两个端口没有其他程序占用。

获取基础配置代码

使用 git 将包含基础配置的项目下载到本地:

代码语言:javascript复制
git clone https://github.com/soulteary/traefik-v3-example.git

然后进入代码目录:

代码语言:javascript复制
cd traefik-v3-example

Docker 环境

关于 Docker 环境的准备,非常简单。

Docker, Develop faster, Run anywhere.

如果你使用的是图形化界面,尤其是 Windows 或者 macOS,可以访问 “Docker 官方网站[5]”,从网页下载安装程序,“一路下一步”,完成环境准备。

当然,你也可以参考之前的一些文章:

•如果你是 Windows 环境,可以参考《基于 Docker 的深度学习环境:Windows 篇[6]》中的“准备 Docker 虚拟化运行环境”来完成环境准备。•如果你是 Linux 操作系统,可以参考《在笔记本上搭建高性价比的 Linux 学习环境:基础篇[7]》中的“更简单的 Docker 安装”来完成环境准备。

准备 Traefik Docker 专用网络

在完成 Docker 的安装后,我们执行代码目录的脚本文件,就能够自动创建 Traefik 运行所需要的虚拟网络了:

代码语言:javascript复制
bash scripts/prepare-network.sh

命令执行后,如果一切正常,我们能够看到类似下面的日志内容:

代码语言:javascript复制
# bash scripts/prepare-network.sh

create docker network for traefik ok

让 Traefik 支持使用 HTTPS 证书

Traefik 支持两种方式来使用 HTTPS 证书:一种是使用我们准备好的证书文件,另一种是为我们拥有的域名自动申请“Let’s Encrypt”免费证书。去年这家非盈利证书机构已经为 3.63 亿网站提供了 TLS 证书。

关于第一种方式,我们可以在各种云服务商处购买或者申请免费的 HTTPS 证书,将 HTTPS 证书下载到本地,放在项目目录的 ssl 目录中即可。

当然,我们也可以贯彻免费到底,根据自己需求,自己生成一套证书来使用。

快速生成一套自己的签名证书

这里,推荐一个几年前写的开源证书生成小工具:soulteary/certs-maker[8]。如果你对自签名证书的基础知识、如何快速部署到系统感兴趣,可以阅读之前的文章:《如何制作和使用自签名证书[9]》。

如果你已经完成了 Docker 的安装,那么只需要使用下面的命令,就能够快速的完成自签名证书的生成了:

代码语言:javascript复制
docker run --rm -it -v `pwd`/ssl:/ssl soulteary/certs-maker:v3.5.0 "--CERT_DNS=lab.com,*.lab.com,*.data.lab.com"

当命令执行后,就能够得到证书文件了。

代码语言:javascript复制
[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=HelloWorld
- CERT_DOMAINS=[lab.com *.lab.com *.data.lab.com]
- APP_FOR_K8S=false
- APP_FOR_FIREFOX=false
- APP_OUTPUT_DIR=./ssl

上面的命令中,我们指定了本地系统目录的 ssl 目录和容器内的 /ssl 目录打通,所以只需要查看本地的 ssl 目录,就能够验收证书了:

代码语言:javascript复制
ls ssl    
lab.com.conf lab.com.crt  lab.com.key

不论是购买的证书还是自己生成的证书,我们只要放在 ssl 目录中就可以了,一会再用。

更新 Traefik 配置文件

根据你想 Traefik 使用 HTTPS 证书方式的不同,我们需要对示例代码的配置进行一些调整。

如果你选择自签名证书(参考上面的方法生成),或者云服务商处购买的域名,我们需要修改项目中的 .env 配置文件和 config/tls.toml 配置。

.env 配置文件中,我们需要将 Traefik 管理界面的域名地址修改为适配证书的域名:

代码语言:javascript复制
# 服务域名
SERVICE_DOMAIN=traefik.example.com

并在 config/certs.toml 配置中,更新相关的域名:

代码语言:javascript复制
[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 中的相关配置:

代码语言:javascript复制
# 服务域名
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_MAINDNS_LIST 我们想要申请的域名证书列表,需要拥有域名所有权,比如,你不能够申请 www.google.com 或者 www.apple.com 这种不属于你的域名。

至于 Cloudflare 的 API Key,我们可以在登录后的“API 令牌[10]”页面获得,配置方式参考下面的图片:

配置 CloudFlare API Key

快速上手

下面来分别介绍两种启动并使用 Traefik ,支持使用 HTTPS 证书的方法。

快速启动一个 Traefik 3 正式版程序

我们先来介绍配合购买或使用自签名的证书文件的使用方式。

想要使用这种方式,我们需要将目录中的 docker-compose.local-certs.yml 重命名为 docker-compose.yml,或者复制一份,将配置文件进行改名:

代码语言:javascript复制
cp docker-compose.local-certs.yml docker-compose.yml

上面的准备工作结束后,在代码目录中,我们执行下面的命令,就能够自动启动 Traefik 来提供服务了。

代码语言:javascript复制
docker compose down && docker compose up -d

命令执行后,我们将看到类似下面的日志内容:

代码语言:javascript复制
# 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 健康运行:

代码语言:javascript复制
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 地址。比如,我启动的容器在本地:

代码语言:javascript复制
127.0.0.1 traefik.example.com

使用浏览器访问 https://traefik.example.com ,我们就能够看到 Traefik 的管理界面了:

Traefik 的管理界面

如果你使用的是购买的证书,那么图中的小红锁默认应该就是绿色的。

信任自签名的 HTTPS 证书后,锁子就变绿了

如果你使用的是自签名证书,我们可以通过信任自签名证书,来解决浏览器中展示的“小红锁”,在不泄漏自签名证书的前提下,同样能够保证安全的访问,以及 HTTP2/3 请求特性。

启动 Traefik 并自动申请 HTTPS 证书

如果我们拥有某个域名,并且希望 Traefik 能够自动从网上申请免费的 HTTPS 证书,可以使用下面的方式。

我们需要将目录中的 docker-compose.acme.yml 重命名为 docker-compose.yml,或者复制一份,将配置文件进行改名:

代码语言:javascript复制
cp docker-compose.acme.yml docker-compose.yml

本文中,我使用的是 CloudFlare 的方式来申请证书,所以我们需要确保配置文件 .env 中的变量 CF_DNS_API_TOKEN 配置在 docker-compose.yml 中:

代码语言:javascript复制
environment:
  - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}

和上文中一样,我们使用下面的命令,就能够创建干净的容器,来运行 Traefik 并自动申请证书了:

代码语言:javascript复制
docker compose down && docker compose up -d

使用这种方式注册的证书,Traefik 会进行自动维护,在证书到期之前进行自动替换。不过,第一次注册的时候会比较漫长,如果我们打开 Traefik 可能看到它的申请或者证书续期的过程:

代码语言:javascript复制
# 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 端口来访问它:

代码语言:javascript复制
docker pull soulteary/flare:0.5.1
docker run --rm -it -p 5005:5005 soulteary/flare:0.5.1

运行在指定端口上的 Flare 程序

如果我们访问 http://localhost:5005 ,就能够看到上面的界面啦。

我们将上面的命令简化,去掉调试和自动清理容器的参数:

代码语言:javascript复制
docker run -p 5005:5005 soulteary/flare:0.5.1

使用工具转换 Docker 命令为 Compose 配置

然后,我们将命令粘贴到在线转换 Docker 命令到 Compose 的工具里,可以得到最简单的 Docker Compose 配置文件:

代码语言:javascript复制
name: flare
services:
  flare:
    ports:
      - 5005:5005
    image: soulteary/flare:0.5.1

我们可以对上面的配置进行一些修改,将上面的通过 5005 端口访问的程序,能够通过 flare.example.com 进行访问,并且支持自动将 HTTP 请求转换为 HTTPS 请求,并对访问内容自动进行 GZIP 压缩,提升访问加速:

代码语言:javascript复制
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

其他的程序也是如此,尤其是基于 Docker 运行的程序,都可以使用这个方式来处理,是不是非常简单?

最后

通过上面的介绍,相信你应该已经能够快速的将 Traefik 运行起来,完成一个支持 HTTPS 的网关服务的部署了。

并且,也应该能够快速的将原本只支持使用 HTTP 或者具体端口访问的程序,通过 Traefik 来统一管理和提供服务,告别需要为每一个程序都配置和管理证书的日子了。

--EOF

引用链接

[1] 发布了 3.1 版本: https://traefik.io/blog/announcing-traefik-proxy-v3-1/ [2] Traefik v3.0 Docker 全面使用指南:基础篇: https://soulteary.com/2023/07/18/traefik-v3-docker-comprehensive-user-guide-basics.html [3] 正式发布 3.0: https://traefik.io/blog/traefik-3-0-ga-has-landed-heres-how-to-migrate/ [4] soulteary/traefik-v3-example: https://github.com/soulteary/traefik-v3-example [5] Docker 官方网站: https://www.docker.com/ [6] 基于 Docker 的深度学习环境:Windows 篇: https://soulteary.com/2023/07/29/docker-based-deep-learning-environment-under-windows.html [7] 在笔记本上搭建高性价比的 Linux 学习环境:基础篇: https://soulteary.com/2022/06/21/building-a-cost-effective-linux-learning-environment-on-a-laptop-the-basics.html [8] soulteary/certs-maker: https://github.com/soulteary/certs-maker [9] 如何制作和使用自签名证书: https://soulteary.com/2021/02/06/how-to-make-and-use-a-self-signed-certificate.html#写在前面 [10] API 令牌: https://dash.cloudflare.com/profile/api-tokens

0 人点赞