Traefik 2.0新增了很多高级功能,灰度发布就是其中一个,本文我们来介绍一下基于Traefik 2.0实现灰度发布。
注意: 目前最新版本是v2.1.1,截至目前版本要实现灰度发布、流量复制等高级功能,只能通过File Provider来实现。不能使用KubernetesCRD Provider了。
灰度发布,就是将测试的服务放到生产去跑,然后观察是否符合上线要求,如下:
1、我们把测试服务放到生产,接入少部分流量来进行观察;
2、如果测试观察没问题,就符合上线要求,可以慢慢增加新版本数量,减少旧版本数量;
3、如果测试观察有问题,就需要切掉该版本,对测试用户进行修数处理;
比如现在我们有两个名为 appv1 和 appv2 的 Nginx 服务,我们希望通过 Traefik 来控制我们的流量,将 3⁄4 的流量路由到 appv1,1/4 的流量路由到 appv2 去,这个时候就可以利用 Traefik2.0 中提供的带权重的轮询(WRR)来实现该功能,首先在 Kubernetes 集群中部署上面的两个服务。
appv1的资源清单(appv1.yaml)
apiVersion: apps/v1kind: Deploymentmetadata:name: appv1namespace: defaultspec:selector:matchLabels:app: appv1template:metadata:labels:use: testapp: appv1spec:containers:- name: nginximage: nginxports:- containerPort: 80name: portv1---apiVersion: v1kind: Servicemetadata:name: appv1namespace: defaultspec:selector:app: appv1ports:- name: httpport: 80targetPort: portv1
appv2的资源清单(appv2.yaml)
apiVersion: apps/v1kind: Deploymentmetadata:name: appv2namespace: defaultspec:selector:matchLabels:app: appv2template:metadata:labels:use: testapp: appv2spec:containers:- name: nginximage: nginxports:- containerPort: 80name: portv2---apiVersion: v1kind: Servicemetadata:name: appv2namespace: defaultspec:selector:app: appv2ports:- name: httpport: 80targetPort: portv2
然后创建这两个资源清单:
# kubectl get podNAME READY STATUS RESTARTS AGEappv1-684f8cbc7-kr4d5 1/1 Running 0 3m53sappv2-645d7666b5-thgt2 1/1 Running 0 3m53s
由于 WRR 这个功能目前只支持 File Provider,所以我们需要开启该 Provider 才能使用,这里需要注意的是由于需要开启 File Provider,所以我们需要提供一个文件用于该 Provider 的配置,我们这里是用在 Kubernetes 集群中的,所以可以通过一个 ConfigMap 对象,将配置文件内容挂载到 Traefik 的 Pod 中去,如下所示,我们通过将一个名为 traefik-dynamic-conf 的 ConfigMap 对象挂载到了 /config 目录下面去,然后通过 —providers.file.filename参数指定配置文件开启 File Provider,另外添加 - —providers.file.watch=true 参数可以让 Traefik 动态更新配置:
traefik.yaml
kind: DeploymentapiVersion: extensions/v1beta1metadata:name: traefiknamespace: kube-systemlabels:k8s-app: traefik-ingress-lbspec:selector:matchLabels:k8s-app: traefik-ingress-lbtemplate:metadata:labels:k8s-app: traefik-ingress-lbname: traefik-ingress-lbspec:serviceAccountName: traefik-ingress-controllertolerations:- operator: "Exists"nodeSelector:kubernetes.io/hostname: 172.16.0.33containers:- image: traefik:v2.0name: traefik-ingress-lbports:- name: webcontainerPort: 80- name: websecurecontainerPort: 443- name: admincontainerPort: 8080- name: rediscontainerPort: 6379volumeMounts:- name: configmountPath: /configargs:- --entrypoints.web.Address=:80- --entrypoints.websecure.Address=:443- --entrypoints.redis.Address=:6379- --entrypoints.foo- --api.insecure=true- --providers.kubernetescrd- --providers.file.watch=true- --providers.file.filename=/config/traefik-dynamic.toml- --api- --api.dashboard=true- --accesslog# 使用 tls 验证这种方式- --certificatesresolvers.default.acme.tlsChallenge=true# # 邮箱配置- --certificatesResolvers.default.acme.email=rookieops@163.com# # 保存 ACME 证书的位置- --certificatesResolvers.default.acme.storage="acme.json"# # 下面是用于测试的ca服务,如果https证书生成成功了,则移除下面参数#- --certificatesresolvers.default.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory- --certificatesresolvers.default.acme.caserver=https://acme-v02.api.letsencrypt.org/directoryvolumes:- name: configconfigMap:name: traefik-dynamic-conf---kind: ServiceapiVersion: v1metadata:name: traefiknamespace: kube-systemspec:type: NodePortselector:k8s-app: traefik-ingress-lbports:- protocol: TCPport: 8080name: admin- name: webport: 80protocol: TCP- name: websecureport: 443protocol: TCP- name: redisport: 6379protocol: TCP
上面是开启 File Provider 的配置,接下来需要创建对应的 ConfigMap 对象,首先创建一个名为 traefik-dynamic.toml 的文件,内容如下所示:
[http][http.routers][http.routers.Router0]entryPoints = ["web"]service = "app"rule = "Host(`nginx.rookieops.top`)"[http.services][http.services.app][[http.services.app.weighted.services]]name = "appv1"weight = 3[[http.services.app.weighted.services]]name = "appv2"weight = 1[http.services.appv1][http.services.appv1.loadBalancer][[http.services.appv1.loadBalancer.servers]]url = "http://appv1.default.svc.cluster.local/"[http.services.appv2][http.services.appv2.loadBalancer][[http.services.appv2.loadBalancer.servers]]url = "http://appv2.default.svc.cluster.local/"
上面这个配置文件就是我们需要配置的灰度发布的规则,创建一个名为 Router0 的路由,在 web 这个入口点上面监听 Host=nginx.rookieops.top 这样的请求,将请求路由给名为 app 的服务,而该服务则将请求路由给了 appv1 这个服务,权重为 3,另外一部分请求路由给了 appv2 这个服务,权重为 1,也就是有 3⁄4 的请求会被路由到 http://appv1.default.svc.cluster.local/ 这个真实的服务上,同样的另外的 1⁄4 请求会被路由到 http://appv2.default.svc.cluster.local/ 这个真实的服务上。
然后创建这个ConfigMap:
# kubectl create configmap traefik-dynamic-conf --from-file=traefik-dynamic.toml -n kube-system
创建完成后,再更新 Traefik2.0,就可以将配置文件通过 ConfigMap 挂载到 Traefik Pod 的 /config/traefik-dynamic.toml 路径下面去了。
然后我们测试观察如下:
