Traefik 配合 Docker 暴露服务实战:从第一个 HTTP 服务到路径路由与 TLS 加密
2026/9/7 19:53:16 网站建设 项目流程

Traefik 配合 Docker 暴露服务实战:从第一个 HTTP 服务到路径路由与 TLS 加密

【免费下载链接】traefikThe Cloud Native Application Proxy项目地址: https://gitcode.com/GitHub_Trending/tr/traefik

本文以 Traefik 仓库中的官方入门指南(expose/docker/basic.md)为主体,完整讲解如何在 Docker 环境中让 Traefik 通过容器标签自动发现并暴露 HTTP 服务:从搭建第一个 whoami 路由、按 URL 路径分流到不同后端,再到为服务启用 TLS 终止。读完本文,你将掌握traefik.http.routers.*标签的编写方式、Docker provider 的动态配置生成机制,以及结合 File provider 挂载自签证书的完整 HTTPS 部署方案。

前置条件

开始前需要满足以下条件:

  • 已安装 Docker 与 Docker Compose;
  • 对 Docker 网络(network)与标签(labels)有基本了解;
  • Traefik 已通过 Traefik Docker 部署指南完成基础部署(本文会给出完整的自包含 Compose 文件,也可独立运行)。

暴露你的第一个 HTTP 服务

Traefik 仓库配套提供了一个traefik/whoami镜像,它会把收到的请求头、IP、来源地址原样回显,是验证反向代理路由结果最直观的工具。下面用它演示一次完整的基础路由。

编写 docker-compose.yml

创建docker-compose.yml文件,定义 Traefik 与 whoami 两个服务:

services: traefik: image: "traefik:v3.4" container_name: "traefik" restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" - "--entryPoints.web.address=:80" ports: - "80:80" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" whoami: image: "traefik/whoami" restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" - "traefik.http.routers.whoami.entrypoints=web" networks: proxy: name: proxy

各关键配置项的含义如下:

配置项作用
--providers.docker=true启用 Docker provider,让 Traefik 通过 Docker API 发现容器
--providers.docker.exposedbydefault=false默认不暴露任何容器,只有带traefik.enable=true标签的容器才会生成路由
--providers.docker.network=proxy指定 Traefik 使用哪个网络中的容器 IP 来访问后端(见下文源码分析)
--entryPoints.web.address=:80定义名为web的 HTTP 入口,监听 80 端口
/var/run/docker.sock只读挂载提供 Docker API 访问通道(:ro保证只读)
traefik.http.routers.whoami.rule路由匹配规则:Host(\whoami.docker.localhost`)` 表示 Host 为该域名时命中
traefik.http.routers.whoami.entrypoints=web该路由绑定到web入口

保存文件后启动服务:

docker compose up -d

验证路由生效

服务此时应当可以通过 http://whoami.docker.localhost/ 访问。由于该域名未必在本地解析,可以手动指定 Host 头测试:

curl -H "Host: whoami.docker.localhost" http://localhost/

预期输出类似:

Hostname: whoami IP: 127.0.0.1 IP: ::1 IP: 172.18.0.3 IP: fe80::215:5dff:fe00:c9e RemoteAddr: 172.18.0.2:55108 GET / HTTP/1.1 Host: whoami.docker.localhost User-Agent: curl/7.68.0 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 172.18.0.1 X-Forwarded-Host: whoami.docker.localhost X-Forwarded-Port: 80 X-Forwarded-Proto: http X-Forwarded-Server: 5789f594e7d5 X-Real-Ip: 172.18.0.1

响应中出现的X-Forwarded-HostX-Forwarded-ProtoX-Real-Ip等请求头说明请求确实经过了 Traefik 的反向代理层——它向 whoami 转发了请求并附加了标准的转发头。

源码级原理:Docker provider 如何把标签变成路由

上面的效果在 Traefik 源码中由 Docker provider 完成,核心实现位于 pkg/provider/docker/pdocker.go:

  1. 首次全量同步:provider 启动后调用listContainers列出全部容器,经builder.build生成动态配置,推送到configurationChan通道(见 pdocker.go#L82-L92)。
  2. 事件驱动增量更新:当watch开启(默认开启)时,Traefik 订阅容器事件流,收到startdiehealth_status前缀的事件时重新构建配置(见 pdocker.go#L94-L136)。这也是为什么新起的 whoami 容器无需重启 Traefik 就能被自动发现。
  3. 容器过滤:pkg/provider/docker/config.go 的keepContainer实现了本文exposedbydefault=false的行为——若容器没有traefik.enable=true标签,ExtraConf.Enablefalse,容器直接被过滤(见 config.go#L197-L234)。traefik.enable的默认值即 provider 的ExposedByDefault配置(默认true,见 shared_labels.go#L42-L63)。同一函数还表明:非 running 状态或 healthcheck 不健康的容器会被过滤,其 service 保留空负载列表(可用allowEmptyServices调整)。
  4. 后端地址解析:Traefik 用--providers.docker.network=proxy指定的网络(proxy)来取容器 IP——getIPAddress优先从该网络中查找network.Addr,找不到会降级到第一个可用网络并打警告日志(见 config.go#L359-L425)。这就是为什么 whoami 必须和 traefik 容器接入同一个proxy网络。
  5. 端口探测:若没有用traefik.http.services.<name>.loadbalancer.server.port标签指定端口,Traefik 取容器暴露的最低端口(见 shared.go#L189-L207);服务名则默认取自 Compose 注入的com.docker.compose.service标签,格式为服务名_项目名(见 shared.go#L209-L217)。

关于 Docker provider 的更多安装配置选项(如endpointconstraintsuseBindPortIP),可查阅 Docker provider 参考文档;可使用的完整标签清单见 Docker 路由标签参考。

添加路由规则:基于路径分流

接下来按 URL 路径将流量导向不同服务——这在 API 版本化、前后端分离、微服务分组中非常实用。在docker-compose.yml中追加一个whoami-api服务:

# ... # New service whoami-api: image: "traefik/whoami" networks: - proxy container_name: "whoami-api" environment: - WHOAMI_NAME=API Service labels: - "traefik.enable=true" # Path-based routing - "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)" - "traefik.http.routers.whoami-api.entrypoints=web"

两个路由同时命中whoami.docker.localhost这个 Host,为什么/api请求会走whoami-api?关键在于Traefik 的路由优先级机制:默认情况下优先级等于规则字符串的长度,更长的规则更具体、优先级更高(priority显式设置为 0 时才回到按长度排序)。本文的whoami-api规则(Host(...) && PathPrefix(/api))比whoami规则长,因此/api前缀的请求优先命中whoami-api,其余路径落到whoami。更完整的匹配器(Path/PathPrefix/PathRegexpHost/HostRegexpQueryHeaderMethod等)与优先级计算细节,参见 路由规则与优先级参考。

应用变更:

docker compose up -d

测试路径路由

验证不同路径是否落到不同服务:

# Root path should go to the main whoami service curl -H "Host: whoami.docker.localhost" http://localhost/ # /api path should go to the whoami-api service curl -H "Host: whoami.docker.localhost" http://localhost/api

/api的请求,whoami 会在环境变量部分回显WHOAMI_NAME=API Service,证明路径分流工作正常。

启用 TLS:自签证书 + File provider 动态配置

下面为服务启用 HTTPS。本地开发环境先使用自签证书;生产环境则应换成可信 CA 签发的证书(例如 Let's Encrypt,见 进阶指南)。

生成自签证书

mkdir -p certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout certs/local.key -out certs/local.crt \ -subj "/CN=*.docker.localhost"

*.docker.localhost的通配符 CN 可以覆盖whoami.docker.localhostdashboard.docker.localhost等子域(注意通配只匹配一层子域)。

然后创建动态配置目录,写入 TLS 证书配置:

mkdir -p dynamic cat > dynamic/tls.yml << EOF tls: certificates: - certFile: /certs/local.crt keyFile: /certs/local.key EOF

这里certFile/keyFile指向的是容器内路径/certs/...),与下面的 volume 挂载目标一致。

更新 docker-compose.yml 启用 HTTPS

services: traefik: image: "traefik:v3.4" container_name: "traefik" restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy command: - "--api.insecure=false" - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=proxy" - "--providers.file.directory=/etc/traefik/dynamic" - "--entryPoints.web.address=:80" - "--entryPoints.websecure.address=:443" - "--entryPoints.websecure.http.tls=true" ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" # Add the following volumes - "./certs:/certs:ro" - "./dynamic:/etc/traefik/dynamic:ro" labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`dashboard.docker.localhost`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=api@internal" # Add the following label - "traefik.http.routers.dashboard.tls=true" whoami: image: "traefik/whoami" restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)" - "traefik.http.routers.whoami.entrypoints=websecure" # Add the following label - "traefik.http.routers.whoami.tls=true" whoami-api: image: "traefik/whoami" container_name: "whoami-api" restart: unless-stopped networks: - proxy environment: - WHOAMI_NAME=API Service labels: - "traefik.enable=true" - "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)" - "traefik.http.routers.whoami-api.entrypoints=websecure" # Add the following label - "traefik.http.routers.whoami-api.tls=true" networks: proxy: name: proxy

与 HTTP 版本相比,关键变化有:

  1. 新增websecure入口--entryPoints.websecure.address=:443,并通过--entryPoints.websecure.http.tls=true强制该入口所有 HTTP 流量走 TLS;
  2. File provider 加载动态 TLS 配置--providers.file.directory=/etc/traefik/dynamic对应挂载的./dynamic目录,dynamic/tls.yml中的证书被注册进 TLS store;
  3. 各路由迁移到websecure入口并加tls=truetraefik.http.routers.<name>.tls=true是路由级开关,声明该路由需要 TLS 终止,Traefik 会按 SNI 从 TLS store 中匹配证书;
  4. Dashboard 自路由:Traefik 容器自身也打了traefik.enable=true标签,通过service=api@internal把仪表盘挂在dashboard.docker.localhost上;配合--api.insecure=false,仪表盘不会裸露在 8080 管理端口,只能通过这条受 TLS 保护的 HTTPS 路由访问。

应用变更:

docker compose up -d

现在浏览器访问 https://whoami.docker.localhost/ 即可打开服务,自签证书会触发安全警告,接受后即可正常访问。

小结与进阶方向

本文完整走通了 Traefik + Docker 的三条基本能力链:标签驱动的容器发现(Docker provider 事件监听与traefik.enable过滤)、规则路由Host+PathPrefix组合与基于规则长度的优先级仲裁)、TLS 终止websecure.http.tls=true入口级强制 + 路由级tls=true+ File provider 证书配置)。三者叠加后,一个 Docker Compose 文件即可承载多域名、多路径、加密的反向代理。

掌握了这些基础之后,可以继续探索 进阶指南:

  • 使用 middlewares 实现安全响应头与访问控制;
  • 使用 Let's Encrypt(ACME)自动签发与续期证书;
  • 为有状态应用配置 sticky sessions;
  • 搭建基于认证结果的多层路由。

【免费下载链接】traefikThe Cloud Native Application Proxy项目地址: https://gitcode.com/GitHub_Trending/tr/traefik

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询