k8s

通过nginx-ingress实现灰度/蓝绿发布

前言

上篇文章我们介绍了如何通过service来原生实现简单的灰度/蓝绿发布,这篇文章就来介绍一下如何通过nginx-ingress实现灰度/蓝绿发布。

实现方式

nginx-ingress controller通过增加annotation来实现不同场景的灰度/蓝绿发布。有两种annotation的方式:

  • canary-*:是社区官方实现的灰度发布方式。
  • service-*:早期的实现方式,现在不怎么用了。

canary-*

一共有以下几种annotation,包括header,cookie,weight。

  • nginx.ingress.kubernetes.io/canary
    必须设置该Annotation值为true,否则其它规则将不会生效
  • nginx.ingress.kubernetes.io/canary-by-header
    • 适用于灰度发布以及 A/B 测试。
    • 表示基于请求头的名称进行灰度发布。
    • 值为always:无论什么情况下,流量均会进入灰度服务。
    • 值为never:无论什么情况下,流量均不会进入灰度服务。
    • 若没有指定请求头名称的值,则只要该头存在,都会进行流量转发。
  • nginx.ingress.kubernetes.io/canary-by-header-value
    • 用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务。
    • 表示基于请求头的值进行灰度发布。
    • 需要与canary-by-header头配合使用。
  • nginx.ingress.kubernetes.io/canary-by-header-pattern
    • 表示基于请求头的值进行灰度发布,并对请求头的值进行正则匹配。
    • 需要与canary-by-header头配合使用。
  • nginx.ingress.kubernetes.io/canary-by-cookie
    • 适用于灰度发布与 A/B 测试。
    • 表示基于Cookie进行灰度发布。
    • 值为always:无论什么情况下,流量均会进入灰度服务。
    • 值为never:无论什么情况下,流量均不会进入灰度服务。
    • 只要存在该Cookie名称,都会进行流量转发。
  • nginx.ingress.kubernetes.io/canary-weight
    • 适用于蓝绿部署。
    • 表示基于权重进行灰度发布。
    • 取值范围:0~权重总值。
    • 若未设定总值,默认总值为100。
  • nginx.ingress.kubernetes.io/canary-weight-total
    • 表示设定的权重总值。
    • 若未设定总值,默认总值为100。

优先级

canary-by-header>canary-by-cookie>canary-weight。

目前每个Ingress规则只支持同时指定一个Canary Ingress,大于一个的Canary Ingress将会被忽略。

应用场景

基于header

  1. 假设当前环境已经有一套服务Service A对外提供7层服务,此时上线了一些新的特性,需要发布上线一个新的版本Service A’。
  2. 但又不想直接替换Service A服务,而是希望将请求头中包含foo=bar或者Cookie中包含foo=bar的客户端请求转发到Service A’服务中。
  3. 待运行一段时间稳定后,可将所有的流量从Service A切换到Service A’服务中,再平滑地将Service A服务下线。
    file

基于weight

  1. 假设当前环境已经有一套服务Service B对外提供7层服务,此时上线了一些新的特性,需要发布上线一个新的版本Service B’。
  2. 但又不想将所有客户端流量切换到新版本Service B’中,而是希望将20%的流量切换到新版本Service B’中。
  3. 待运行一段时间稳定后,再将所有的流量从Service B切换到Service B’服务中,再平滑地将Service B服务下线。
    file

实例

1.部署服务

参考这里的部署两个版本的nignx章节

cat oldsvc.yaml
apiVersion: v1
kind: Service
metadata:
  name: old-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
    version: v1
  type: ClusterIP
---
cat newsvc.yaml
apiVersion: v1
kind: Service
metadata:
  name: new-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
    version: v2
  type: ClusterIP

file

2.创建old-ingress

cat old-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: old-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: www.nginx.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: old-nginx
            port:
              number: 80
        pathType: ImplementationSpecific

file

2.1测试访问

我的ingress是没有loadbalancer的,采用的NodePort方式,所以ingress的地址就是本机网卡地址。

k get svc -n ingress
ip a | grep eth0
curl -H "Host: www.nginx.com" http://172.17.88.228:30080

file

3.1创建基于header的new-ingress

当header中包含foo=bar的请求才能路由到新版本服务。

cat new-ingress-header.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: new-ingress-header
  annotations:
    # 开启Canary。
    nginx.ingress.kubernetes.io/canary: "true"
    # 请求头为foo。
    nginx.ingress.kubernetes.io/canary-by-header: "foo"
    # 请求头foo的值为bar时,请求才会被路由到新版本服务new-nginx中。
    nginx.ingress.kubernetes.io/canary-by-header-value: "bar"
spec:
  ingressClassName: nginx
  rules:
  - host: www.nginx.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: new-nginx
            port:
              number: 80
        pathType: ImplementationSpecific

file

3.2测试访问

curl -H "Host: www.nginx.com" http://172.17.88.228:30080
curl -H "Host: www.nginx.com" -H "foo: bar" http://172.17.88.228:30080

file

4.1创建基于weight的new-ingress

header中包含foo=bar的请求,只允许50%的流量被路由到新版本服务中。

cat new-ingress-weight.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: new-ingress-weight
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "foo"
    nginx.ingress.kubernetes.io/canary-by-header-value: "bar"
    # 在满足foo=bar的基础上仅允许50%的流量会被路由到新版本服务new-nginx中。
    nginx.ingress.kubernetes.io/canary-weight: "50"
spec:
  ingressClassName: nginx
  rules:
  - host: www.nginx.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: new-nginx
            port:
              number: 80
        pathType: ImplementationSpecific

file

4.2测试访问

curl -H "Host: www.nginx.com" http://172.17.88.228:30080
curl -H "Host: www.nginx.com" -H "foo: bar" http://172.17.88.228:30080

file

5.1创建仅weight的ingress

仅50%的流量被路由到新版本服务中。

cat weight-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: weight-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "50"
spec:
  ingressClassName: nginx
  rules:
  - host: www.nginx.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: new-nginx
            port:
              number: 80
        pathType: ImplementationSpecific

file

5.2测试访问

k delete -f new-ingress-header.yaml
k delete -f new-ingress-weight.yaml
curl -H "Host: www.nginx.com" http://172.17.88.228:30080

file

6.删除老版本服务

系统运行一段时间后,当新版本服务已经稳定并且符合预期后,需要下线老版本的服务 ,仅保留新版本服务在线上运行。为了达到该目标,需要将旧版本的Service指向新版本服务的Deployment,并且删除旧版本的Deployment和新版本的Service。

6.1替换old-svc指向new-nginx

k patch svc old-nginx -p '{"spec":{"selector":{"version":"v2"}}}'

file

6.2测试访问

可以看到请求全部被路由到了新版本的服务。

curl -H "Host: www.nginx.com" http://172.17.88.228:30080

file

6.3删除old-ingress,old-deploy,new-svc

k delete -f weight-ingress.yaml
k delete -f old-nginx.yaml
k delete -f newsvc.yaml
k get po,svc | grep nginx
k get ing

file

分类: k8s
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x