Traefik学习
Traefik学习
背景
- 因为之前购入了NUC11,在查询Linux服务器能够做什么有意思的事情时,偶然在这篇文章中看到了Traefik这个老熟人,之前在学校项目中也曾计划使用,但是奈何时间不太够,没有进一步接触,现在则重新开始学习这个云原生时代的反向代理工具
- 本文不打算也不可能完整的介绍Traefik,推荐参考Traefik的官方文档,写的真的很详细,本文如果详细介绍的话,也不过是官方文档的翻译罢了,这里仅大概介绍下自己的理解,以及自己的实际使用案例,慢慢探索!
Traefik与Nginx
-
Traefik作为一款反向代理/网关工具,不得不与其老大哥Nginx比一比,相比于Nginx,Traefik的特点如下:
-
无须重启即可更新配置,即可以做所谓的动态配置,也就是热加载
- Nginx中如果需要更新配置,则首先要更新
.conf
格式的配置文件,随后使用nginx -s reload
执行配置的更新 - Traefik将服务的代理配置集中在服务自身的声明式配置文件中,而不用进行额外的集中式的配置的更新操作
- Nginx中如果需要更新配置,则首先要更新
-
针对其支持的一众服务(在Traefik中,服务提供方被称为
Provider
),可以实现自动的服务发现与负载均衡-
与
Docker
完美集成,基于容器label
属性的的配置实现自动的服务发现与负载均衡,这里实际上就是把Docker作为一种Provider
-
其余的常用的
Provider
有Kubernetes
、Rancher
等等,所以说Traefik是”云原生“时代的反向代理工具
-
-
-
流程清晰,作为一个反向代理/网关产品,Traefik抽象了
EntryPoints
、Routers
、Services
、Providers
等概念,这使得整个代理流程更加清晰,相比Nginx的传统配置更加容易理解 -
支持很漂亮的Dashboard,同时Dashboard对于上述的一些列抽象概念也有明晰的划分
-
具有良好的可观测性,提供了对日志、Metrics、Tracing的支持
-
支持一系列Middleware,可以以中间件的方式提供多种开箱即用的代理功能,比如文件压缩、登录验证、HTTP重定向到HTTPS等
基本概念
EntryPoint
-
定义网关的入口,最常用的就是定义两个端口提供服务,即80与443,traefik通过这两个端口监听外界的请求
# 定义网关入口 [entryPoints] [entryPoints.http] address = ":80" [entryPoints.https] address = ":443"
-
除了定义端口,还可以定义端口监听的协议(TCP/UDP)
Router
-
路由组件,将请求路由到指定的Service,在路由组件中可以使用各种中间件处理请求
[http.routers.halo-redirect-https] rule = "Host(`blog.demoli.xyz`)" entryPoints = ["http"] service = "noop" middlewares = ["https-redirect"] priority = 100 [http.routers.halo] rule = "Host(`blog.demoli.xyz`)" entrypoints = ["https"] service = "halo" [http.routers.halo.tls]
- 可以使用rule定义路由规则,类似Nginx中的location
- tls属性执行该路由使用TLS加密,即支持HTTPS协议
-
同样的可以设置支持TCP或UDP的路由
Service
-
可以用来配置声明代理网关背后真正工作的服务
[http.services] [http.services.halo.loadBalancer] [[http.services.halo.loadBalancer.servers]] url = "http://halo:8090"
-
支持一系列负载均衡的配置
-
同样支持TCP/UDP服务的配置
Provider
-
服务的提供方,也可以理解为是动态配置的实现方,支持Docker、Kubernetes、Rancher、Marathon、File等
-
对于最常用的Docker来说,支持使用Docker Label来声明动态配置
version: '3.1' services: halo: image: halohub/halo container_name: halo restart: unless-stopped volumes: - /root/blog/halo:/root/.halo labels: - traefik.http.routers.halo.rule=Host(`blog.demoli.xyz`) - traefik.http.routers.halo.tls=true - traefik.http.routers.halo.entrypoints=https - traefik.http.services.halo.loadbalancer.server.port=8090 - traefik.http.routers.halo-redirect-https.rule=Host(`blog.demoli.xyz`) - traefik.http.routers.halo-redirect-https.entrypoints=http - traefik.http.routers.halo-redirect-https.service=noop@file - traefik.http.routers.halo-redirect-https.middlewares=https-redirect@file - traefik.http.routers.halo-redirect-https.priority=100 networks: default: external: name: traefik
Middleware
- 作用与Routers与Services之间,可在请求到达Services之前或者是响应从Services发出但是到达Client之前对请求或响应进行处理,实际上是一些常用的Web能力的封装,常用的有:
- BasicAuth 提供Basic Auth身份验证
- Buffering,提供请求缓存,过滤体积过大的请求
- Compress,使用gzip压缩响应,提升响应速度
- RateLimit,提供限流
- IPWhiteList,IP白名单设置
- Retry,如果后端服务没有成功响应,则重试多次
配置文件
- Traefik提供了两种类型的配置方式
- 静态配置
- 动态配置
静态配置
- 静态配置,或者说启动配置,一般用来设置Providers与Entrypoints,因为一般情况下这两者在整个系统中是不会发生改变的,可以使用
yaml
或者toml
两种格式的配置文件提供静态配置- 常用的配置可以参考Traefik提供的配置文件模板Traefik.sample.toml
- 还可以使用命令行参数和环境变量的形式提供静态配置
- 关于静态配置的一个关键的认识就是,如果不对配置设定值,或者没有显式设置某配置,则该配置使用其默认值,对于一些子配置同样有效,比如使用命令行参数的情况下,
--providers.docker
表示开启使用Docker作为Provider的功能,但是实际上并没有为改参数设置值,等价于--providers.docker=true
,即便是指定--providers.docker.endpoint
这个子配置,也会默认开启Docker作为Provider的功能。其他形式下的静态配置类比即可
动态配置
- 动态配置一般用来设置其余的配置,可以实现热更新,动态配置的提供源就是一众Provider
案例
- 以Halo博客网站的搭建为案例介绍Traefik配置实操,关于Halo博客的部署参考使用Docker Compose &Halo 搭建博客
Traefik的部署
-
使用Docker Compose部署Traefik,首先创建Traefik的配置环境,文件系统结构如下所示
- traefik
- config
- 存放动态配置文件
- ssl
- 存放HTTPS证书
- traefik.toml --静态配置文件
- traefik.yaml --Docker Compose配置文件
- config
- traefik
-
traefik.toml静态配置如下:
[global] checkNewVersion = false sendAnonymousUsage = false [log] level = "WARN" format = "common" # dashboard与API设置 [api] dashboard = true insecure = false # ping设置 [ping] # accessLog设置 [accessLog] # 配置provider [providers] [providers.docker] endpoint = "unix:///var/run/docker.sock" network = "traefik" [providers.file] watch = true directory = "/etc/traefik/config" debugLogGeneratedTemplate = true # 定义网关入口 [entryPoints] [entryPoints.http] address = ":80" [entryPoints.https] address = ":443" # 定义metrics [metrics] [metrics.prometheus] addEntryPointsLabels = true addRoutersLabels = true addServicesLabels = true
- 配置了Dashboard功能与API服务
- 配置了Docker与File两个Provider,其中File中指定了
/etc/traefik/config
目录下的配置文件的变动会被监听以实现动态配置与配置的热加载 - 定义了http与https两个EntryPoint
- 定义了Prometheus存储的Metrics,可结合Grafana做Metrics展示,metrics默认在
${TraefikIP}:8080/metrics
下提供
-
config目录下的tls的配置文件如下:
[tls] [tls.options] [tls.options.default] minVersion = "VersionTLS12" maxVersion = "VersionTLS12" [tls.options.test-tls13] minVersion = "VersionTLS13" cipherSuites = [ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ] # 配置两个证书 [[tls.certificates]] certFile = "/data/ssl/blog.demoli.xyz.pem" keyFile = "/data/ssl/blog.demoli.xyz.key" [[tls.certificates]] certFile = "/data/ssl/dashboard.demoli.xyz.pem" keyFile = "/data/ssl/dashboard.demoli.xyz.key"
- Traefik 可以定制每个请求响应使用的 TLS 版本,还可以定制加密算法、以及独立为某个/某些域名单独进行配置
- ssl文件夹下的证书可以根据证书文件的命名中的domain与对应的路由进行自动匹配
-
config目录下用于配置HTTP到HTTPS跳转的配置文件
default.toml
如下:[http.middlewares.https-redirect.redirectScheme] scheme = "https" [http.middlewares.content-compress.compress] # tricks # https://github.com/containous/traefik/issues/4863#issuecomment-491093096 [http.services] [http.services.noop.LoadBalancer] [[http.services.noop.LoadBalancer.servers]] url = "" # or url = "localhost" [http.routers] [http.routers.https-redirect] entryPoints = ["http"] rule = "HostRegexp(`{any:.*}`)" middlewares = ["https-redirect"] service = "noop"
- 使用官方提供的
redirectScheme
中间件定义https-redriect
中间件 - 配置了
noop
这个Service,后续需要设置此Service做为跳转路由的后端服务 - 定义了名为
https-redirect
的Router,使用正则匹配匹配所有域名都实现这种跳转 - 将调准配置维护到一个单独的配置文件中,相当于定义了几个公共方法,好处是可以为后续使用 Traefik 的每一个服务单独配置是否进行 HTTP->HTTPS 跳转
- 使用官方提供的
-
config目录下的Dashboard/API配置文件
dashboard.demoli.xyz.toml
如下:[http.middlewares.dash-compress.compress] [http.middlewares.dash-auth.basicAuth] users = [ "${username}:${password}" ] [http.routers.dashboard-redirect-https] rule = "Host(`dashboard.demoli.xyz`)" entryPoints = ["http"] service = "noop" middlewares = ["https-redirect"] priority = 100 [http.routers.dashboard] rule = "Host(`dashboard.demoli.xyz`)" entrypoints = ["https"] service = "dashboard@internal" middlewares = ["dash-auth", "dash-compress"] [http.routers.dashboard.tls] [http.routers.api] rule = "Host(`dashboard.demoli.xyz`) && PathPrefix(`/api`)" entrypoints = ["https"] service = "api@internal" middlewares = ["dash-auth", "dash-compress"] [http.routers.api.tls] [http.routers.ping] rule = "Host(`dashboard.demoli.xyz`) && PathPrefix(`/ping`)" entrypoints = ["https"] service = "ping@internal" middlewares = ["dash-auth", "dash-compress"] [http.routers.ping.tls]
- 定义了
dash-auth
与dash-compress
两个middleware(在文件开头定义),前者用来提供BasicAuth验证,后者用来提供gzip文件压缩dash-auth
使用了官方提供的Basic Auth
中间件- users属性的值定义
用户名:密码
,其中密码部分使用htpasswd
生成,也可以直接使用在线服务生成 - Traefik也同时提供了Digest Auth中间件,二者的区别可以参考What is the difference between Digest and Basic Authentication?
- users属性的值定义
dash-compress
使用了官方提供的Compress
中间件
- 使用
https-redirect
中间件添加了dashboard-redirect-https
的路由,用来实现HTTP访问自动重定向到HTTPS访问,因为是重定向,其后边的服务配置的是noop
,即是空服务(在default.toml
中配置)https-redirect
中间件是在config/default.toml
中自定义的
- 定义了
dashboard@internal
、api@internal
、ping@internal
三种服务的路由,其中API用来提供API服务,ping用来支持健康检查,同时设置了这三种服务对HTTPS的支持- 三者同时使用了
dash-auth
与dash-compress
两个middleware(在文件开头定义)
- 三者同时使用了
- Host部分配置的访问域名可以自行更改,注意在自己的DNS提供商中添加对应的解析即可
- 定义了
-
traefik.yaml Docker Compose配置文件如下:
version: '3' services: reverse-proxy: image: traefik restart: always ports: - "80:80" - "443:443" networks: - traefik volumes: - ./traefik.toml:/etc/traefik/traefik.toml - /var/run/docker.sock:/var/run/docker.sock - ./ssl/:/data/ssl/:ro - ./config/:/etc/traefik/config/:ro container_name: traefik # 网关健康检查 healthcheck: test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"] interval: 3s timeout: 5s # 创建外部网络 docker network create traefik networks: traefik: external: true
-
首先执行
docker network create traefik
创建外部网络,再执行docker-compose -f traefik.yaml up -d
开启服务 -
Halo博客的yaml配置文件
blog.yaml
:version: '3.1' services: halo: image: halohub/halo container_name: halo restart: unless-stopped volumes: - /root/blog/halo:/root/.halo labels: - traefik.http.routers.halo.rule=Host(`blog.demoli.xyz`) - traefik.http.routers.halo.tls=true - traefik.http.routers.halo.entrypoints=https - traefik.http.services.halo.loadbalancer.server.port=8090 - traefik.http.routers.halo-redirect-https.rule=Host(`blog.demoli.xyz`) - traefik.http.routers.halo-redirect-https.entrypoints=http - traefik.http.routers.halo-redirect-https.service=noop@file - traefik.http.routers.halo-redirect-https.middlewares=https-redirect@file - traefik.http.routers.halo-redirect-https.priority=100 - traefik.http.middlewares.halo-compress.compress=true - traefik.http.routers.halo.middlewares=halo-compress networks: default: external: name: traefik
-
traefik.http.routers.halo.rule
定义路由规则 -
traefik.http.routers.halo.tls
表示使用HTTPS -
traefik.http.services.halo.loadbalancer.server.port
指定Service的服务端口,注意此项设置是必须的,否则Traefik无法监视到Halo应用,参考Port Dection -
剩余的部分则是仿照Dashboard设置HTTP到HTTPS的重定向以及定义并使用了Compress插件,以减少响应的体积
-
除了使用Docker的label提供动态配置,还可以在
conf
文件夹中以文件的形式提供动态配置(即使用File类型的Provider),blog.demoli.xyz.toml
:[http.routers.halo-redirect-https] rule = "Host(`blog.demoli.xyz`)" entryPoints = ["http"] service = "noop" middlewares = ["https-redirect"] priority = 100 [http.routers.halo] rule = "Host(`blog.demoli.xyz`)" entrypoints = ["https"] service = "halo" [http.routers.halo.tls] [http.services] [http.services.halo.loadBalancer] [[http.services.halo.loadBalancer.servers]] url = "http://halo:8090"
-
-
执行
docker-compose -f blog.yaml up -d
启动博客应用,启动完毕后,Dashboard中可以看到博客应用已经被Traefik捕获到
补充
Traefik监控系统
Traefik代理Wireguard VPN
-
结合使用Wireguard搭建VPN服务食用更香,在这篇文章中,实现了内网主机部署Wireguard VPN,然后通过Frp做内网穿透。现在要做的就是将公网上的Frp服务以及并随的Wireguard UDP服务统一纳入Traefik的管理
-
首先为Frp服务以及伴随的UDP服务添加Entrypoint
[entryPoints] [entryPoints.http] address = ":80" [entryPoints.https] address = ":443" [entryPoints.tcp] address = ":6000" [entryPoints.udp] address = ":443/udp"
- 其中tcp用来实现FrpServer与Frp Client的沟通(即frps.ini配置文件中的
bind_port
),使用TCP类型的Entrypoint,这里实际上可以复用前边的http与https两个EntryPoint,这样公网服务器可以少开放一个端口,但是考虑到使用同一个Entrypoint的TCP router的优先级比HTTP router高,如果复用的话,那么博客的访问会收到影响,所以还是单独开放一个端口 - UDP类型的EntryPoint则复用了443端口,需要注意的是不要忘记在公网云服务器的防火墙设置中打开UDP类型的443端口,6000端口同理
- 其中tcp用来实现FrpServer与Frp Client的沟通(即frps.ini配置文件中的
-
Traefik的Docker Compose文件添加两个EntryPoint的端口映射
version: '3' services: reverse-proxy: image: traefik restart: always ports: - "80:80" - "443:443" - "443:443/udp" - "6000:6000" networks: - traefik volumes: - ./traefik.toml:/etc/traefik/traefik.toml - /var/run/docker.sock:/var/run/docker.sock - ./ssl/:/data/ssl/:ro - ./config/:/etc/traefik/config/:ro container_name: traefik # 网关健康检查 healthcheck: test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"] interval: 3s timeout: 5s # 创建外部网卡 docker network create traefik networks: traefik: external: true
-
修改Frps的Docker Compose配置文件
version: '3' services: frps: image: snowdreamtech/frps container_name: frps restart: unless-stopped volumes: - ./frps.ini:/etc/frp/frps.ini # dashboard端口直接使用SSH端口映射,不使用网关处理 ports: - 6001:6001 labels: - traefik.tcp.routers.frps.rule=HostSNI(`*`) - traefik.tcp.routers.frps.entryPoints=tcp - traefik.tcp.services.frps.loadbalancer.server.port=6000 - traefik.udp.routers.frps.entryPoints=udp - traefik.udp.services.frps.loadbalancer.server.port=51820 networks: default: external: name: traefik
-
6001端口被设置为Frp Dashboard的端口,此端口使用端口映射映射到内网服务器,不对外开放,因此只做Docker的端口映射,而不做Traefik的管理
-
对TCP Routers与TCP Services的设置参考Configure TCP Routers
-
需要注意的是
traefik.tcp.routers.frps.rule
的设置之所以使用*
是因为:It is important to note that the Server Name Indication is an extension of the TLS protocol. Hence, only TLS routers will be able to specify a domain name with that rule. However, non-TLS routers will have to explicitly use that rule with
*
(every domain) to state that every non-TLS request will be handled by the router.
-
-
对UDP Routers与UDP Services的设置参考 Configure UDP Routers
traefik.udp.services.frps.loadbalancer.server.port
指定的端口正是内网的Wireguard 服务通过Frp内网穿透映射的端口
-
-
在Wireguard的客户端,对端节点需要设置为:
公网IP:443
-
经过上述的一番操作,实际上有利有弊,好处在于进一步的将对外访问服务收归Traefik的统一管理,弊端在于后续如果使用该Frp Server做其他的端口映射时,需要修改Frps的Docker Compose配置文件,甚至是Traefik的静态配置文件,应该会有更高的方法待进一步改进
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)