前言:
因为公司业务发版需要进行灰度发布,基于一定的权重来指向用户流量到不同的版本应用中,这里用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