Traefik 是一款开源的反向代理和负载均衡软件,可以自动地为多个微服务实例进行负载均衡,并提供 HTTP/HTTPS/TCP/UDP 等协议支持。
Traefik 具有简单易用、自动发现服务、动态配置、可插拔的中间件等特点,被广泛应用于云原生和容器化场景中,介绍中也是表明自己是一个云原生网关。
Traefik 支持多种后端服务,包括 Kubernetes、Docker Swarm、Mesos、Consul、Etcd、Zookeeper、Redis 等,同时也提供了丰富的 API 和 Dashboard 等管理工具,使得用户能够方便地对反向代理和负载均衡进行配置和监控。
基本概念
Traefik 有 4 个基本概念,EntryPoints、Routers、Middlewares、Services。(官方图已经很清晰明了了,就不多画图了)
![null bec821f0deb432de039409f4a0e8e262.png](https://i-blog.csdnimg.cn/blog_migrate/22cfb2262e4f6e4ad6eb3c82e8fbfd0d.png)
EntryPoints
网络入口点,配置端口、协议,包括 HTTP、HTTPS、TCP 和 UDP,每个入口点都有一个唯一标识符,并可以配置不同的访问规则和路由策略。
![null 73e06348684a965c4f606c907c23c80f.png](https://i-blog.csdnimg.cn/blog_migrate/eb08b49ea112e717ac70369f0ead6559.png)
针对http、https 和 udp 不同的配置方式:
## Static configuration
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
streaming:
address: ":1704/udp"
Routers
路由,负责将传入的请求连接到可以处理它们的服务,在这个过程中,路由可以使用一些中间件来修改请求的一些信息。
![null cfc9427c0cef97e7a5c7435d0afaad7a.png](https://i-blog.csdnimg.cn/blog_migrate/9af41bbe4eaad45370479b0abae9ba62.png)
配置/foo
开始的请求路由到的后端服务。
## Dynamic configuration
http:
routers:
my-router:
rule: "Path(`/foo`)"
service: service-foo
路由可以配置不同的的规则,比如针对请求 host 和请求路径进行匹配。
rule = "Host(`example.com`) || (Host(`example.org`) && Path(`/traefik`))"
规则 | 描述 |
Headers(key , value ) | 请求头校验规则 |
HeadersRegexp(key , regexp ) | 请求头校验规则,value 正则匹配 |
Host(example.com , ...) | 请求域名校验规则 |
HostRegexp(example.com , {subdomain:[a-z]+}.example.com , ...) | 请求域名正则匹配规则 |
Method(GET , ...) | 请求方法校验规则,支持GET\POST\PUT\DELETE\PATCH\HEAD |
Path(/path , /articles/{cat:[a-z]+}/{id:[0-9]+} , ...) | 请求路径匹配规则,精确匹配,支持正则 |
PathPrefix(/products/ , /articles/{cat:[a-z]+}/{id:[0-9]+} ) | 请求路径前缀匹配规则,支持正则 |
Query(foo=bar , bar=baz ) | 请求参数匹配规则 |
ClientIP(10.0.0.0/16 , ::1 ) | 请求 IP 匹配规则 |
Middlewares
中间件,用于对请求进行处理和转换,类似过滤器、拦截器,有些人可能把他理解成很多网关中的插件,但是其实在 Traefik 里面也有插件的概念,并且可以发布分享,可以参考 https://plugins.traefik.io/create。
Traefik 提供了多种内置的中间件,比如日志记录、重定向、身份验证和限流等第,此外,也可以根据需要自定义中间件。
![null 621396d61942a2b68dc19e9a76b40f83.png](https://i-blog.csdnimg.cn/blog_migrate/d0f3c31f171a85009273800de59a3c2a.png)
配置方式:
# As a Docker Label
whoami:
# A container that exposes an API to show its IP address
image: traefik/whoami
labels:
# `foo-add-prefix` 中间件
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo"
- "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"
列出一些 HTTP 中间件列表,其实很多一看名字基本就知道是干嘛用的,基本上基础的网关鉴权、熔断、限流都有默认的插件。
中间件 | 描述 |
AddPrefix | 路径添前缀 |
BasicAuth | 鉴权 |
Buffering | 缓冲 |
Chain | 中间件链,可以定义可重用的中间件组合 |
CircuitBreaker | 熔断 |
Compress | 压缩 |
Headers | 请求头操作,可以添加、删除请求头 |
IPWhiteList | IP 白名单 |
RateLimit | 限流 |
Retry | 重试 |
Services
服务指的是 Traefik 服务,每个服务都有一个唯一标识符,并可以配置不同的负载均衡规则和健康检查策略。
需要注意的是这里的服务指的是 Traefik 自身的 service,并非是我们自己的服务。
![null 41f7a3923e9ce9039b5ec3b62cbd2129.png](https://i-blog.csdnimg.cn/blog_migrate/086e5d2221f8bd15e2bd30eb9fa6bde0.png)
配置示例:
## Dynamic configuration
http:
services:
my-service:
loadBalancer:
servers:
- url: "http://<private-ip-server-1>:<private-port-server-1>/"
- url: "http://<private-ip-server-2>:<private-port-server-2>/"
根据以上的概念,实际上在 Traefik 中一个请求的流程:
• 当客户端发送请求时,请求首先会被协议处理器接收并解析。
• 然后,请求会被路由器匹配到相应的路由规则,并根据规则将请求转发给相应的中间件链。
• 中间件链会按照顺序执行各个中间件,并根据需要对请求进行处理和转换。
• 处理完请求后,请求会被转发给相应的后端服务器。
• 后端服务器将处理完请求后的响应返回给 Traefik。
• 最后,Traefik 将响应返回给客户端。
负载均衡
Traefik 的负载均衡功能通过负载均衡器来实现,支持多种负载均衡策略,包括轮询、随机、加权轮询和加权随机等。
当 Traefik 接收到请求时,根据路由规则将请求转发给相应的后端服务器。如果后端服务器有多个,Traefik 就需要使用负载均衡算法来选择一个服务器处理请求。具体流程如下:
1. Traefik 会先根据配置的路由规则,将请求匹配到对应的前端入口点
2. 针对该入口点,Traefik 会获取所有与之关联的后端服务列表
3. 根据负载均衡策略,在可用的后端服务器中选择一个服务
4. 将请求转发给所选择的后端服务
5. 如果后端服务出现故障或者不可用,Traefik 会将其从服务器列表中移除,并选择另外一个可用的服务器来处理请求。
目前来说,官方支持轮询和加权轮询策略。
加权轮询
比如配置 v1 版本权重为3,v2版本权重为1,可用于灰度流量,配置方式如下。
## Dynamic configuration
http:
services:
app:
weighted:
services:
- name: appv1
weight: 3
- name: appv2
weight: 1
appv1:
loadBalancer:
servers:
- url: "http://private-ip-server-1/"
appv2:
loadBalancer:
servers:
- url: "http://private-ip-server-2/"
流量复制
另外还有一个比较特殊的是镜像请求,镜像能够将发送到一个服务的请求镜像到其他服务,或者我们叫做流量复制更好。
比如针对 appv1的请求,配置 percent 10,那么 10% 的流量就会被打到 appv2 服务上,配置方式如下:
## Dynamic configuration
http:
services:
mirrored-api:
mirroring:
service: appv1
# maxBodySize is the maximum size allowed for the body of the request.
# If the body is larger, the request is not mirrored.
# Default value is -1, which means unlimited size.
maxBodySize: 1024
mirrors:
- name: appv2
percent: 10
appv1:
loadBalancer:
servers:
- url: "http://private-ip-server-1/"
appv2:
loadBalancer:
servers:
- url: "http://private-ip-server-2/"
健康检查&故障转移
Traefik 要做负载均衡同样是需要健康检查的机制,健康检查需要配置健康检查的路径、请求频率(默认30秒)、超时时间(默认5秒),但是 K8S 有自己的健康检查机制,会移除失效的 pod,所以这里的健康检查对 K8S CRD 和 K8SIngress 无效。
故障转移只是依赖健康检查做正常的负载均衡而已,配置方式如下:
## Dynamic configuration
http:
services:
app:
failover:
service: main
fallback: backup
main:
loadBalancer:
healthCheck:
path: /status
interval: 10s
timeout: 3s
servers:
- url: "http://private-ip-server-1/"
backup:
loadBalancer:
servers:
- url: "http://private-ip-server-2/"
部署
接下来通过 Docker 和 K8S 方式了解一下基本的使用。
Docker
首先下载镜:
docker run -d -p 8080:8080 -p 80:80 -v $PWD/traefik.yml:/etc/traefik/traefik.yml traefik:v2.10
创建配置文件:
version: '3'
services:
whoami:
# A container that exposes an API to show its IP address
image: traefik/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.10
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
# The HTTP port
- "80:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
启动:
docker-compose up -d reverse-proxy
docker-compose up -d whoami
服务创建成功,自动服务发现 whoami
,并且存在规则,请求头带 Host 请求可以访问到 whoami 的服务。
![null 392c529f97871e2f20f40ead43ca1ed0.png](https://i-blog.csdnimg.cn/blog_migrate/fbd73e03b2eaa5ea952eccc0bed23b4f.png)
测试请求http://localhost
可以得到响应
![null 6aac9eb7772d12771b15db07d5547e7f.png](https://i-blog.csdnimg.cn/blog_migrate/185d7528db221cbc6c224ec448a0eea2.png)
同时,可以使用命令扩容:
docker-compose up -d --scale whoami=2
发现启动了两个 whoami
的实例
![null 5fbf3a75650a2ff71ff9b463b62e5af1.png](https://i-blog.csdnimg.cn/blog_migrate/bb6baa825e813f060137af0b80936ae6.png)
再次请求会发现响应的 IP 会发生变化 IP: 172.18.0.4或者 IP: 172.18.0.3,从后台也可以看到两个实例
![null f17651b1a60bcbb2c87abf23af932cfb.png](https://i-blog.csdnimg.cn/blog_migrate/c9f31a9cf19dde667e5e5ae99df958b0.png)
K8S
Traefik 结合 K8S 首先需要 K8S 的环境,Mac 下直接使用 Docker Desktop 还是比较方便的。
Mac K8S 环境搭建
首先,下载 Docker Desktop,下载好之后是自带 K8S 的,我们只要在设置中开启即可。
![null ecdb071fcbcde4bcc80a7176dd5001fb.png](https://i-blog.csdnimg.cn/blog_migrate/506c6d7bd5c28970e55e01bc85d4feff.png)
开启之后需要等待一段时间,需要去拉取相关依赖的镜像,国内可能需要自己科学上网,OK 之后可以看到 K8S 已经启动成功。
![null 14880372d4fca56e8389f6ddb5b09ce0.png](https://i-blog.csdnimg.cn/blog_migrate/eb32596788bf8a60d47b43bbedb79e7e.png)
到这里那其实已经就好了,顺便可以安装一下Kubernetes Dashboard,默认情况下不会部署控制台,使用命令部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
运行结果:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
然后,使用 kubectl
命令行工具来启用 Dashboard 访问。
kubectl proxy
启动成功之后访问 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ ,进入控制台页面,然后需要我们去配置 token,目前只能通过这种方式去访问。
![null a1a9eb09576888feb2a6adf15c879149.png](https://i-blog.csdnimg.cn/blog_migrate/b3bc372e00bd7781b9e7c56edb69aedb.png)
按照官网文档:https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md,配置一个账户和集群角色,复制到一个文件就行,不需要做修改,保存文件为 k8s-admin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
使用命令创建服务:
kubectl create -f k8s-admin.yaml
执行命令,生成 token:
kubectl -n kubernetes-dashboard create token admin-user
![null f87f20c1eb909d37f4c66b1729e1cc30.png](https://i-blog.csdnimg.cn/blog_migrate/95cf9895f51c3c7d5d7c0f6a1644b5c7.png)
然后填入 token,就可以正常访问 dashboard 了。
![null 7f814c8e1eabf9134b07ce054b903cd3.png](https://i-blog.csdnimg.cn/blog_migrate/f8a4d926c29968aeb407b7921e60fab7.png)
Traefik 部署
参考官方文档:https://doc.traefik.io/traefik/getting-started/quick-start-with-kubernetes/
Traefik 使用 Kubernetes API 来做服务发现,为了使用 Kubernetes API,Traefik 需要一些权限,首先是创建角色,创建 ClusterRole 角色:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-role
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
然后创建用于 traefik 的账户:
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-account
然后,在账户上绑定角色以应用权限和规则:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-role
subjects:
- kind: ServiceAccount
name: traefik-account
namespace: default
这样角色和账户的配置已经完成了,接下来需要配置 Traefik 的服务信息和 Dashboard 控制台,其中 args 参数是 traefik 的启动静态配置参数。
kind: Deployment
apiVersion: apps/v1
metadata:
name: traefik-deployment
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-account
containers:
- name: traefik
image: traefik:v2.10
args:
- --api.insecure
- --providers.kubernetesingress
ports:
- name: web
containerPort: 80
- name: dashboard
containerPort: 8080
创建 Traefik 的服务资源:
apiVersion: v1
kind: Service
metadata:
name: traefik-dashboard-service
spec:
type: LoadBalancer
ports:
- port: 8080
targetPort: dashboard
selector:
app: traefik
---
apiVersion: v1
kind: Service
metadata:
name: traefik-web-service
spec:
type: LoadBalancer
ports:
- targetPort: web
port: 80
selector:
app: traefik
最终,我们可以根据这些配置统一到一个配置文件中,命名为k8s-traefik.yaml
,然后使用命令创建:
kubectl apply -f k8s-traefik.yaml
clusterrole.rbac.authorization.k8s.io/traefik-role created
serviceaccount/traefik-account created
clusterrolebinding.rbac.authorization.k8s.io/traefik-role-binding created
deployment.apps/traefik-deployment created
service/traefik-dashboard-service created
service/traefik-web-service created
这时候,访问控制台http://localhost:8080/dashboard/#/
,可以看到已经成功了。
![null b7ed541b91f6d1bb91e2f29119fa2e85.png](https://i-blog.csdnimg.cn/blog_migrate/0f80aa707c0b3cc17e30a33172f89858.png)
traefik/whoami
。
同样,新建一个文件命名为k8s-whoami.yaml
,使用命令创建服务,这样服务就部署成功了。
kubectl apply -f k8s-whoami.yaml
deployment.apps/whoami created
service/whoami created
ingress.networking.k8s.io/whoami-ingress created
从后台可以看到服务启动成功:
![null 65518c0f003bfa2c7162dd901bb50b13.png](https://i-blog.csdnimg.cn/blog_migrate/3227ca7de82fcf3a87a125cd0c18f26d.png)
同时,可以访问http://localhost
访问到服务:
![null 15dfcced278b0cdc9656b023ad059afa.png](https://i-blog.csdnimg.cn/blog_migrate/82c8ecb54cca7380ff0ec09243181761.png)