【k8s】ingress-nginx通过header路由到不同后端

K8S中ingress-nginx通过header路由到不同后端

背景
  • 公司使用ingress-nginx作为网关的项目,需要在相同域名、uri,根据header将请求转发到不同的后端中
  • 在稳定发布的情况下,ingress-nginx是没有语法直接支持根据header做转发的。但是这个可以利用灰度发布的特性实现header路由功能
准备
  • 准备两个后端,后端代码如下,路由均为 /app
    • main.go
go 复制代码
package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/app", func(context *gin.Context) {
		context.JSON(200, gin.H{"message": "app1"})
	})
	r.Run(":8080")
}
  • 使用Dockerfile构建镜像
    • 这里构建 goapp1:v1,goapp2:v1两个镜像(goapp2请将main.go修改 "message": "app2")

      FROM golang:1.17.13
      RUN mkdir -p /go/app/;
      cd /go/app/;
      go mod init app1;
      GOPROXY="https://goproxy.cn,direct" go get github.com/gin-gonic/gin@v1.6.3
      WORKDIR /go/app/
      COPY main.go /go/app
      EXPOSE 8080
      CMD go run main.go

使用灰度发布的特性进行header的路由
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goapp1
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: goapp1
  template:
    metadata:
      labels:
        app: goapp1
    spec:
      containers:
      - image: goapp1:v1
        imagePullPolicy: IfNotPresent
        name: goapp1
        ports:
        - containerPort: 80
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: goapp1
  namespace: default
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: goapp1
  • 部署稳定发布版本的ingress,路由至goapp1
yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: goapp1 
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: test.com
    http:
      paths:
      - path: /app 
        pathType: Prefix
        backend:
          service:
            name: goapp1
            port: 
              number: 8080
yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: goapp2
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: canary
spec:
  rules:
  - host: test.com
    http:
      paths:
      - path: /app 
        pathType: Prefix
        backend:
          service:
            name: goapp2
            port: 
              number: 8080
  • 进行测试
bash 复制代码
for i in {1..20};
  # ingress-nginx的NodePort请自行查看,替换下面的端口
  do curl test.com:31132/app -H "canary: never"; # 路由至稳定版本的goapp1
  echo -e "";
done
bash 复制代码
for i in {1..20};
  do curl test.com:31132/app -H "canary: always"; # 路由至canary版本的goapp2
  echo -e "";
done
  • 效果如下,可以看到可以通过header控制发送请求到不同后端,能够满足需求
通过nginx进行转发
  • 第二种方法可通过在k8s集群部署一个nginx, 通过nginx进行分流
    • 流量路径如下: ingress-nginx --> nginx --> goapp1或goapp2
  • 这里nginx写法有比较多,我选择最简单的通过if判断$http_my_header
  • 在使用$http_my_header之前,需要对ingress-nginx和nginx添加参数,允许header中存在下划线
    • ingress-nginx
bash 复制代码
kubectl edit cm ingress-nginx-controller
------------------
apiVersion: v1
data:
  allow-snippet-annotations: "true"
  # 添加下面这两个参数
  enable-underscores-in-headers: "true"
  ignore-invalid-headers: "false"
kind: ConfigMap
  • 部署nginx,nginx中开启允许header下划线的参数:underscores_in_headers on;
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.24.0
        ports:
        - containerPort: 80
        volumeMounts:
          - name: nginx
            mountPath: /etc/nginx/nginx.conf
            subPath: nginx.conf
      volumes:
        - name: nginx
          configMap:
            name: nginx
            items:
            - key: nginx.conf
              path: nginx.conf
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
---
apiVersion: v1
data:
  nginx.conf: |
    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
    
        upstream upstream_server1 {
            server goapp1:8080;
        }
    
        upstream upstream_server2 {
            server goapp2:8080;
        }
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" "$http_my_header"';
    
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
    
        keepalive_timeout  65;
    
        server {
            underscores_in_headers on; 
            listen 80;
            server_name test.com;
    
            location /app {
              if ($http_my_header = "value1") {
                  proxy_pass http://upstream_server1;
              }
              if ($http_my_header = "value2") {
                  proxy_pass http://upstream_server2;
              }
            }
        }
    
    }

kind: ConfigMap
metadata:
  name: nginx
  namespace: default
  • 上面的配置判断 $http_my_header是 value1 还是 value2,再转发到不同的upstream
  • 测试
bash 复制代码
curl test.com/app -H "my_header:value1"
curl test.com/app -H "my_header:value2"
相关推荐
€☞扫地僧☜€1 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
全能全知者2 小时前
docker快速安装与配置mongoDB
mongodb·docker·容器
ajsbxi8 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
景天科技苑8 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
wclass-zhengge9 小时前
K8S篇(基本介绍)
云原生·容器·kubernetes
颜淡慕潇9 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
川石课堂软件测试11 小时前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
昌sit!17 小时前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
A ?Charis20 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab
wclass-zhengge20 小时前
Docker篇(Docker Compose)
运维·docker·容器