灰度发布专题---3、Nginx+Lua灰度发布

上一章已经讲解了配置文件灰度发布、应用版本灰度发布、API网关灰度发布实现,但如果用户这时候在代理层如何做灰度发布呢?

代理层灰度发布分析

用户无论访问应用服务还是静态页,都要经过Nginx代理层,我们可以在Nginx这里做灰度发布,这里的灰度发布可以分为静态页灰度发布和应用动态发布,

如上图:动态服务灰度发布IP/ID切流:

  • zhangsan、wangwu使用A应用
  • zhaoliu使用B应用
  • 192.168.211.1/192.168.211.2 IP的用户使用A应用
  • 192.168.211.3 IP的用户使用B应用

静态资源灰度发布IP/ID切流:

  • zhangsan、wangwu访问静态页,使用/usr/bj目录下的静态页
  • zhaoliu访问静态页,使用/usr/tj目录下的静态页
  • 192.168.211.1/192.168.211.2 IP的用户使用/usr/sz目录下的静态页

IP分流灰度发布

我们为了测试系统,通常把公司内部IP设置为测试IP,也就是使用灰度系统的IP,此时内部员工测试直接访问服务器即可,但是访问服务器又分为静态资源访问和动态服务访问,都有不同的实现策略。在代理层实现灰度发布,可以采用Nginx+Lua实现。

动态服务灰度发布

IP切流动态服务灰度发布方式的实现要借助Nginx+Lua和Redis了,我们可以先把公司内部的IP全部存储在Redis缓存中,当用户访问系统的时候,先通过Lua脚本根据IP查询Redis缓存,如果Redis缓存数据存在就表明使用灰度系统,如果没有缓存则使用稳定版系统。

IP切流步骤如上图:

  1. IP校验
    在服务器上创建lua脚本文件/usr/local/openresty/nginx/lua/loadip.lua:
bash 复制代码
--客户端
IPlocal headers=ngx.req.get_headers()
local ip=headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or 
ngx.var.remote_addr or "0.0.0.0"
--local ip = "192.168.211.1"

--引入redis依赖
local redis = require("resty.redis");
local red = redis:new()
red:set_timeout(2000)
red:connect("192.168.211.142", 6379)
--执行查询
local grayresult=red:get(ip);
red:close()

if grayresult==nil or grayresult==nil or grayresult==ngx.null then 
--没有数据则查询主服务 
ngx.var.upstream = "sys"
else 
--如果有数据,则查询灰度服务 
ngx.var.upstream = "gray"
end
  1. Nginx控制配置:
    修改nginx.conf配置如下:

    上图代码如下:
bash 复制代码
#灰度系统负载均衡池
upstream gray { 
server 192.168.211.1:18082;
}
#稳定系统负载均衡池
upstream sys { 
server 192.168.1.5:18081;
}
server {    
listen       80;    
server_name localhost;    
#charset koi8-r;    
#access_log logs/host.access.log main;
#所有动态请求    
location / {        
#设置负载均衡池        
set $upstream '';        
#查找负载均衡池        
access_by_lua_file /usr/local/openresty/nginx/lua/loadip.lua;        
#反向代理        
proxy_pass http://$upstream;   
}
}
  1. 效果测试

    在Redis中添加IP 192.168.211.1,访问时会走灰度发布系统,把IP删除会走稳定系统。

静态资源灰度发布

我们把稳定静态资源和灰度静态页资源分别放在了 /usr/local/openresty/nginx/static1/ 和 /usr/local/openresty/nginx/static2/目录下,我们要求公司员工IP访问灰度发布的静态页, 非公司员工IP访问稳定版本页面,这里又需要用到指定IP查询了。

创建 home.lua脚本如下:

bash 复制代码
--客户端IP 
local headers=ngx.req.get_headers() 
local ip=headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr or "0.0.0.0" 
--local ip = "192.168.211.1" 
--引入redis依赖 
local redis = require("resty.redis"); 
local red = redis:new() 
red:set_timeout(2000) 
red:connect("192.168.211.142", 6379) 
--执行查询 
local grayresult=red:get(ip); 
red:close() 
if grayresult==nil or grayresult==nil or grayresult==ngx.null then --没有数据则查询主服务 
ngx.var.homepath = "/usr/local/openresty/nginx/static1/" 
else 
--如果有数据,则查询灰度服务 
ngx.var.homepath = "/usr/local/openresty/nginx/static2/" 
end

nginx.conf配置如下:图片、静态页、样式、脚本,我们都进行灰度发布,如下配合

bash 复制代码
#静态资源 
location ~* \.(jpg|png|html|css|js|woff|ttf|woff2) { 
#静态资源路径设置 
set $homepath ''; 
#lua脚本校验使用静态资源 
access_by_lua_file /usr/local/openresty/nginx/lua/home.lua; #静态资源root配置 
root $homepath; 
} 

ID切流灰度发布

现在的项目大多数已经是微服务项目,而微服务项目几乎都是前天传递JWT令牌到后台,要想实现ID切 流,我们需要在代理层识别用户身份(JWT令牌),我们需要引入 lua-resty-jwt模块,是用于 ngx_lua 和 LuaJIT 的 Lua 实现库,在该模块能实现Jwt令牌生成、Jwt令牌校验,依赖库的地址:http s://github.com/SkyLothar/lua-resty-jwt。

JWT令牌识别库安装

将下载好了该依赖库 lua-resty-jwt-master.zip,我们将该库文件上传到服务器上,并解压,当然,我 们也可以使用opm直接安装 lua-resty-jwt,配置 lua-resty-jwt之前,我们需要先安装resty和 opm。

安装仓库管理工具包:

bash 复制代码
yum install yum-utils 

添加仓库地址:

bash 复制代码
yum-config-manager --add-repo 
https://openresty.org/package/centos/openresty.repo 

安装resty:

bash 复制代码
yum install openresty-resty 

安装opm:

bash 复制代码
yum install openresty-opm 

安装Jwt组件:

bash 复制代码
opm get SkyLothar/lua-resty-jwt 

此时 lua-resty-jwt安装好了,可以直接使用了。

ID识别

我们先利用 lua-resty-jwt生成令牌,再解析令牌 创建 make.lua用于生成令牌:

bash 复制代码
ngx.header.content_type="application/json;charset=utf8" local cjson = require "cjson" 
local jwt = require "resty.jwt" 
--生成令牌 
--lua-resty-jwt为秘钥 
local jwt_token = jwt:sign( 
"lua-resty-jwt", 
{ 
header={typ="JWT", alg="HS256"}, 
payload={name="zhangsan"} 
} 
) 
ngx.say(jwt_token) 

创建 token.lua用户校验令牌:

bash 复制代码
local cjson = require "cjson" 
local jwt = require "resty.jwt" 
--获取请求头中的令牌数据 
local auth_header = ngx.var.http_Authorization 
local jwt_obj = jwt:verify("lua-resty-jwt", auth_header) ngx.say(cjson.encode(jwt_obj)) 

nginx.conf配置如下:

bash 复制代码
#校验令牌 
location /check { 
content_by_lua_file /usr/local/openresty/nginx/lua/token.lua; } 
#生成令牌 
location /token { 
content_by_lua_file /usr/local/openresty/nginx/lua/make.lua; } 

生成令牌:http://192.168.211.142/token

bash 复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.VxhQcGihWyHuJeHhpUiq2FU7 aW2s_3ZJlY6h1kdlmJY 

校验令牌:http://192.168.211.142/check

ID切流实现

结合上面JWT令牌识别,可以编写一个ID切流的流程,我们这里假设是zhangsan用户就访问灰度版本, 其他用户访问稳定版本,创建id.lua如下代码:

bash 复制代码
local cjson = require "cjson" 
local jwt = require "resty.jwt" 
--获取请求头中的令牌数据 
local auth_header = ngx.var.http_Authorization 
local jwt_obj = jwt:verify("lua-resty-jwt", auth_header) --解析的用户名 
local username = jwt_obj["payload"]["name"] 
if username=="zhangsan" then 
--没有数据则查询主服务 
ngx.var.idpath = "/usr/local/openresty/nginx/static1/" 
else
--如果有数据,则查询灰度服务 
ngx.var.idpath = "/usr/local/openresty/nginx/static2/" 
end

nginx.conf修改配置如下:

bash 复制代码
#ID切流 
location =/1.html { 
#静态资源路径设置 
set $idpath ''; 
#lua脚本校验使用静态资源 
access_by_lua_file /usr/local/openresty/nginx/lua/id.lua; #静态资源root配置 
root $idpath; 
} 
相关推荐
Ewen Seong5 小时前
Nginx系列-9 set和变量和if指令
运维·nginx
Ewen Seong7 小时前
Nginx系列-4 proxy_pass使用和路径拼接问题
运维·nginx
程序猿阿伟10 小时前
Lua 中的元表(Metatable)在实际开发中的高级应用场景有哪些?
开发语言·lua
逍康19 小时前
Nginx部署前端项目尝试 - windows版
前端·nginx
TOMORROW6COME1 天前
LVS+Nginx高可用集群---搭建高可用集群负载均衡
nginx·负载均衡·lvs
是小赵鸭.1 天前
云计算实训07——本地yum源及网络yum源配置、nginx源安装配置、自建yum源仓库、安装createrepo制作仓库软件
linux·nginx·云计算
Evan_su1 天前
Redis中lua脚本和pipeline的区别
redis·lua
R2024712 天前
Linux安装nginx
linux·nginx
节奏昂2 天前
服务器上有多个nginx,如何知道启动的是哪个?
服务器·nginx
冲鸭,牛码2 天前
Redis入门,Idea操作Redis
java·数据库·redis·分布式·缓存·消息队列·lua