简介 traefik 的路由规则就可以实现 4 层和 7 层的基本负载均衡操作,使用 IngressRoute IngressRouteTCP IngressRouteUDP 资源即可。但是如果想要实现 加权轮询、流量复制
等高级操作,traefik抽象出了一个 TraefikService 资源。此时整体流量走向为:外部流量先通过 entryPoints 端口进入 traefik,然后由 IngressRoute/IngressRouteTCP/IngressRouteUDP 匹配后进入 TraefikService
,在 TraefikService
这一层实现加权轮循和流量复制,最后将请求转发至kubernetes的service。
除此之外traefik还支持7层的粘性会话、健康检查、传递请求头、响应转发、故障转移等操作。
灰度发布 官方文档
Traefik2.0 的一个更强大的功能就是灰度发布,灰度发布也称为金丝雀发布(Canary),主要就是让一部分测试的服务也参与到线上去,经过测试观察看是否符号上线要求。
比如现在我们有两个名为 appv1
和 appv2
的服务,我们希望通过 Traefik 来控制我们的流量,将 3⁄4 的流量路由到 appv1,1/4 的流量路由到 appv2 去,这个时候就可以利用 Traefik2.0 中提供的带权重的轮询(WRR) 来实现该功能,首先在 Kubernetes 集群中部署上面的两个服务。为了对比结果我们这里提供的两个Nginx服务不同页面,方便测试。
appv1 服务的资源清单 appv2 服务的资源清单 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 cat > appv1.yml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: appv1 spec: selector: matchLabels: app: appv1 template: metadata: labels: use: test app: appv1 spec: containers: - image: nginx:alpine name: appv1 command: ["/bin/sh" , "-c" , "echo '你好, 这是(王先森)APP-v1服务中心'>/usr/share/nginx/html/index.html;nginx -g 'daemon off;'" ] ports: - containerPort: 80 name: portv1 --- apiVersion: v1 kind: Service metadata: name: appv1 spec: selector: app: appv1 ports: - name: http port: 80 targetPort: portv1 EOF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 cat > appv2.yml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: appv2 spec: selector: matchLabels: app: appv2 template: metadata: labels: use: test app: appv2 spec: containers: - name: appv2 image: nginx:alpine command: ["/bin/sh" , "-c" , "echo '你好, 这是(王先森)APP-v2服务中心'>/usr/share/nginx/html/index.html;nginx -g 'daemon off;'" ] ports: - containerPort: 80 name: portv2 --- apiVersion: v1 kind: Service metadata: name: appv2 spec: selector: app: appv2 ports: - name: http port: 80 targetPort: portv2 EOF
直接创建上面两个服务:
1 2 3 4 $ kubectl apply -f appv1.yml $ kubectl apply -f appv2.yml # 通过下面的命令可以查看服务是否运行成功 $ kubectl get pods -l use=test
在 Traefik2.1 中新增了一个 TraefikService
的 CRD 资源,我们可以直接利用这个对象来配置 WRR,之前的版本需要通过 File Provider,比较麻烦,新建一个描述 WRR 的资源清单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cat > wrr.yml <<EOF apiVersion: traefik.containo.us/v1alpha1 kind: TraefikService metadata: name: app-wrr spec: weighted: services: - name: appv1 weight: 3 # 定义权重 port: 80 kind: Service # 可选,默认就是 Service - name: appv2 weight: 1 port: 80 EOF
然后为我们的灰度发布的服务创建一个 IngressRoute 资源对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cat > wrr-ingressroute.yml <<EOF apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: wrr-ingressroute namespace: default spec: entryPoints: - web routes: - match: Host(\`wrr.od.com\`) kind: Rule services: - name: app-wrr kind: TraefikService EOF
在浏览器中连续访问 4 次,我们可以观察到 appv1 这应用会收到 3 次请求,而 appv2 这个应用只收到 1 次请求,符合上面我们的 3:1
的权重配置。
1 2 3 4 5 6 7 8 [root@ceph01 ~]#curl wrr.od.com 你好, 这是(王先森)APP-v2服务中心 [root@ceph01 ~]#curl wrr.od.com 你好, 这是(王先森)APP-v1服务中心 [root@ceph01 ~]#curl wrr.od.com 你好, 这是(王先森)APP-v1服务中心 [root@ceph01 ~]#curl wrr.od.com 你好, 这是(王先森)APP-v1服务中心
会话保持 官方文档
会话保持功能依赖加权轮询功能
当我们使用 traefik 的负载均衡时,默认情况下轮循多个 k8s 的 service 服务,如果用户对同一内容的多次请求,可能被转发到了不同的后端服务器。假设用户发出请求被分配至服务器 A,保存了一些信息在 session 中,该用户再次发送请求被分配到服务器 B,要用之前保存的信息,若服务器 A 和 B 之间没有 session 粘滞,那么服务器 B 就拿不到之前的信息,这样会导致一些问题。traefik 同样也支持粘性会话,可以让用户在一次会话周期内的所有请求始终转发到一台特定的后端服务器上。
创建 traefikervie 和 ingressRoute,实现基于 cookie 的会话保持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 cat > cookie.yml <<EOF apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: ingressroute-sticky namespace: default spec: entryPoints: - web routes: - match: Host(\`wrr.od.com\`) kind: Rule services: - name: sticky namespace: default kind: TraefikService --- apiVersion: traefik.containo.us/v1alpha1 kind: TraefikService metadata: name: sticky namespace: default spec: weighted: services: - name: appv1 port: 80 weight: 1 - name: appv2 port: 80 weight: 2 sticky: cookie: name: boysec-cookie EOF
客户端访问测试,携带 cookie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [root@ceph01 ~]# for i in {1..5}; do curl -b "boysec-cookie=default-appv2-80" http://wrr.od.com; done 你好, 这是(王先森)APP-v2服务中心 你好, 这是(王先森)APP-v2服务中心 你好, 这是(王先森)APP-v2服务中心 你好, 这是(王先森)APP-v2服务中心 你好, 这是(王先森)APP-v2服务中心 [root@ceph01 ~]# for i in {1..5}; do curl -b "boysec-cookie=default-appv1-80" http://wrr.od.com; done 你好, 这是(王先森)APP-v1服务中心 你好, 这是(王先森)APP-v1服务中心 你好, 这是(王先森)APP-v1服务中心 你好, 这是(王先森)APP-v1服务中心 你好, 这是(王先森)APP-v1服务中心 [root@ceph01 ~]#for i in {1..5}; do curl http://wrr.od.com; done 你好, 这是(王先森)APP-v2服务中心 你好, 这是(王先森)APP-v2服务中心 你好, 这是(王先森)APP-v1服务中心 你好, 这是(王先森)APP-v1服务中心 你好, 这是(王先森)APP-v1服务中心
流量复制 官方文档
所谓的流量复制,是一种可以将流入流量复制并同时将其发送给其他服务的方法,镜像服务可以获得给定百分比的请求同时也会忽略这部分请求的响应。,这个功能在做一些压测或者问题复现的时候很有用。
现在我们部署两个 nginx
的服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 cat > mirror-nginx.yml <<EOF apiVersion: v1 kind: Service metadata: name: v1 spec: ports: - protocol: TCP name: web port: 80 selector: app: v1 --- kind: Deployment apiVersion: apps/v1 metadata: name: v1 labels: app: v1 spec: selector: matchLabels: app: v1 template: metadata: labels: app: v1 spec: containers: - name: v1 image: nginx:alpine ports: - name: web containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: v2 spec: ports: - protocol: TCP name: web port: 80 selector: app: v2 --- kind: Deployment apiVersion: apps/v1 metadata: name: v2 labels: app: v2 spec: selector: matchLabels: app: v2 template: metadata: labels: app: v2 spec: containers: - name: v2 image: nginx:alpine ports: - name: web containerPort: 80 EOF
创建一个 IngressRoute 对象,将服务 v1 的流量复制 50% 到服务 v2,如下资源对象所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 cat > mirror-ingress-route.yaml <<EOF apiVersion: traefik.containo.us/v1alpha1 kind: TraefikService metadata: name: app-mirror spec: mirroring: name: v1 port: 80 mirrors: - name: v2 percent: 50 port: 80 --- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: mirror-ingress-route namespace: default spec: entryPoints: - web routes: - match: Host(\`mirror.od.com\`) kind: Rule services: - name: app-mirror kind: TraefikService EOF
创建这个资源对象后,在连续访问 4 次 mirror.od.com
可以发现有一半的请求也出现在了 v2
这个服务中。与预期相同,收到了 50% 的流量。
1 2 3 4 5 6 7 8 9 10 # V1 日志 $ kubectl logs -f v1-695b469cd-92jqj 172.16.130.2 - - [25/Aug/2023:07:03:08 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.0.1" "172.16.130.1" 172.16.120.5 - - [25/Aug/2023:07:03:08 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.0.1" "172.16.120.1" 172.16.100.5 - - [25/Aug/2023:07:03:08 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.0.1" "172.16.100.1" 172.16.130.2 - - [25/Aug/2023:07:03:08 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.0.1" "172.16.130.1" # V2 日志 $ kubectl logs -f v2-7b889df5d6-q2gkt 172.16.130.2 - - [25/Aug/2023:07:03:08 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.0.1" "172.16.130.1" 172.16.100.5 - - [25/Aug/2023:07:03:08 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.0.1" "172.16.100.1"