Traefik是一个开源的可以使服务发布变得轻松有趣的边缘路由器。它负责接收你系统的请求,然后使用合适的组件来对这些请求进行处理。
除了众多功能之外,Traefik的与众不同之处还在于它会自动发现你服务的配置。当Traefik在检查你的服务时,会找到服务的相关信息并找到合适的服务来满足对应的请求。
Traefik兼容所有主流的集群技术,如k8s、docker、doker swarm、aws、mesos、marathon等等;并且可以同事处理多种方式。
使用Traefik,不需要维护或者同步一个独立的配置文件,因为一切都会自动配置,实时操作的(无需重新启动,不会中断连接)。使用Traefik,可以花更多的时间在系统的开发和新功能上,而不是在配置和维护工作状态上花费时间。
核心概念
Traefik是一个边缘路由器,是整个平台的大门,拦截并路由每个传入的请求:它知道所有的逻辑和规则,这些规则确定哪些服务处理哪些请求;传统的反向代理需要一个配置文件,其中包含路由到你服务的所有可能路由,而Traefik会实时检测服务并自动更新路由规则,可以自动服务发现。
首先,当启动Traefik时,需要定义entrypoints(入口点),然后根据连接到这些entrypoints的路由来分析传入的请求,查看他们是否与一组规则相匹配,如果匹配,则路由可能会将请求通过一系列中间件转换过后再转发到你的服务上去。在了解Traefik之前有几个核心概念需要了解:
Providers:用来自动发现平台上的服务,可以是编排工具、容器引擎或者是key-value存储等,比如docker、k8s、fileEntrypoints:监听传入的流量(端口等…),是网络的入口点,它们定义了接收请求的端口(HTTP或者TCP)Routers:分析请求(host、path、headers、SSL….),负责将传入请求连接到可以处理这些请求的服务上去Services:将请求转发给你的应用(Load balancing…),负责配置如何获取最终将处理传入请求的实际服务。Middlewares:中间件,用来修改请求或者根据请求来做出一些判断(authentication,ratelimiting,headers….),中间件被附件到路由上,是一种在请求发送到你的服务之前(或者在服务的响应发送到客户端之前)调整请求的一种方法。
安装
使用Traefik2.3.6版本
在Traefik中的配置可以使用两种不同的方式:
- 动态配置:完全动态的路由配置
- 静态配置:启动配置
静态配置中的元素(这些元素不会经常变更)连接到providers并定义Traefik将要监听的entrypoints。
Traefik中有三种方式定义静态配置:在配置文件中、在命令行参数中、通过环境变量传递
动态配置包含定义系统如何处理请求的所有配置内容,这些配置是可以改变的,而且是无缝热更新的,没有任何请求中断或连接损耗。
使用helm来快速安装traefik,首先获取Helm Chart包:
➜ git clone https://github.com/traefik/traefik-helm-chart
创建一个定制的values配置文件:
# values-prod.yaml
# Create an IngressRoute for the dashboard
ingressRoute:
dashboard:
enabled: false # 禁用helm中渲染的dashboard,我们自己手动创建
# Configure ports
ports:
web:
port: 8000
hostPort: 80 # 使用 hostport 模式
# Use nodeport if set. This is useful if you have configured Traefik in a
# LoadBalancer
# nodePort: 32080
# Port Redirections
# Added in 2.2, you can make permanent redirects via entrypoints.
# https://docs.traefik.io/routing/entrypoints/#redirection
# redirectTo: websecure
websecure:
port: 8443
hostPort: 443 # 使用 hostport 模式
# Options for the main traefik service, where the entrypoints traffic comes
# from.
service: # 使用 hostport 模式就不需要Service了
enabled: false
# Logs
# https://docs.traefik.io/observability/logs/
logs:
general:
level: DEBUG
tolerations: # kubeadm 安装的集群默认情况下master是有污点,需要容忍这个污点才可以部署
- key: "node-role.kubernetes.io/master"
operator: "Equal"
effect: "NoSchedule"
nodeSelector: # 固定到master1节点(该节点才可以访问外网)
kubernetes.io/hostname: "master1"
用 hostport 模式将 Traefik 固定到 master1 节点上,因为只有这个节点有外网 IP,所以这里 master1 是作为流量的入口点。直接使用上面的 values 文件安装 traefik:
➜ helm install --namespace kube-system traefik ./traefik -f ./values-prod.yaml
NAME: traefik
LAST DEPLOYED: Thu Dec 24 11:23:51 2020
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
➜ kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik
NAME READY STATUS RESTARTS AGE
traefik-78ff486794-64jbd 1/1 Running 0 3m15s
安装完成后可以通过查看Pod的资源清单来了解Traefik的运行方式:
➜ kubectl get pods traefik-78ff486794-64jbd -n kube-system -o yaml
apiVersion: v1
kind: Pod
metadata:
......
spec:
containers:
- args:
- --global.checknewversion
- --global.sendanonymoususage
- --entryPoints.traefik.address=:9000/tcp
- --entryPoints.web.address=:8000/tcp
- --entryPoints.websecure.address=:8443/tcp
- --api.dashboard=true
- --ping=true
- --providers.kubernetescrd
- --providers.kubernetesingress
- --accesslog=true
- --accesslog.fields.defaultmode=keep
- --accesslog.fields.headers.defaultmode=drop
...
其中entryponits属性定义了web和websecure这两个入口点,并开启kubernetesingress和kubernetescrd这两个provider,也就是说明可以使用k8s原本的ingress对象,也可以使用Traefik自己扩展的IngressRoute这样的CRD资源对象。
创建一个用于Dashboard访问的IngressRoute资源清单:
➜ cat <<EOF | kubectl apply -f -
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
namespace: kube-system
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.qikqiak.com`) # 指定域名
kind: Rule
services:
- name: api@internal
kind: TraefikService # 引用另外的 Traefik Service
EOF
➜ kubectl get ingressroute -n kube-system
NAME AGE
traefik-dashboard 19m
其中的TraefikService是Traefik Service的一个CRD实现,这里使用的api@internal这个TraefikService,表示我们访问的是Traefik内置的应用服务。
部署完成后可以通过在本地/etc/hosts中添加域名的映射即可访问Traefik的Dashboard页面:
需要注意的是默认情况下Traefik的IngressRoute已经允许跨namespace进行通信了,可以通过设置参数
--providers.kubernetescrd.allowCrossNamespace=true(默认已经开启),开启后IngressRoute就可以引用IngressRoute命名空间以外的其他命名空间中的任何资源了
ACME
Traefik通过扩展CRD的方式来扩展Ingress的功能,除了默认的用Secret的方式可以支持应用的HTTPS之外,还支持自动生成HTTPS证书。
示例应用:
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
ports:
- protocol: TCP
name: web
port: 80
selector:
app: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami
labels:
app: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: containous/whoami
ports:
- name: web
containerPort: 80
然后定义一个IngressRoute对象:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: simpleingressroute
spec:
entryPoints:
- web
routes:
- match: Host(`who.qikqiak.com`) && PathPrefix(`/notls`)
kind: Rule
services:
- name: whoami
port: 80
通过entrypoints指定了应用的入口点是web,也就是通过80端口访问,然后访问的规则就是匹配who.qikqiak.com这个域名,并且具有/notls的路径前缀的请求才会被whoami这个Service所匹配。可以直接创建上面的资源对象,然后对域名做对应的解析后,就可以访问应用了:
在IngressRoute对象中定义了一些匹配规则,这些规则在Traefik中有如下定义方式:
如果需要用HTTPS来访问应用的话,就需要监听websecure这个入口点,也就是通过443端口来访问,同样用HTTPS访问必然需要证书,这里用openssl来创建一个自签名证书:
➜ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=who.qikqiak.com"
然后通过Secret对象来引用证书文件:
# 要注意证书文件名称必须是 tls.crt 和 tls.key
➜ kubectl create secret tls who-tls --cert=tls.crt --key=tls.key
secret/who-tls created
这时候就可以创建一个HTTPS访问应用的IngressRoute对象:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls
spec:
entryPoints:
- websecure
routes:
- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
kind: Rule
services:
- name: whoami
port: 80
tls:
secretName: who-tls
创建完成后就可以通过HTTPS来访问应用了,由于是自签名证书,所以证书不受信任:
除了手动提供证书的方式外Traefik同样也支持使用let's encrypt自动生成证书,要使用let’s encrypt来进行自动化HTTPS,就需要首先开启ACME,开启ACME需要通过静态配置的方式,也就是说可以通过环境变量、启动参数等方式来提供。
ACME有多种校验方式tlsChallenge、httpChallenge 和 dnsChallenge 三种验证方式,之前常用的是http这种验证方式,关于这几种验证方式的使用可以查看文档:https://www.qikqiak.com/traefik-book/https/acme/了解它们之间的区别。要使用tls校验方式的话需要保证Traefik的443端口可达,dns校验方式可以生成通配符的证书,只需要配置上DNS解析服务商的API访问密钥即可校验。下面是DNS校验的方式
重新修改Helm安装的values配置文件,添加如下的定制参数:
# values-prod.yaml
additionalArguments:
# 使用 dns 验证方式
- --certificatesResolvers.ali.acme.dnsChallenge.provider=alidns
# 先使用staging环境进行验证,验证成功后再使用移除下面一行的配置
# - --certificatesResolvers.ali.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
# 邮箱配置
- --certificatesResolvers.ali.acme.email=ych_1024@163.com
# 保存 ACME 证书的位置
- --certificatesResolvers.ali.acme.storage=/data/acme.json
envFrom:
- secretRef:
name: traefik-alidns-secret
# ALICLOUD_ACCESS_KEY
# ALICLOUD_SECRET_KEY
# ALICLOUD_REGION_ID
persistence:
enabled: true # 开启持久化
accessMode: ReadWriteOnce
size: 128Mi
path: /data
# 由于上面持久化了ACME的数据,需要重新配置下面的安全上下文
securityContext:
readOnlyRootFilesystem: false
runAsGroup: 0
runAsUser: 0
runAsNonRoot: false
通过设置--certificatesresolvers.ali.acme.dnschallenge.provider=alidns参数来指定阿里云的DNS校验,要使用阿里云的DNS校验还需要配置3个环境变量:ALICLOUD_ACCESS_KEY、ALICLOUD_SECRET_KEY、ALICLOUD_REGION_ID,分别对应平时开发阿里云应用的时候的密钥,可以登录阿里云后台获取,由于比较私密,所以使用Secret对象来创建:
➜ kubectl create secret generic traefik-alidns-secret --from-literal=ALICLOUD_ACCESS_KEY=<aliyun ak> --from-literal=ALICLOUD_SECRET_KEY=<aliyun sk> --from-literal=ALICLOUD_REGION_ID=cn-beijing -n kube-system
创建完后将这个Secret通过环境变量配置到Traefik的应用中,还有一个值得注意的是验证通过的证书存放在/data/acme.json文件中,一定要将这个文件持久化,否则每次Traefik重建后就需要重新认证,而let’s encrypt本身验证次数是有限制的。所以在values中重新开启了数据持久化,不过开启过后需要提供一个可用的PV存储,由于将Traefik固定到master节点上,所以可以创建一个hostpath类型的pv:
➜ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: traefik
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 128Mi
hostPath:
path: /data/k8s/traefik
EOF
然后使用如下命令更新Traefik:
➜ helm upgrade --install traefik --namespace=kube-system ./traefik -f ./values-prod.yaml
Release "traefik" has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Thu Dec 24 14:32:04 2020
NAMESPACE: kube-system
STATUS: deployed
REVISION: 2
TEST SUITE: None
更新完成后来修改whoami的资源清单:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls
spec:
entryPoints:
- websecure
routes:
- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
kind: Rule
services:
- name: whoami
port: 80
tls:
certResolver: ali
domains:
- main: "*.qikqiak.com"
其他的都不变,只需要将 tls 部分改成我们定义的 ali 这个证书解析器,如果我们想要生成一个通配符的域名证书的话可以定义 domains 参数来指定,然后更新 IngressRoute 对象,这个时候我们再去用 HTTPS 访问我们的应用(当然需要将域名在阿里云 DNS 上做解析):
中间件
中间件是Traefik2.x中一个非常有特色的功能,可以根据自己的各种需求去选择不同的中间件来满足服务,traefik官方已经内置了许多不同功能的中间件,其中一些可以修改请求,头信息,一些负责重定向,一些添加身份验证等等,而且中间件还可以通过链式组合的方式来适用各种情况。
比如上面定义的whoami这个应用,可以通过https://whoami.qikqiak.com/tls来访问到应用,但是如果用http访问就会404,因为根本没有监听80端口这个入口点,所以要想通过http来访问应用的话就需要监听下web这个入口点:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls-http
spec:
entryPoints:
- web
routes:
- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
kind: Rule
service:
- name: whoami
port: 80
这里创建的IngressRoute的entryPoints是web,然后创建这个对象,就可以通过http访问到这个应用。
但是如果只希望用户通过https,需要让http强制跳转到https服务去,在Traefik中可以配置强制跳转,只是这个功能目前是通过中间件来提供的,如下所示,使用redirectScheme中间件来创建提供强制跳转服务:
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-https
spec:
redirectScheme:
scheme: https
然后将这个中间件附加到http的服务上去:
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls-http
spec:
entryPoints:
- web
routes:
- match: Host(`who.qikqiak.com`) && PathPrefix(`/tls`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: redirect-https
这个时候再去访问 http 服务可以发现就会自动跳转到 https 去了。关于更多中间件的用法可以查看文档Traefik Docs。
Traefik Pilot
虽然Traefik已经默认实现了很多中间件,可以满足大部分日常需求,但是在实际的工作中,用户仍然还是有自定义中间件的需求,这就是Traefik Pilot的功能了。
Traefik Pilot是一个SaaS平台,和Traefik进行链接来扩展其功能,它提供了很多功能,通过一个全局控制面板和Dashboard来增强traefik的观测和控制:
- Traefik代理和代理组的网络活动的指标
- 服务健康问题和安全漏洞警报
- 扩展Traefik功能的插件
在Traefik可以使用Traefik Pilot的功能之前,必须先连接他们,只需要对Traefik的静态配置进行少量更改即可。
Traefik代理必须要能访问互联网才能连接Traefik Pilot,通过HTTP在443端口上建立连接
首先需要在Traefik Pilot主页(https://pilot.traefik.io/)上创建账号,注册新的Traefik实例并开始使用Traefik Poilt。登录后,可以通过选择Register New Traefik IInstance来创建新实例。
另外,当 Traefik 尚未连接到 Traefik Pilot 时,Traefik Web UI 中将出现一个响铃图标,我们可以选择 Connect with Traefik Pilot 导航到 Traefik Pilot UI 进行操作。
登录完成后,Traefik Pilot 会生成一个新实例的令牌,我们需要将这个 Token 令牌添加到 Traefik 静态配置中。
我们这里就是在 values-prod.yaml 文件中启用 Pilot 的配置:
# values-prod.yaml
# Activate Pilot integration
pilot:
enabled: true
token: "e079ea6e-536a-48c6-b3e3-f7cfaf94f477"
然后重新更新 Traefik:
➜ helm upgrade --install traefik --namespace=kube-system ./traefik -f ./values-prod.yaml
更新完成后,在 Traefik 的 Web UI 中就可以看到 Traefik Pilot UI 相关的信息了。
接下来就可以在 Traefik Pilot 的插件页面选择想要使用的插件,比如这里使用 Demo Plugin 这个插件。
点击右上角的 Install Plugin 按钮安装插件会弹出一个对话框提示如何安装。
首先需要将当前 Traefik 注册到 Traefik Pilot(已完成),然后需要以静态配置的方式添加这个插件到 Traefik 中,这里同样更新 values-prod.yaml 文件中的 Values 值即可:
# values-prod.yaml
# Activate Pilot integration
pilot:
enabled: true
token: "e079ea6e-536a-48c6-b3e3-f7cfaf94f477"
additionalArguments:
# 添加 demo plugin 的支持
- --experimental.plugins.plugindemo.modulename=github.com/traefik/plugindemo
- --experimental.plugins.plugindemo.version=v0.2.1
# 其他配置
重新更新 Traefik:
➜ helm upgrade --install traefik --namespace=kube-system ./traefik -f ./values-prod.yaml
更新完成后创建一个如下所示的 Middleware 对象:
➜ cat <<EOF | kubectl apply -f -
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: myplugin
spec:
plugin:
plugindemo: # 插件名
Headers:
X-Demo: test
Foo: bar
EOF
然后添加到上面的 whoami 应用的 IngressRoute 对象中去:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: simpleingressroute
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`who.qikqiak.com`) && PathPrefix(`/notls`)
kind: Rule
services:
- name: whoami # K8s Service
port: 80
middlewares:
- name: myplugin # 使用上面新建的 middleware
更新完成后,当去访问 http://who.qikqiak.com/notls 的时候就可以看到新增了两个上面插件中定义的两个 Header。
当然除了使用 Traefik Pilot 上开发者提供的插件之外,也可以根据自己的需求自行开发自己的插件,可以自行参考文档:https://doc.traefik.io/traefik-pilot/plugins/plugin-dev/
灰度发布
Traefik2.x的一个更强大的功能就是灰度发布,灰度发布有时候也会称为金丝雀发布(Canary),主要就是让一部分测试服务也参与到线上,经过测试观察是否符合上线要求。
比如现在有两个名为appv1和appv2的服务,希望通过Traefik来控制流量,将3/4的流量路由到appv1,1/4的流量路由到appv2去,这时候就可以利用Traefik2.x中提供的带权重的轮询(WRR)来实现这个功能,首先在k8s集群中部署两个服务:
appv1服务资源清单(appv1.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv1
spec:
selector:
matchLabels:
app: appv1
template:
metadata:
labels:
use: test
app: appv1
spec:
containers:
- name: whoami
image: containous/whoami
ports:
- containerPort: 80
name: portv1
---
apiVersion: v1
kind: Service
metadata:
name: appv1
spec:
selector:
app: appv1
ports:
- name: http
port: 80
targetPort: portv1
appv2服务资源清单(appv2.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv2
spec:
selector:
matchLabels:
app: appv2
template:
metadata:
labels:
use: test
app: appv2
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: portv2
---
apiVersion: v1
kind: Service
metadata:
name: appv2
spec:
selector:
app: appv2
ports:
- name: http
port: 80
targetPort: portv2
直接创建上面两个服务
➜ kubectl apply -f appv1.yaml
➜ kubectl apply -f appv2.yaml
# 通过下面的命令可以查看服务是否运行成功
➜ kubectl get pods -l use=test
NAME READY STATUS RESTARTS AGE
appv1-58f856c665-shm9j 1/1 Running 0 12s
appv2-ff5db55cf-qjtrf 1/1 Running 0 12s
在Traekfik2.1中新增了一个TraefikService的CRD资源,可以直接利用这个对象来配置WRR,之前的版本需要通过File Provider。新建一个描述WRR的资源清单:(wrr.yaml)
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
然后为我们的灰度发布的服务创建一个 IngressRoute 资源对象:(ingressroute.yaml)
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: wrringressroute
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`wrr.qikqiak.com`)
kind: Rule
services:
- name: app-wrr
kind: TraefikService
不过需要注意的是现在配置的 Service 不再是直接的 Kubernetes 对象了,而是上面定义的 TraefikService 对象,直接创建上面的两个资源对象,这个时候对域名 wrr.qikqiak.com 做上解析,去浏览器中连续访问 4 次,可以观察到 appv1 这应用会收到 3 次请求,而 appv2 这个应用只收到 1 次请求,符合上面的 3:1 的权重配置。
流量复制
除了灰度发布之外,Traefik2.0还引入了流量镜像服务,是一种可以将流入流量复制并同时将其发送给其他服务的方法,镜像服务可以获得给定百分比的请求同时也会忽略这部分请求的响应。
部署两个whoami的服务,资源清单文件如下:
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
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
ports:
- name: web
containerPort: 80
直接创建上面的资源对象:
➜ kubectl get pods
NAME READY STATUS RESTARTS AGE
v1-77cfb86999-wfbl2 1/1 Running 0 94s
v2-6f45d498b7-g6qjt 1/1 Running 0 91s
➜ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
v1 ClusterIP 10.96.218.173 <none> 80/TCP 99s
v2 ClusterIP 10.99.98.48 <none> 80/TCP 96s
现在创建一个IngressRoute对象,将服务v1的流量复制50%到服务v2,如下资源清单:(mirror-ingress-route.yaml)
apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
name: app-mirror
spec:
mirroring:
name: v1 # 发送 100% 的请求到 K8S 的 Service "v1"
port: 80
mirrors:
- name: v2 # 然后复制 50% 的请求到 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.qikqiak.com`)
kind: Rule
services:
- name: app-mirror
kind: TraefikService # 使用声明的 TraefikService 服务,而不是 K8S 的 Service
然后直接创建这个资源对象:
➜ kubectl apply -f mirror-ingress-route.yaml
ingressroute.traefik.containo.us/mirror-ingress-route created
traefikservice.traefik.containo.us/mirroring-example created
这个时候在浏览器中去连续访问4次 mirror.qikqiak.com 可以发现有一半的请求也出现在了 v2 这个服务中:
