一、根据请求头匹配不同用户

开发一个网页或者应用时,往往会适配计算机端和手机端,通常会将移动客户端访问的页面重定向到移动端的服务上,一般m.xxx.com此类的域名,基本都属于移动端服务。

Nginx可以通过一个请求的请求头判断客户端来源,并将其路由到指定的服务上。下面演示把来自移动端的访问重定向到移动端服务,计算机端访问保持默认即可。

部署移动端

1.部署移动端应用

[root@k8s-master01 ~]# kubectl create deploy phone --image=registry.cn-hangzhou.aliyuncs.com/abroad_images/nginx:phone -n study-ingress

[root@k8s-master01 ~]# kubectl expose deploy phone --port 80 -n study-ingress

2.部署移动端Ingress 实例

[root@k8s-master01 ~]# vim phone-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: phone
  namespace: study-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: m.test.com
    http:
      paths:
      - backend:
         service:
           name: phone
           port:
             number: 80
        path: /
        pathType: Prefix

部署计算机端

1.部署计算机端应用

[root@k8s-master01 ~]# kubectl create deploy laptop --image=registry.cn-hangzhou.aliyuncs.com/abroad_images/nginx:laptop -n study-ingress

[root@k8s-master01 ~]# kubectl expose deploy laptop --port 80 -n study-ingress

2.部署计算机端Ingress 实例

编写yaml文件

[root@k8s-master01 ~]# vim laptop-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/server-snippet: |
      set $agentflag 0;
              if ($http_user_agent ~* "(Android|iPhone|Windows Phone|UC|Kindle)" ){
                set $agentflag 1;
              }
              if ( $agentflag = 1 ) {
                return 301 http://m.test.com;
              }
  name: laptop
  namespace: study-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: test.com
    http:
      paths:
      - backend:
         service:
           name: laptop
           port:
             number: 80
        path: /
        pathType: ImplementationSpecific

上面参数说明:

  • nginx.ingress.kubernetes.io/server-snippet: |: 这个注解设置一个自定义的Nginx配置片段。在这个配置片段中,根据请求的User-Agent进行了一些判断和重定向操作。下面的Nginx配置片段用于判断请求的User-Agent是否匹配指定的设备类型,如果匹配,则将请求重定向到http://m.test.com

更新Ingress 实例

[root@k8s-master01 ~]#  kubectl create -f laptop-ingress.yaml

测试访问

1.在windows主机上修改hosts文件,文件路径为:C:\Windows\System32\drivers\etc\hosts

10.0.0.22 nginx.test.com m.test.com test.com

2.打开浏览器,输入m.test.com访问移动端,可以看到页面内容是Access From Android|iPhone|Windows Phone|UC|Kindle

Ingress Nginx匹配请求头-区分手机端和PC端-1

输入test.com访问计算机端,可以看到页面内容是Access From Laptop

Ingress Nginx匹配请求头-区分手机端和PC端-2

此时按F12将终端类型改为 iPhone XR

Ingress Nginx匹配请求头-区分手机端和PC端-3

刷新浏览器,观察到网站由http://test.com/变为http://m.test.com/,页面内容变为Access From Android|iPhone|Windows Phone|UC|Kindle

Ingress Nginx匹配请求头-区分手机端和PC端-4

环境复原

# 删除ingress
k delete -f laptop-ingress.yaml -f phone-ingress.yaml

# 删除deploy
k delete deploy phone laptop -n study-ingress

# 删除svc
k delete svc phone laptop -n study-ingress

二、灰度/金丝雀发布

假设我们有两个命名空间,一个是正在使用的生产环境Production,另一个是用于灰度测试的Canary。在发布应用时,可以将应用先发布至Canary,然后切一部分流量到Canary,之后慢慢将流量全部切换到上面即可。

创建v1版本

1.先创建模拟 Production(生产)环境的 Namespace 和服务

[root@k8s-master01 ~]# kubectl create ns production
[root@k8s-master01 ~]# kubectl create deploy canary-v1 --image=registry.cn-hangzhou.aliyuncs.com/abroad_images/canary:v1 -n production
[root@k8s-master01 ~]# kubectl expose deploy canary-v1 --port 8080 -n production

创建完成服务后,查看服务,观察到服务已成功创建

[root@k8s-master01 ~]# kubectl get svc -n production
NAME        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
canary-v1   ClusterIP   10.0.239.16   <none>        8080/TCP   41s

2.创建Ingress

[root@k8s-master01 ~]# vim canary-v1-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-v1
  namespace: production
spec:
  ingressClassName: nginx
  rules:
  - host: canary.com
    http:
      paths:
      - backend:
         service:
           name: canary-v1
           port:
             number: 8080
        path: /
        pathType: Prefix

查看Ingress

[root@k8s-master01 ~]# kaf canary-v1-ingress.yaml

[root@k8s-master01 ~]# kubectl get ingress -n production
NAME        CLASS   HOSTS        ADDRESS   PORTS   AGE
canary-v1   nginx   canary.com             80      8s

3.在win主机上修改hosts文件,文件路径为:C:\Windows\System32\drivers\etc\hosts

10.0.0.22 canary.com

4.打开浏览器,输入canary.com后,显示Canary v1

使用 Nginx 实现灰度/金丝雀发布-1

当然你也可以选择一台主机进行测试

[root@k8s-master01 ~]# curl -H "Host:canary.com"  10.0.0.22
<h1>Canary v1</h1>

创建v2版本

上面创建完成v1版本后,接着创建v2版本来充当灰度环境

1.创建 v2 版本的命名空间、应用和 Service

[root@k8s-master01 ~]# kubectl create ns canary
[root@k8s-master01 ~]# kubectl create deploy canary-v2 --image=registry.cn-hangzhou.aliyuncs.com/abroad_images/canary:v2 -n canary
[root@k8s-master01 ~]# kubectl expose deploy canary-v2 --port 8080 -n canary

查看服务

[root@k8s-master01 ~]# kubectl get svc -n canary
NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
canary-v2   ClusterIP   10.0.76.59   <none>        8080/TCP   5s

2.访问服务,此时会返回 Canary v2

[root@k8s-master01 ~]# curl 10.0.76.59:8080
<h1>Canary v2</h1>

Canary版本切入部分流量

上面生产环境和灰度环境已经准备完毕后,此时需要做的就是把生产环境的流量切入到灰度环境。因此在创建v2 版本的 Ingress 时,添加注释,完成生产环境流量切入到灰度环境流量。

创建 v2 版本的 Ingress 时,需要添加两个注释,一个是nginx.ingress.kubernetes.io/canary , 表明是灰度环境,nginx.ingress.kubernetes.io/canary-weight 表明切多少流量到该环境,本示例为 10%

1.创建v2 版本的 Ingress

编写Ingress文件

[root@k8s-master01 ~]# vim canary-v2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
  name: canary-v2
  namespace: canary
spec:
  ingressClassName: nginx # for k8s >= 1.22+
  rules:
  - host: canary.com
    http:
      paths:
      - backend:
          service:
            name: canary-v2
            port:
              number: 8080
        path: /
        pathType: ImplementationSpecific

上面参数说明:

  • nginx.ingress.kubernetes.io/canary: "true":表示启用了金丝雀发布策略。
  • nginx.ingress.kubernetes.io/canary-weight: "10":表示新版本的金丝雀比例为 10%,即将 10% 的流量引导到此版本

创建该ingress

[root@k8s-master01 study-ingress]# kubectl create -f canary-v2.yaml

2.在k8s-master01主机上修改/etc/hosts文件,添加canary.com和192.168.1.35的映射关系

[root@k8s-master01 ~]# vim /etc/hosts
10.0.0.20 k8s-node02   nginx.test.com  canary.com

3.在k8s-master01主机上安装Ruby工具及编写 Ruby 脚本

安装 Ruby 工具

[root@k8s-master01 ~]# yum install ruby -y

编写 Ruby 脚本

[root@k8s-master01 ~]# vim test-canary.rb
counts = Hash.new(0)

100.times do
 output = `curl -s canary.com | grep 'Canary' | awk '{print $2}' | awk -F "<" '{print $1}'`
 counts[output.strip.split.last] += 1
end
puts counts

上面参数说明:

创建了一个名为 counts 的哈希表,用于存储统计结果。这个哈希表中的键(Key)是字符串,表示响应中的 'Canary' 字符串,值(Value)是整数,表示该字符串出现的次数。

counts = Hash.new(0)

使用循环,总共进行了 100 次 HTTP 请求。每次请求通过 curl 命令从 canary.com 网站获取内容,然后使用 grepawk 等命令提取响应中的 'Canary' 字符串,并将其存储在变量 output 中。

100.times do
 output = `curl -s canary.com | grep 'Canary' | awk '{print $2}' | awk -F "<" '{print $1}'`
 counts[output.strip.split.last] += 1
end

通过 output.strip.split.last,从 output 中获取到最后一个单词,并存储在哈希表 counts 中。如果响应中包含多个 'Canary' 字符串,那么就统计每个不同的字符串出现的次数。最后,将统计结果打印输出,显示不同的 'Canary' 字符串和它们出现的次数。

puts counts

4.使用 Ruby 脚本进行测试,此脚本会输出 v1 和 v2 的访问次数比值。观察到输出 v1 和 v2 的访问次数比值为9:1

[root@k8s-master01 ~]#  ruby test-canary.rb
{"v1"=>89, "v2"=>11}

环境清理

# 删除ingress
k delete -f canary-v2.yaml  -f canary-v1-ingress.yaml

# 删除deploy
k delete deploy canary-v1 -n production
k delete deploy canary-v2 -n canary

# 删除svc
k delete svc canary-v1 -n production
k delete svc canary-v2 -n canary