首页 > 系统相关 >Nginx基于cookies控制流量的灰度发布

Nginx基于cookies控制流量的灰度发布

时间:2024-09-04 13:53:29浏览次数:14  
标签:cookies name nginx header Nginx 灰度 proxy conf cookie

前言:

        因为公司业务发版需要进行灰度发布,基于一定的权重来指向用户流量到不同的版本应用中,这里用nginx的两种不同的方法来实现。

参考:

        nginx会话保持之sticky模块 - 天生帅才 - 博客园 (cnblogs.com)

方法一:利用Nginx-sticky

我将在这里介绍容器化的nginx配置,如果是主机部署的nginx则会简单点(需添加了sticky模块的nginx),下面可提供参考。

部署一个deployment并将配置文件挂载到对应configmap。镜像名为:runnable/sticky-nginx:v1.8.1

对应关系:

/etc/nginx/nginx.conf => nginx-conf(nginx.conf)

/etc/nginx/conf.d => conf-d(*.conf)

1.首先我们创建一个比较通用的nginx.conf配置文件内容的ConfigMap:

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-conf
  namespace: proxy
data:
  nginx.conf: |-
    # 设置工作进程数为 4。通常这个值设置为 CPU 核心数,但根据负载情况可以调整。
    worker_processes  4;

    # 将错误日志输出到标准错误流,以便容器化环境中能捕获和管理日志。
    error_log  /dev/stderr notice;

    events {
        # 设置每个工作进程的最大连接数为 1024。
        worker_connections  1024;
    }

    http {
        # 包含 mime.types 文件,该文件定义了各种文件扩展名和 MIME 类型的映射。
        include       mime.types;

        # 包含 conf.d 目录下的所有配置文件。方便分模块管理配置。
        include       conf.d/*.conf;

        # 设置默认的 MIME 类型为 application/octet-stream。用于未定义 MIME 类型的文件。
        default_type  application/octet-stream;

        # 启用 sendfile 选项,提高文件传输效率。
        sendfile        on;

        # 设置 keep-alive 超时时间为 65 秒。这个值可以根据需要调整。
        keepalive_timeout  65;

        # 定义日志格式,命名为 main。日志格式包含客户端 IP、用户信息、请求时间、请求行、响应状态、发送字节数、引用页面、用户代理、转发信息、Cookie 和上游服务器地址。
        log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for" "$http_cookie" => "$upstream_addr"';

        # 将访问日志输出到标准输出流,以便容器化环境中能捕获和管理日志。
        access_log /dev/stdout main;

        server {
            # 监听 80 端口。
            listen       80;

            # 设置服务器名称为 localhost。
            server_name  localhost;

            location / {
                # 设置网站根目录为 html。
                root   html;

                # 设置默认首页文件为 index.html 和 index.htm。
                index  index.html index.htm;
            }

            # 定义错误页面,当出现 500、502、503、504 错误时,重定向到 /50x.html。
            error_page   500 502 503 504  /50x.html;
            
            location = /50x.html {
                # 设置错误页面的根目录为 html。
                root   html;
            }
        }
    }

    # 禁用 Nginx 守护进程模式,使 Nginx 以前台模式运行。这在容器化环境中非常有用,可以确保日志输出到标准输出。
    daemon off;

2.再创建一个针对我们灰度发布所需要的配置文件内容的ConfigMap

kind: ConfigMap
apiVersion: v1
metadata:
  name: conf-d
  namespace: proxy
data:
  test-sticky.conf: |-
    upstream backend {
       sticky;    #使用sticky自动set-cookie来控制流量指向哪个后端,后面有介绍用法,默认可用此
       server your_backend_server1 weight=3; #30%流量到后端服务1
       server your_backend_server2  weight=7; #70%流量到后端服务2
       #可以通过权重来平滑过渡,因为是k8s容器部署的nginx,所以平滑度会比主机部署的nginx效果好一点,理论上用户是完全无感的。
    }
    server {
        listen 80;
        server_name your_domain.com;
        location ~/ {
            proxy_pass http://backend;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host $host;
        }
    }

3.创建Nginx  Deployment

kind: Deployment
apiVersion: apps/v1
metadata:
  name: nginx-sticky
  namespace: proxy
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      volumes:
        - name: nginx-conf
          configMap:
            name: conf-d #configmap名对应的是目录
            items:
              - key: test.conf
                path: ./test.conf
            defaultMode: 420
        - name: nginx-conf-d
          configMap:
            name: nginx-conf #configmap名对应的是文件
            defaultMode: 420
      containers:
        - name: nginx
          image: 'runnable/sticky-nginx:v1.8.1'
          ports:
            - name: http-0
              containerPort: 80
              protocol: TCP
          resources: {}
          volumeMounts:
            - name: nginx-conf
              readOnly: true
              mountPath: /etc/nginx/conf.d
            - name: nginx-conf-d
              readOnly: true
              mountPath: /etc/nginx/nginx.conf
              subPath: nginx.conf
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: IfNotPresent
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirst
      serviceAccountName: default
      serviceAccount: default
      securityContext: {}
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  revisionHistoryLimit: 10
  progressDeadlineSeconds: 600

 部署好Nginx容器后我们可以做出尝试。

4.效果如图

5.sticky的更多配置

# 参数,解析

sticky [name=route] [domain=.foo.bar] [path=/] [expires=1h] 
       [hash=index|md5|sha1] [no_fallback] [secure] [httponly];
[name]       设置用来记录会话的cookie名称 默认是route
[domain=.foo.bar]    设置cookie作用的域名
[path=/]          设置cookie作用的URL路径,默认根目录
[expires=1h]        设置cookie的生存期,默认不设置,浏览器关闭即失效,需要是大于1秒的值
[hash=index|md5|sha1]   设置cookie中服务器的标识是用明文还是使用md5值,默认使用md5
[no_fallback]       设置该项,当sticky的后端机器挂了以后,nginx返回502 (Bad Gateway or Proxy Error) ,而不转发到其他服务器,不建议设置
[secure]          设置启用安全的cookie,需要HTTPS支持
[httponly]         允许cookie不通过JS泄漏,没用过


方法二:利用逻辑判断来控制cookie的办法 

我们可以利用nginx的if语句和add_header来进行配置。

我们通过正则判断cookies是否含有我们的关键cookie信息,要注意正则判断容易出现的涵盖情况(这里我踩过一个问题,例如我需要鉴别router=a或router=ab,if判断a的时候,前者成立,if判断ab,两者都成立(因为是判断"始于"),所以可以注意if判断顺序或正则表达再精确点。)

# 定义两个上游服务器,分别是 webserver1 和 webserver2
upstream webserver1 {
    server 192.168.66.1;
}

upstream webserver2 {
    server 192.168.2.1;
}

# 使用map来定义后端目标
map $http_cookie $route_cookie {
    default "";
    "~*route=webserver1" "webserver1";
    "~*route=webserver2" "webserver2";
}

# 使用时间字符串来进行伪随机流量划分,70% 的流量转发到 webserver1,30% 的流量转发到 webserver2
split_clients "${date_gmt}" $route_cookie_endpoint {
    70%    "webserver1";
    30%    "webserver2";
}

server {
    listen 80;
    server_name your_domain.com; # 监听域名

    location / {
        # 如果请求中没有包含名为 "route" 的 cookie,则添加一个新的 cookie,并根据流量划分规则设置后端服务器
        if ($route_cookie = "" ) {
            set $route_cookie $route_cookie_endpoint;
            add_header Set-Cookie "route=$route_cookie; Path=/; Max-Age=3600;" always;
        }

        # 根据正则判断,将请求转发到相应的上游服务器
        if ($route_cookie = "webserver1") {
            proxy_pass http://webserver1;
        }

        if ($route_cookie = "webserver2") {
            proxy_pass http://webserver2;
        }

        # 设置代理相关的头部信息
        proxy_set_header Accept-Encoding "gzip";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_read_timeout 7200s;
        proxy_send_timeout 7200s;
        proxy_next_upstream error timeout invalid_header http_502 http_503 http_504;
        proxy_next_upstream_tries 5;
        
        # 添加 CORS 支持
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,X-Version,clienttoken,x-timestamp,X-Sign,tenant-id,x-access-token,X-Token,storeid,contenttype';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
    }
}

配置解析:

1.首先我定义了两个版本的应用为webserver1 和webserver2,在此基础上可以增加更多的服务器再控制权重来达到负载均衡。

2.使用map提取出cookies中我们会被灰度命中的cookie,如果没有则为空。

3.使用split_clients函数和date_gmt变量来实现伪随机的效果(nginx默认应该没有真随机的函数)

4.通过三个判断,第一个判断是否为空,空则伪随机分配并设置好相应cookie;第二个第三个则根据cookie来控制流量的版本指向;


文章写的比较粗糙,如果有其他问题欢迎交流讨论啦。

标签:cookies,name,nginx,header,Nginx,灰度,proxy,conf,cookie
From: https://blog.csdn.net/Matthewmq/article/details/141865830

相关文章

  • nginx部署前端项目 (Linux版)
    目录一:nginx部署前端项目(Windows版)二:下载相关依赖三:下载安装nginx四:启动nginx五:部署前端项目一:nginx部署前端项目(Windows版)nginx部署前端项目(Windows版本)二:下载相关依赖yuminstall-ygcc-c++pcrepcre-develzlibzlib-developensslopen......
  • Nginx 【limit_conn_zone】指令简介
    【limit_conn_zone】是Nginx中的一个指令,用于限制特定IP地址或IP地址段的并发连接数,这个指令可以帮助我们防止恶意用户通过大量连接来消耗服务器资源,从而保证正常用户的访问速度和体验,本文将详细介绍【limit_conn_zone】指令的使用方法和相关问题解答。一、【limit_conn_zone】指......
  • Nginx $remote_addr和$proxy_add_x_forwarded_for变量的实现
    $remote_addr代表客户端IP。注意,这里的客户端指的是直接请求Nginx的客户端,非间接请求的客户端。假设用户请求过程如下:用户客户端--发送请求->Nginx1--转发请求-->Nginx2->后端服务器那么,默认情况下,针对Nginx1而言,$remote_addr为用户客户端IP,对Nginx2而言,$remote_addr则为Ngi......
  • Nginx中的limit_req模块和limit_conn模块详解
    引言在高流量场景下,良好的限流和连接控制策略至关重要,以防止服务器过载,确保服务稳定性和高可用性。Nginx提供了limit_req和limit_conn模块,用以实现请求频率和并发连接数的限制。本文将详细介绍这两个模块的生效阶段和生效范围,并提供实际配置示例,解释相关指令的作用。limit_re......
  • Nginx中的 限流和屏敝版本号
    server{location/{#应用请求频率限制配置limit_req模块用于限制客户端请求的频率,以防止单一客户端占用过多服务器资源,提升稳定性。#zone=one引用名为"one"的共享内存区域#burst=10允许短时间内突发最多10个请求#nodela......
  • 前端Vue项目iHRM人力资源后台管理从Vue模板到整体开发Nginx部署上线
    前端Vue项目iHRM人力资源后台管理:‌从Vue模板到整体开发Nginx部署上线引言随着企业信息化的不断深入,‌人力资源管理系统的自动化和智能化成为企业提升管理效率的重要手段。‌本文将详细介绍一个基于Vue.js开发的人力资源后台管理系统(‌iHRM)‌的完整开发流程,‌包括从Vue模板的选......
  • Nginx:长短连接
    g学习自:通过nginx理解什么是长连接和短连接-寻梦99-博客园 0、前言C/S通信连接分为短连接、长连接。HTTP请求、响应通常采用短连接。TCP通信可以根据需要选择短连接、长连接。长连接C端和S端建立持久连接,用于传输多个请求、响应。在一次连接中,可以进行多次通信而无......
  • Vue3+NestJS+Vite4+TS4+Mysql8+Nginx全栈开发企业级管理后台
    vite打包快的原因:冷启动1.esbuild构建依赖,go语言编写多线程打包。2.原生的esm方式提供源码,浏览器分担了一部分工作。HMR热更新1.缓存机制,利用浏览器http头部,源码模块请求根据304协商缓存和依赖模块请求通过强缓存(cache-control:max-age=315360000,public,immutable)只是模块......
  • nginx部署前端vue项目
    Nginx部署前端Vue项目的技术分析引言在现代Web开发中,Vue.js作为一种流行的前端框架,被广泛应用于构建单页面应用(SPA)。然而,将Vue项目部署到生产环境时,通常需要依赖一个高效的Web服务器来提供服务。Nginx,作为一个高性能的HTTP和反向代理服务器,因其稳定性、易用性和丰富的功能特......
  • nginx服务器如何配置多虚拟站点及其它
    nginx服务器如何配置多虚拟站点,操作如下:1、配置文件目录:除了nginx服务器根目录下的nginx.conf文件外,其它多站点一般配置在目录"conf/vhost"下,演示如下:目录图:目录列表图:站点配置文件以“.conf”为后缀,名称一般按域名来起就可以了,多站点创建不同的.conf文件。2、配置站点,......