最小范围控制更新app迭代影响,灰度发布必备宝典

Traefik目前的最新版本是 v2.0.2,截止该版本,要实现灰度发布、流量复制这些高级功能,只能通过File Provider来实现。

灰度发布我们有时候也会称为金丝雀发布(Canary),主要就是让一部分测试的服务也参与到线上去,经过测试观察看是否符号上线要求。

发布架构概述

canary deployment(灰度发布 NGINX服务)

比如现在有两个名为 appv1 和 appv2 的 Nginx 服务,我们希望通过 Traefik 来控制我们的流量,将 34 的流量路由到 appv1,1/4 的流量路由到 appv2 去,这个时候就可以利用 Traefik2.0 中提供的带权重的轮询(WRR)来实现该功能,首先在 Kubernetes 集群中部署上面的两个服务。

NGINX-server1服务的资源清单

appv1.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv1
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: appv1
  template:
    metadata:
      labels:
        use: test
        app: appv1
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: portv1

---

apiVersion: v1
kind: Service
metadata:
  name: appv1
  namespace: kube-system
spec:
  selector:
    app: appv1
  ports:
  - name: http
    port: 80
    targetPort: portv1

打开百度APP,查看更多高清图片

NGINX-server2服务的资源清单

appv1.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv2
  namespace: kube-system
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
  namespace: kube-system
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 -n kube-system
NAME                     READY   STATUS    RESTARTS   AGE
appv1-684f8cbc7-b9zm9    1/1     Running   0          2m27s
appv2-645d7666b5-qjrjs   1/1     Running   0          37s

ConfigMap 开启Provider

由于 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 动态更新配置:

......
      volumes:
      - name: config
        configMap:
          name: traefik-dynamic-conf
      containers:
      - image: traefik:v2.0.2
        name: traefik-ingress-lb
        volumeMounts:
        - name: config
          mountPath: /config
        ports:
        - name: web
          containerPort: 80
          hostPort: 80
        - name: admin
          containerPort: 8080
          hostPort: 8080
        args:
        - --entrypoints.web.Address=:80
        - --api.insecure=true
        - --providers.file.watch=true
        - --providers.file.filename=/config/traefik-dynamic.toml
        - --api
        - --api.debug=true
        - --api.dashboard=true
        - --accesslog

完整的 YAML 文件可以前往 https://github.com/cnych/kubeapp/tree/master/traefik2/canary 获取。

创建对应的 ConfigMap 对象

上面是开启File Provide的配置,接下来需要创建对应的 ConfigMap 对象,首先创建一个名为traefik-dynamic.toml的文件,内容如下所示:

[http]
  [http.routers]
    [http.routers.Router0]
      entryPoints = ["web"]
      service = "app"
      rule = "Host(`nginx.chuanzhi.com`)"

  [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/"

    [http.services.appv2]
      [http.services.appv2.loadBalancer]
        [[http.services.appv2.loadBalancer.servers]]
          url = "http://appv2/"

上面这个配置文件就是我们需要配置的灰度发布的规则

创建一个名为Router0的路由,在Web这个入口点上面监听Host=nginx.chuanzhi.com这样的请求,将请求路由给名为app的服务,而该服务则将请求路由给了appv1这个服务,权重为 3,另外一部分请求路由给了appv2这个服务,权重为 1,也就是有 34 的请求会被路由http://appv1/这个真实的服务上,这个地址也就是我们 Kubernetes 集群中的 appv1 这个 Service 对象的 FQDN 地址,当然我们也可以用全路径(http://appv1.kube-system.svc.cluster.local:80)表示,因为都在kube-system这个命名空间下面,所以直接用服务名也是可以的,同样的另外的 14 请求会被路由到http://appv2/这个真实的服务上。

现在通过上面的配置文件来创建对应的 ConfigMap 对象:

$ kubectl create configmap traefik-dynamic-conf --from-file=traefik-dynamic.toml -n kube-system

创建完成后,再更新 Traefik2.0,就可以将配置文件通过 ConfigMap 挂载到 Traefik Pod 的/config/traefik-dynamic.toml路径下面去了。

测试及日志分析

然后将域名nginx.chuanzhi.com解析到 Traefik 所在的 Pod,这个时候我们打开两个终端,分别去观察 appv1 和 appv2 两个应用的日志。

在浏览器中连续访问nginx.chuanzhi.com4 次,我们可以观察到 appv1 这应用会收到 3 次请求,而 appv2 这个应用只收到 1 次请求,符合上面我们的3:1的权重配置。

traefik2 wrr demo

不知道是否是 Traefik 的 BUG,同时将 KubernetesCRD Provider 和 File Provider 开启的时候,识别不了 File Provider 中的配置,该问题还有待验证。

在2.0.4 版本中测试通过支持crd 方式 金丝雀部署如下:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  creationTimestamp: '2019-11-06T15:53:21Z'
  generation: 1
  name: traefik-nginx
  namespace: default
spec:
  entryPoints:
    - web
  routes:
    - kind: Rule
      match: Host(`ng.101.101.244.212.nip.io`) && PathPrefix(`/`)
      services:
        - name: appv1
          port: 80
          weight: 3    # 权重
        - name: appv2
          port: 80
          weight: 1    # 权重

这种配置方式支持k8s的service服务发现

发布了638 篇原创文章 · 获赞 1184 · 访问量 159万+

猜你喜欢

转载自blog.csdn.net/itcast_cn/article/details/103524655