前言
之前,我在家庭数据中心部署的应用(包括博客在内),从网络架构上来说是一个简单的4级结构:Cloudflare Tunnel—>长亭雷池WAF社区版—>ZEVENET负载均衡社区版—>博客主站点(博客冗余站点)。其中,ZEVENET负载均衡的作用是监测博客主站点的健康状况,如果主站点down掉之后自动把请求转发在家庭数据中心中的博客冗余站点上,从而实现博客的高可用。
不过,由于ZEVENET社区版的版本貌似一直没更新,让我很不爽,所以本来有写一个关于ZEVENET教程的想法都迟迟未付诸实践,加上之前一段时间由于加强了WAF上的安全策略,且博客主站点的稳定性经受住了考验,所以就干脆把ZEVENET去掉了,感觉也蛮好。
不过,这种单点运行的结构始终让我心里不踏实,思来想去,觉得还是要加上负载均衡才稳妥,可是,万年版本不升级的ZEVENET社区版我是真的不想用,而且ZEVENET我也觉得不够轻量化,想找个更轻量化的解决方案,所以,不得不开始寻觅了。
ZEVENET其实应该算最符合我要求的负载均衡解决方案,它的web界面的配置思路以及配置的基本元素和F5、A10等专业设备是差不多的(可惜搞不到F5的BIGIP VE或者A10的vThunder的长期使用license,不然我哪需要费这些劲找替代品~~),虽然社区版提供的功能和监控内容太少,但是也勉强够用,只是打死不升级的社区版(估计根本就没瞧上这一块,重心还是在收费版)实在让人蛋痛,其在docker hub上的镜像已经6年没更新了:
这不是我这种动不动就想升个级的升级狂人能接受的,所以最后只能忍痛放弃了。
不过到底选哪种呢?其实,在专业的负载均衡设备大行其道之前,linux系统上最出名的负载均衡软件是LVS(现在不少公司的生产环境还在用),功能上来说完全足够我用了;而Nginx加上stream模块也可以做7层负载均衡(也是现在很多生产环境在使用的,性能也非常强),可是这2个最常用的软件解决方案默认都有一个最大的问题:没有方便的web UI(我是用惯了F5的人,没有方便的web UI实在是无法忍受~)。
LVS默认倒是提供了一个web界面,可惜只能看看一些基本的参数,而网上以前倒是有很多针对LVS的开源web UI的项目,可惜现在绝大部分都消失了(估计是因为LVS用的人少的原因),剩下倒是还有,比如roxy-wi,但是其官方貌似没提供docker的部署方式(github主页:https://github.com/roxy-wi/roxy-wi),我实在不想为个UI还去搞源码部署,docker hub上倒是有一些非官方的,但是基本也是一年以上没更新了,想想只能放弃了。
Nginx倒是有不少web UI的项目支持,可惜都是针对Nginx整体功能的,并未专门针对负载均衡功能进行优化,而我恰恰只需要负载均衡功能,这就比较蛋痛了,总有大炮打蚊子,而且还打不到的感觉。当然,Nginx做七层负载均衡最大的优势是性能强,可是我的博客访问流量基本只是cloudflare发来的回源请求(正常访问都是访问的cloudflare上缓存的内容,真正需要回源的是少数),对性能可以说完全没要求~,所以最后也放弃了。
这时候,发现了一个新的选择:Traefik。
什么是Traefik?
Traefik介绍
Traefik 是一款现代化的反向代理和负载均衡器,专为微服务和容器化环境而设计。它能够动态管理后端服务路由,是自动化云原生环境的理想选择。
Traefik的主要特点如下:
- 动态配置
• Traefik 支持多种配置方式,包括文件、API、Docker 标签和 Kubernetes CRD,能实时响应服务拓扑的变化。
- 自动服务发现
• Traefik 可以自动发现通过 Docker、Kubernetes 等平台注册的服务,并自动更新路由规则,无需手动干预。
- 内置的 HTTPS 支持
• 支持自动申请和管理 Let’s Encrypt SSL/TLS 证书,提供安全的 HTTPS 通信。
- 多协议支持
• 除了 HTTP 和 HTTPS 外,Traefik 还支持 TCP、UDP、WebSocket 等多种协议。
- 中间件支持
• 提供灵活的中间件功能,可以对请求进行认证、重写、速率限制等操作。
- 可视化界面
• 提供直观的仪表盘用于监控服务和路由状态。
- 高性能
• Traefik 采用 Go 语言开发,性能出色,并支持高并发的请求处理。
Traefik、Nginx、HAProxy的竞争分析
Traefik、Nginx和HAProxy在负载均衡功能的比较:
特性 | Traefik | Nginx | HAProxy |
---|---|---|---|
架构与部署 | |||
定位 | 专注于云原生的反向代理和负载均衡 | 通用的反向代理服务器,支持负载均衡 | 高性能负载均衡器,稳定性极高 |
动态配置 | 原生支持动态配置(通过API或文件更新) | 需要通过reload 重新加载配置文件 |
使用Runtime API部分支持动态配置 |
整合能力 | 内置对Kubernetes、Docker等的服务发现支持 | 可通过插件或手动配置实现部分整合能力 | 无原生支持,需要手动配置或依赖其他工具 |
性能 | |||
吞吐量 | 略低于Nginx和HAProxy,适用于中小型流量 | 性能较高,适合中等负载 | 性能最优,适合高并发和低延迟需求 |
并发处理能力 | 中等,取决于后端服务数量和复杂性 | 高效处理大量并发请求 | 极高,专为高并发设计 |
资源占用 | 较高(因Go语言的运行时开销) | 资源占用适中,配置优化后更低 | 资源占用极低,特别适合资源受限环境 |
功能特性 | |||
负载均衡算法 | 支持多种算法(轮询、随机等),较灵活 | 提供轮询、最少连接等多种算法 | 提供更高级的负载均衡策略和算法支持 |
SSL支持 | 自动配置并更新(Let’s Encrypt 集成) | 手动配置证书,支持强大 | 手动配置证书,灵活性强 |
健康检查 | 内置支持,配置简单 | 手动设置,通过插件扩展功能 | 强大的健康检查功能,适合复杂场景 |
连接限速和安全性 | 提供基础限流功能 | 支持限速和复杂的安全配置 | 提供精细化的限速和安全控制 |
Web UI 支持 | |||
是否支持 | 原生支持,带有直观的仪表盘 | 不提供,需要借助第三方工具或插件 | 不提供,需要借助外部工具 |
Web UI 功能 | 可实时查看路由状态、负载均衡状态等 | 无原生支持,手动搭建成本较高 | 无原生支持,手动搭建成本较高 |
从上面的比较可以看出,Traefik的功能更强,且内置支持Web UI,虽然吞吐量上略低于Nginx和HAProxy,但是我根本不在意吞吐量~,所以综合比较下来,的确是Traefik来做负载均衡更适合我。
Traefik适用的场景
Traefik 的适用场景涵盖传统和现代化的应用部署需求,无论是容器化的微服务架构,还是多样化的企业应用场景,Traefik 都是一个高效、灵活且功能丰富的解决方案:
应用场景 | 适用场景描述 | 特点 | 示例 |
---|---|---|---|
容器化环境 | 使用 Docker Compose、Docker Swarm、Kubernetes 等容器编排工具的环境 | – 自动服务发现:基于 Docker 标签或 Kubernetes CRD 自动配置路由 – 动态负载均衡:随容器的启动、停止或扩缩容实时调整流量 – 内置 HTTPS 支持:自动申请和管理 TLS/SSL 证书 |
– 在 Docker Swarm 中动态路由和均衡服务流量 – 在 Kubernetes 中作为 Ingress Controller 管理流量 |
非容器化环境 | 传统的虚拟机或物理服务器托管的应用 | – 静态配置文件或 REST API 设置路由 – 提供负载均衡、健康检查和自动重试功能 – 支持多种协议(HTTP、HTTPS、TCP、UDP) |
– 为多个独立运行的应用实例提供负载均衡 – 为非容器化的企业应用提供动态路由管理 |
容器编排环境(Kubernetes) | 微服务架构中使用 Kubernetes 的应用 | – 作为 Kubernetes Ingress Controller,支持动态配置和自动发现服务 – 提供流量分发、会话保持、权重分配等功能 |
– 在 Kubernetes 集群中动态分配服务流量 – 使用金丝雀发布和蓝绿部署提升系统稳定性 |
边缘计算与 IoT 环境 | IoT 网关或边缘节点的数据流量分发 | – 支持多协议(TCP、UDP、HTTP/HTTPS)处理不同设备和节点的流量 – 中间件功能可实现速率限制和认证 |
– 边缘计算平台上的实时数据流路由和负载分担 – IoT 设备间通信的流量优化 |
混合云与多云环境 | 部署在多个云服务平台或跨云环境的服务 | – 多入口点支持,轻松整合不同云平台的流量 – 提供统一的流量管理和跨区域负载均衡 |
– 混合云中协调 AWS 和 Azure 的服务流量 – 不同区域间的流量分发和访问控制 |
企业内网环境 | 企业内部应用的统一管理 | – 提供反向代理和负载均衡功能,支持路径或子域名路由 – 配合中间件实现身份验证、流量限制等功能 |
– 为多个内部应用(如 CRM、ERP 系统)提供单一入口 – 提供内网服务的高可用和安全访问 |
跨地域分布式服务 | 面向全球用户的分布式应用 | – 支持基于权重的流量分配和健康检查 – 可结合 GeoDNS,实现地理位置感知的流量路由 |
– 跨多个数据中心分发流量 – 优化全球用户访问时的延迟 |
开发与测试环境 | 开发人员需要快速部署和调试服务 | – 快速设置 HTTPS 支持的本地测试环境 – 动态调整路由,模拟多版本发布策略(如蓝绿部署) |
– 为开发团队搭建快速调试环境 – 测试负载均衡策略和路由规则 |
从以上表格可以看出,在我的家庭数据中心内,部署的应用的负载均衡就适合第2种场景:非容器化环境。
注:我的博客主站点和冗余站点分别在2台物理机上(鸡蛋不能放在一个篮子里,不然冗余就没有意义了),如果都是以docker方式部署在在同一台物理机上,就适用于容器环境内部的负载均衡了。
Traefik实操
常见场景
1. Docker 场景
适用于目标是运行在 Docker 容器中的服务,通过 Docker 标签动态管理服务和路由规则。
• 优势:自动化程度高,与容器编排(如 Docker Compose、Swarm)无缝集成。
• 场景:微服务架构、容器化部署。
2. 非 Docker 场景
适用于内网物理机或虚拟机等场景,通过手动配置入口点和服务负载均衡,动态配置可以来源于多种提供者,如文件、API、或 Consul 等服务发现工具。
• 优势:支持多种服务发现方式,适合传统架构。
• 场景:内网应用负载均衡、虚拟机集群流量分发。
3. 文件动态配置场景(非 Docker场景的一种具体实现)
完全基于文件实现静态和动态配置的分离。动态配置文件定义路由规则和服务负载均衡,无需其他外部服务。
• 优势:配置简单,适合资源有限或测试环境。
• 场景:小型内网负载均衡、开发测试环境。
4. Kubernetes 场景
通过 Kubernetes 提供者集成,直接从 Ingress 资源中动态获取路由和服务配置。
• 优势:云原生场景的最佳实践,支持自动扩展和服务发现。
• 场景:基于 Kubernetes 的容器编排平台。
场景 | 配置来源 | 适用环境 | 动态性 |
---|---|---|---|
Docker 环境 | Docker 标签 | 容器化服务 | 高,实时发现更新 |
非 Docker 环境 | 多种来源(文件等) | 内网、物理机、虚拟机集群 | 中,依赖配置方式 |
文件动态配置 | 配置文件 | 小型内网、开发测试 | 中,修改需重载 |
Kubernetes 环境 | Kubernetes Ingress | 云原生、容器编排平台 | 高,动态发现更新 |
“文件动态配置”本质上只是”非 Docker 环境”的一种实现形式,本来是没有必要特别单独划分成一个场景的。之所以单独拿出来,是因为在实际使用中,文件动态配置 有一些独特的使用场景和特点,会让它显得“特殊”:
1. 文件动态配置的独立性
文件动态配置不依赖任何外部服务(如 Docker、Kubernetes 或 Consul),完全通过文件进行静态配置和动态配置的分离。
• 非 Docker 环境 中的其他形式可能需要额外的服务提供动态配置,比如 Consul、Etcd 等;
• 文件动态配置 只需手动管理配置文件,适合一些简单或资源受限的环境。
2. 文件动态配置的典型应用场景
文件动态配置经常用于:
• 开发或测试环境:快速搭建一个简单的负载均衡或路由系统,不需要额外的依赖。
• 小型生产环境:没有复杂的服务发现需求,仅需静态定义几个后端服务。
这些场景与需要服务发现的 非 Docker 环境(如动态扩展的虚拟机集群)有些不同。
3. 简化的部署方式
文件动态配置的实现对用户更友好:
• 只需两个文件(traefik.yml 和动态配置文件),修改后重载即可,无需复杂配置;
• 对于新手用户和资源有限的环境,易于理解和部署。
基于以上这3点理由,我将”文件动态配置”单独作为一个分类,但是其仍属于”非Docker场景”,本文后面的部署就是采用”文件动态配置”的方式。
静态配置文件:traefik.yml
Traefik官方推荐以docker方式进行部署,不论是”docker run”方式还是docker-compose方式都行,不过,不管以那种方式,都需要使用到一个名为”traefik.yml”的静态配置文件。
“traefik.yml”主要用于定义 Traefik 的全局设置和入口配置。静态配置在 Traefik 启动时加载,与动态配置(用于定义具体的路由和服务)不同,动态配置通常通过文件、Docker标签、Kubernetes 等方式加载。
以下是基于不同场景对 traefik.yml 文件内容的分类说明和详解:
1. Docker 环境
在 Docker 环境中,traefik.yml 文件主要配置 Traefik 的全局行为及与 Docker 的集成。示例文件如下:
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
api:
dashboard: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
log:
level: "INFO"
accessLog: {}
certificatesResolvers:
myresolver:
acme:
email: "[email protected]"
storage: "acme.json"
httpChallenge:
entryPoint: "web"
上述内容解释:
- entryPoints
定义 Traefik 的入口点(端口和协议)。
• web 用于 HTTP 流量,监听 80 端口。
• websecure 用于 HTTPS 流量,监听 443 端口。
- api
开启 Traefik 的 Web 管理面板(仪表盘)。通过 /dashboard 访问。
- providers.docker
配置 Traefik 作为 Docker 容器的服务发现工具。
• endpoint: 指定 Docker 的 API 地址,通常是 unix:///var/run/docker.sock。
• exposedByDefault: 设置为 false,意味着只有显式标记的容器才会暴露给 Traefik。
- log 和 accessLog
• log: 定义日志级别(INFO、DEBUG、ERROR)。
• accessLog: 启用访问日志,记录客户端请求。
- certificatesResolvers
配置自动获取 HTTPS 证书(Let’s Encrypt)。
• 使用 httpChallenge 验证,通过 web 入口点处理证书请求。
• 证书信息存储在 acme.json 文件中。
2. 非 Docker 环境(如内网应用负载均衡)
在此场景下,Traefik 的静态配置主要用于定义后端服务的负载均衡逻辑以及入口点。示例文件如下:
entryPoints:
web:
address: ":80"
providers:
file:
filename: "dynamic.yml"
log:
level: "DEBUG"
accessLog: {}
api:
dashboard: true
而对应的动态配置 dynamic.yml 文件可能如下:
http:
routers:
my-router:
rule: "Host(`example.com`)"
service: my-service
entryPoints:
- web
services:
my-service:
loadBalancer:
servers:
- url: "http://192.168.1.101:8080"
- url: "http://192.168.1.102:8080"
内容解释
- entryPoints
定义监听入口点,例如 :80 处理 HTTP 请求。
- providers.file
• 指定动态配置来源的文件路径,例如 dynamic.yml。
• 动态配置定义具体的路由规则和负载均衡后端。
- http.routers(动态配置)
定义路由规则:
• rule: 指定请求的匹配规则(如域名匹配)。
• entryPoints: 绑定到静态配置中的入口点。
- http.services(动态配置)
定义服务及其负载均衡策略:
• loadBalancer: 包含多个后端服务器的地址,Traefik 会自动分发流量。
3. 文件动态配置(非Docker环境的一种具体实现)
配置和非Docker环境的非常类似(因为本来就属于非Docker环境~),特别是在不依赖其他提供者时,可完全通过文件实现静态和动态配置分离。例如:
entryPoints:
web:
address: ":8080"
providers:
file:
directory: "/etc/traefik/dynamic/"
动态配置文件示例:
http:
routers:
static-router:
rule: "Path(`/static`)"
service: static-service
services:
static-service:
loadBalancer:
servers:
- url: "http://localhost:3000"
Traefik 默认会配置两个路由器(routers):
- api router:负责处理对 Traefik 的 API 接口的请求。通过这个路由器,用户可以访问 Traefik 的 API,进行监控和管理等操作。通常它的地址会是类似 http://
:8080/api 这样的格式。 -
dashboard router:负责处理对 Traefik Web Dashboard 的请求。Traefik 的 Web Dashboard 提供了一个图形化界面来监控和管理 Traefik 的状态和配置。默认情况下,Dashboard 地址通常是 http://
:8080/dashboard,但这个地址可以通过配置进行修改。
这两个router通常在 Traefik 启动时默认启用,并且可以通过配置文件或命令行选项进行调整。默认情况下,API 和 Dashboard 都绑定在 8080 端口,你可以根据需要修改它们的端口、访问方式(如开启TLS)等。
所以,假设在dynamic.yml中自行配置了1个router(如上),则router的总数就是3。
4. Kubernetes Ingress Controller
作为 Kubernetes 的 Ingress 控制器时,traefik.yml 文件需要配置为从 Kubernetes API 获取动态配置:
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
kubernetesIngress: {}
certificatesResolvers:
myresolver:
acme:
email: "[email protected]"
storage: "acme.json"
httpChallenge:
entryPoint: "web"
内容解释
- providers.kubernetesIngress
告诉 Traefik 从 Kubernetes 的 Ingress 资源中提取路由规则和服务配置。
- certificatesResolvers
同 Docker 环境,启用自动 HTTPS 证书获取。
Traefik部署
docker run方式
准备工作
假设我需要对内网的3个不同主机的80端口做负载均衡,这3个主机的IP地址分别为:192.168.0.1、192.168.0.2以及192.168.0.3,则操作步骤如下:
1、新建工作目录:
mkdir -p /docker/traefik
2、新建静态配置文件:
touch /docker/traefik/traefik.yml
将如下内容粘贴进去并保存:
entryPoints:
web:
address: ":80" # 为 HTTP 添加 entry point
websecure:
address: ":443" # 为 HTTPS 添加 entry point
traefik:
address: ":8080" # 显式绑定 Dashboard 到 8080 端口
providers:
file:
filename: "/etc/traefik/dynamic.yml" # 指定动态配置文件在traefik容器"内部"的路径
watch: true
log:
level: "INFO"
accessLog: {}
api:
dashboard: true
insecure: true # 启用不安全模式,仅用于测试环境,这条很重要,否则默认不能使用http的8080端口进行管理
certificatesResolvers:
myresolver:
acme: # 启用本地acme进行ssl证书的自动更新
email: "[email protected]" # 替换为你的邮箱
storage: "/etc/traefik/acme.json" # 指定容器内部acme配置文件
httpChallenge:
entryPoint: web # 使用 HTTP-01 验证
新建动态配置文件:
touch /docker/traefik/dynamic.yml
然后把如下内容粘贴进去并保存:
http:
routers:
blog-router:
rule: "Host(`your-domain.com`)"
entryPoints:
- web
service: blog-service
tls:
certResolver: myresolver
services:
blog-service:
loadBalancer:
servers:
- url: "http://192.168.0.1"
- url: "http://192.168.0.2"
- url: "http://192.168.0.3"
healthCheck:
path: "/healthcheck" # 对指定路径健康检查,这里假设是"/healthcheck"
interval: "10s" # 检查间隔
timeout: "5s" # 检查超时时间
passHostHeader: true
新建acme配置文件:
touch /docker/traefik/acme.json
chmod 600 /docker/traefik/acme.json
acme.json 文件在初次使用时只需要创建一个空白文件即可,Traefik 在运行时会自动将 ACME(Let’s Encrypt)的证书和相关数据存储到该文件中,也因此需要配置合适的写入权限。
如果不需要对https协议的端口进行负载,只需将traefik.yml和dynamic.yml中相关内容删除掉,比如:
traefik.yml
entryPoints:
web:
address: ":80" # 为 HTTP 添加 entry point
traefik:
address: ":8080" # 显式绑定 Dashboard 到 8080 端口
providers:
file:
filename: "/etc/traefik/dynamic.yml" # 指定动态配置文件在traefik容器"内部"的路径
watch: true #对动态配置文件进行实时监控,如果配置有改动,立即载入新配置
log:
level: "INFO"
accessLog: {}
api:
dashboard: true
insecure: true # 启用不安全模式,一般用于测试环境,这条配置很重要,否则默认不能使用http的8080端口进行管理
dynamic.yml
http:
routers:
blog-router:
rule: "Host(`your-domain.com`)"
entryPoints:
- web
service: blog-service
services:
blog-service:
loadBalancer:
servers:
- url: "http://192.168.0.1"
- url: "http://192.168.0.2"
- url: "http://192.168.0.3"
healthCheck:
path: "/healthcheck" # 对指定路径健康检查,这里假设是"/healthcheck"
interval: "10s" # 检查间隔
timeout: "5s" # 检查超时时间
passHostHeader: true
部署
docker run格式命令如下:
docker run -d --name traefik --restart=always --net=public-net \
-p 80:80 \
-p 443:443 \
-p 8080:8080 \
-v /docker/traefik/traefik.yml:/etc/traefik/traefik.yml \
-v /docker/traefik/dynamic.yml:/etc/traefik/dynamic.yml \
-v /docker/traefik/acme.json:/etc/traefik/acme.json \
traefik:v2.11
注1:如果不需要对https协议端口进行负载,删除-p 443:443 \
以及-v /docker/traefik/acme.json:/etc/traefik/acme.json \
这两行即可。
注2: --net=public-net
在”非docker场景”中并不是必须的,不过如果是”docker场景”(要对同一个宿主机上的某些docker做负载均衡时),就需要traefik和这些docker都位于同一个bridge之内。
docker-compose方式部署
其实就是将docker run格式的命令转成docker-compose.yml文件:
version: '3.8'
services:
traefik:
image: traefik:v2.11
container_name: traefik
restart: always
networks:
- public-net
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /docker/traefik/traefik.yml:/etc/traefik/traefik.yml
- /docker/traefik/dynamic.yml:/etc/traefik/dynamic.yml
- /docker/traefik/acme.json:/etc/traefik/acme.json
networks:
public-net:
external: true
说明:
- services: 定义服务 traefik。
-
networks: 指定使用外部网络 public-net,需要确保该网络已通过 docker network create public-net 创建(此处不是必须的)。
-
volumes: 将宿主机的文件挂载到容器中。
-
ports: 映射容器端口到宿主机。
将此内容保存为 docker-compose.yml 文件后,进入相同目录下,通过以下命令启动:
docker-compose up -d
进阶配置:基于优先级的配置思路
多优先级配置示范
上一节只是使用Traefik完成最基本、最简单的负载均衡配置,而Traefik还能实现更复杂的逻辑,比如服务基于”优先级”的方式实现热备,举例说明:对任意域名的访问,192.168.0.1:80的服务是最高优先级,192.168.0.2:80的服务是中等优先级,192.168.0.3:80的服务是最低优先级。只要192.168.0.1:80服务是正常的,就只把对任意域名的访问请求都发送到它上;如果192.168.0.1:80的服务down掉,就把请求发送到192.168.0.2:80的服务上;如果192.168.0.2:80的服务也down掉,再把请求发送到192.168.0.3:80的服务上,要实现这个功能,dynamic.yml的内容可以如下设置:
http:
routers:
blog-router:
rule: "HostRegexp(`{host:.+}`)" # 匹配所有域名
entryPoints:
- web
service: high-priority-service # 默认使用高优先级服务
middlewares:
- strip-prefix # 中间件示例(可按需调整)
services:
high-priority-service:
loadBalancer:
servers:
- url: "http://192.168.0.1" # 高优先级服务地址
healthCheck:
path: "/healthcheck" # 健康检查路径
interval: "10s" # 健康检查间隔
timeout: "5s" # 健康检查超时时间
passHostHeader: true # 传递原始 Host Header
medium-priority-service:
loadBalancer:
servers:
- url: "http://192.168.0.2" # 中等优先级服务地址
healthCheck:
path: "/healthcheck" # 健康检查路径
interval: "10s" # 健康检查间隔
timeout: "5s" # 健康检查超时时间
passHostHeader: true # 传递原始 Host Header
low-priority-service:
loadBalancer:
servers:
- url: "http://192.168.0.3" # 最低优先级服务地址
healthCheck:
path: "/healthcheck" # 健康检查路径
interval: "10s" # 健康检查间隔
timeout: "5s" # 健康检查超时时间
passHostHeader: true # 传递原始 Host Header
middlewares:
strip-prefix:
stripPrefix:
prefixes:
- "/api" # 示例:如果请求包含 "/api",会移除此前缀
配置解读
- 服务定义(services):
• high-priority:优先级最高,只使用 192.168.0.1:80。
• medium-priority:次优先级,只在高优先级不可用时启用。
• low-priority:最低优先级,仅在前两个都不可用时启用。
- 健康检查(healthCheck):
• 健康检查路径 /healthcheck,需要每个服务器提供。
• 如果健康检查失败,Traefik 会将服务标记为不可用。
- 路由(routers):
• blog-router 默认指向 high-priority 服务。
- 中间件(middlewares):
• retry-medium:尝试向 high-priority 发送流量,如果失败则切换到 medium-priority。
• retry-low:当 medium-priority 也不可用时,切换到 low-priority。
多个service对应不同优先级
Traefik使用高、中、低三种service的配置来对应不同的优先级,是为了在负载均衡和流量调度中实现更高效的控制,尤其是在高优先级服务故障时能够立即把访问请求转向较低优先级服务,从而达到”热备”的效果。
1. 明确的流量优先级控制
优先级控制的必要性:
• 在多服务环境中,可能存在一个主服务(高优先级服务),它负责处理最重要或最多的请求;同时,可能有一些备份服务(中、低优先级服务),它们在主服务不可用时作为冗余处理。
• 在这种情况下,简单地使用负载均衡的 weight 配置(例如,设置权重比例)并不能有效实现优先级控制,因为 weight 只是简单地按比例分配流量,而没有考虑服务的相对重要性和可用性。
• 例如,如果使用 weight,流量会按照权重分配,可能导致低优先级服务承担一部分流量,即使高优先级服务并未出现故障,进而影响性能或资源分配。
高、中、低优先级的使用:
• 高优先级服务被设置为默认的服务,表示它在正常情况下应承载大部分流量。
• 中、低优先级服务则是备用或故障恢复服务,只有在高优先级服务出现问题时,流量才会转移到这些服务。
• 这种做法通过简单的优先级控制和流量路由规则(如健康检查)确保了系统在不同情况下的稳定性和高可用性。
2. 健康检查与故障恢复的需求
健康检查机制:Traefik 内建的健康检查机制可以实时监控服务的可用性。如果某个服务无法通过健康检查,Traefik 会自动将流量转移到健康的服务。这时,优先级的配置显得尤为重要。
• 高优先级服务:优先处理正常请求,只有在它无法正常工作时,才会降级到中或低优先级服务。
• 中、低优先级服务:这些服务在高优先级服务出现故障或不可用时才会被启用。因此,只有在健康检查失败时,这些服务才会接收流量。
通过这种优先级策略,系统可以在出现服务故障时自动切换到备份服务,避免了依赖于 weight 来分配流量,从而降低了因权重不准确或比例分配不合适而导致的问题。
3. 简化配置与逻辑
减少配置复杂度:配置高、中、低优先级服务比通过 weight 来分配流量更简单。通过明确的优先级划分,管理者可以清楚地知道哪些服务是关键服务,哪些是备用服务,无需调整权重配置,只需依赖服务的健康状态来决定流量的转发。
故障恢复更加直观:在优先级配置中,流量转发的决策不依赖于权重,而是由服务的健康状态和优先级决定。这样可以更直接地实现流量调度,简化了运维人员的配置和决策。
4. 灵活的流量管理
通过明确的优先级配置,Traefik 可以根据服务的健康状态和重要性来动态调整流量的转发。与 weight 不同,优先级配置能确保服务之间的流量切换是基于实际可用性和业务需求,而不仅仅是静态的流量分配比例。
Traefik支持weight(权重)功能,不过,weight主要是控制不同服务负载流量的多少,和优先级的概念不同:
• weight无法明确优先级:在 Traefik 中,weight 主要用于控制流量的比例分配(例如:80% 流量到服务 A,20% 流量到服务 B)。但是它并没有为每个服务设置明确的优先级,而只是一个简单的流量分配比例。
• 避免流量误导:在一些场景下,使用 weight 可能会导致流量错误地分配到不应承担流量的服务,尤其是在系统出现故障或负载剧增时。而使用高、中、低优先级的配置可以确保只有在特定条件下,流量才会切换到低优先级服务。
• 控制和监控的灵活性:通过使用不同优先级的服务,系统在控制和监控上更加灵活。当流量从高优先级服务切换到低优先级服务时,可以通过日志或监控轻松识别,及时调整。weight 配置则可能使这种监控变得模糊,难以识别流量是否按照预期的优先级进行分配。
其实吧,主要原因是Traefik不直接支持传统负载均衡设备的”优先级”机制:对不同的服务设置不同的优先级数字,只有优先级数字相同的服务才进行负载均衡,否则,就只把请求发往高优先级数字的服务。如果支持这个功能,哪需要折腾这么多~。
serversTransports介绍
serversTransports 是 Traefik 配置中的一个关键参数,用于定义与上游服务器之间的通信参数,特别是在 HTTP 和 HTTPS 的传输设置方面。它允许你为 Traefik 的负载均衡器配置特定的网络传输选项,例如 TLS 配置、请求头设置、最大连接数等。通过这个配置,你可以优化 Traefik 与后端服务器之间的通信方式,提高性能、稳定性和安全性,示范配置如下:
http:
serversTransports:
my-transport:
lifeCycle:
requestAcceptGraceTimeout: 30s # 请求接受的优雅关闭超时
forwardProxy:
address: "http://proxy.example.com:3128" # 上游代理地址
responses:
headers:
customHeader: "X-Custom-Header-Value" # 自定义请求头
tls:
minVersion: VersionTLS13 # 最低 TLS 版本
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # 支持的加密套件
maxIdleConnsPerHost: 10 # 每个主机最大空闲连接数
idleTimeout: 5m # 空闲连接超时时间
disableHTTPKeepAlive: true # 禁用 HTTP Keep-Alive
maxConns: 50 # Traefik 与后端服务的最大连接数
示范配置中涉及的参数的介绍如下:**
- tls
用于设置 TLS 配置,指定与后端服务器通信时使用的最小 TLS 版本和加密套件。例如,可以通过此配置启用强加密算法来确保数据传输的安全性。
• minVersion: 最小 TLS 版本(如 VersionTLS13)。
• cipherSuites: 支持的加密套件列表。
- lifeCycle.requestAcceptGraceTimeout
设置请求接受的优雅关闭超时时间。在此时间段内,Traefik 会等待现有连接的请求完成后再关闭,确保在关闭连接之前,客户端的请求能正常处理。
- forwardProxy
如果需要通过上游代理访问后端服务,可以使用该参数指定代理服务器的地址。
- responses.headers
设置自定义响应头。在 Traefik 向上游服务器发送请求时,可以附加特定的请求头。
- maxIdleConnsPerHost
设置每个主机最大空闲连接数。空闲连接是指已经建立但未被使用的连接。这个参数有助于避免空闲连接占用过多的资源,优化系统性能。默认值是 2。
- maxConns
设置 Traefik 与后端服务之间的最大并发连接数,假设设置为 50,意味着 Traefik 与所有后端服务的连接总数不会超过 50。这个设置帮助限制系统的负载,避免在流量高峰时与后端服务建立过多的连接。
- idleTimeout
设置空闲连接的超时时间,即如果连接在指定时间内没有被使用,它将被关闭。这有助于释放不再需要的连接,防止连接池中堆积过多的空闲连接。默认值是 0,表示没有超时。
- disableHTTPKeepAlive
如果设置为 true,则关闭 HTTP Keep-Alive。HTTP Keep-Alive 允许客户端与服务器保持持久连接,不必在每次请求时重新建立连接。禁用 Keep-Alive 会导致每次请求都建立新的连接,但可以避免长时间占用连接池的情况。默认值是 false,表示启用 Keep-Alive。
比如,要实现连接复用(Connection Reuse)功能,只需要如下配置:
maxIdleConnsPerHost: 10 # 每个主机最大空闲连接数,根据实际环境设置
idleTimeout: 5m # 空闲连接超时时间,根据实际环境设置
disableHTTPKeepAlive: true # 禁用 HTTP Keep-Alive
maxConns: 50 # Traefik 与后端服务的最大连接数,根据实际环境设置
Traefik Web Dashboard
Treafik提供的Dashboard(通过8080端口访问)可以查看一些简单的内容,具体参看下面的图文介绍:
总的来说,Treafik默认提供的web dashboard太过于简单了(有点失望),看不到具体的访问数据(比如:流量、请求数、响应时间等),要查看这些具体的访问数据,官方推荐是采用Prometheus + Grafana这两种工具组合的方式:
Traefik Metrics(Prometheus)
Traefik 可以与 Prometheus 集成,通过 Prometheus 收集和展示负载均衡的详细数据,包括请求数、流量、响应时间等。
• 启用 Prometheus:你需要在 Traefik 配置中启用 Prometheus 导出器,通常通过配置文件或命令行参数来实现。
在 traefik.yml 或命令行启动时添加以下内容:
metrics:
prometheus:
entryPoint: "metrics" # 设置Prometheus的端点
buckets:
- 0.1
- 0.3
- 0.5
- 1
- 2.5
- 5
- 10
• 访问 Prometheus 数据:Traefik 会提供 Prometheus 格式的指标数据,通常可以通过 http://
Grafana Dashboard
使用 Grafana 可以非常方便地展示 Traefik 的实时监控数据。你可以设置一个 Grafana 仪表板来查看 Prometheus 收集的 Traefik 指标数据,具体数据项包括:
• 请求数(Requests)
• 响应时间(Response Time)
• 流量数据(Traffic)
• 后端服务的健康状况等
可以从 Traefik 官方 Grafana Dashboard 获取现成的面板(通常是通过 Grafana 仪表板 ID 导入),这个大家感兴趣可以自行研究,我这里就不详细说了,最终效果如下:
讲道理,还是挺炫酷的~。
总结
用Traefik来做负载均衡,我其实是有点不习惯的,因为它本来就是专为微服务和容器化环境而设计,所以里面的配置思路(静态配置文件、动态service发现等)和传统负载均衡的基本元素(VIP、service-group、server等)不是很对应得上,而我又是使用不常见的”文件动态配置”方式来实现不常见的”热备”需求,搞得我开始还头晕了一阵,不过习惯了之后也还好,别说,这玩意用来作为k8s的Ingress Controller的确太方便了,只要在动态配置文件里设置好k8s的API地址即可,以前要用传统负载均衡来做这种事可是很折腾的~。
不过,Traefik和传统负载均衡方案比还是有劣势,比如在负载均衡算法、自定义健康检查方式等方面都有不足(实现个优先级都要折腾半天,在传统负载均衡上就是点几下鼠标的事~),虽然我现在是用起来了,但是我还在犹豫,要不还是再折腾一下HAProxy吧?毕竟HAProxy才是最符合我需求的方案。
注1:一般traefik.yml在初次配置完之后,就不用动了,但是后续在配置dynamic.yml的时候,一定要小心,参数设置问题、格式问题(空格、缩进)都可能会导致Traefik里自定义的service消失(文件动态配置方式的劣势),我是吃了不少亏的(这也是我想换HAProxy的原因之一),大家如果遇到这种情况,不要急,静下心来慢慢排查就行了。
注2:本文没有涉及Traefik真正能大展拳脚的场景(微服务、容器环境、k8s),颇有遗憾,等下次有机会的时候我再另外写一篇文章来讲,不过网上这方面的教程也不少,大家如果有需求,也可以直接参考别人的文章。