一、部署环境
系统 | IP 地址 | 主机名 | 软件 |
CentOS 7.9 | 192.168.15.201 | cen01 | openresty-1.21.4.3 |
CentOS 7.9 | 192.168.15.202 | cen02 | 开机即可 |
二、安装 OpenResty
1. 安装依赖及工具
[root@cen01 ~]# yum -y install readline-devel pcre-devel openssl-devel gcc make git
2. 编译安装 OpenResty
[root@cen01 ~]# wget https://openresty.org/download/openresty-1.21.4.3.tar.gz
[root@cen01 ~]# tar -xf openresty-1.21.4.3.tar.gz -C /usr/local/src/
[root@cen01 ~]# cd /usr/local/src/openresty-1.21.4.3
[root@cen01 openresty-1.21.4.3]# ./configure && make && make install # 预配置及编译安装
[root@cen01 openresty-1.21.4.3]# cd /usr/local/openresty
[root@cen01 openresty]# cd nginx/sbin
[root@cen01 sbin]# ./nginx
3. 测试访问页面
地址:本机 IP+80 端口
三、WAF 防火墙模块
1. 安装 WAF
[root@cen01 sbin]# cd
[root@cen01 ~]# git clone https://github.com/unixhot/waf.git
正克隆到 'waf'...
remote: Enumerating objects: 103, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 103 (delta 3), reused 9 (delta 2), pack-reused 89
接收对象中: 100% (103/103), 30.07 KiB | 0 bytes/s, done.
处理 delta 中: 100% (36/36), done.
[root@cen01 ~]# cp -r ./waf/waf/ /usr/local/openresty/nginx/conf/
2. 引入 WAF 模块
[root@cen01 ~]# vim /usr/local/openresty/nginx/conf/nginx.conf
25 #access_log logs/access.log main;
26 lua_shared_dict limit 50m; # 插入26~29行至nginx配置文件
27 lua_package_path "/usr/local/openresty/nginx/conf/waf/?.lua";
28 init_by_lua_file "/usr/local/openresty/nginx/conf/waf/init.lua";
29 access_by_lua_file "/usr/local/openresty/nginx/conf/waf/access.lua";
30 sendfile on;
[root@cen01 ~]# ln -s /usr/local/openresty/lualib/resty/ /usr/local/openresty/nginx/conf/waf/resty
[root@cen01 ~]# /usr/local/openresty/nginx/sbin/nginx -t # 检查nginx配置文件
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
[root@cen01 ~]# /usr/local/openresty/nginx/sbin/nginx -s stop
[root@cen01 ~]# /usr/local/openresty/nginx/sbin/nginx
[root@cen01 ~]# netstat -anpt | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 63183/nginx: master
3. 访问测试
本地 IP/.sql
四、结合 redis 实现灰度发布
1. Redis 配置
安装 redis 略
[root@cen01 ~]# vim /usr/local/redis/redis.conf
87 bind 0.0.0.0
111 protected-mode no
138 port 6379
309 daemonize yes
341 pidfile "redis.pid"
354 logfile "redis.log"
504 dir /usr/local/redis
1036 requirepass 123456
[root@cen01 ~]# /usr/local/redis/redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set 192.168.15.201 192.168.15.201 # 将本机IP添加到redis数据库缓存内,使得本机IP为接受灰度发布的用户
OK
127.0.0.1:6379> exit
2. Nginx 配置
[root@cen01 ~]# vim /usr/local/openresty/nginx/conf/nginx.conf
....
17 http {
18 include mime.types;
19 default_type application/octet-stream;
20
21 #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
22 # '$status $body_bytes_sent "$http_referer" '
23 # '"$http_user_agent" "$http_x_forwarded_for"';
24
25 #access_log logs/access.log main;
26 #lua_shared_dict limit 50m;
27 lua_package_path "/usr/local/openresty/lualib/?.lua;;"; # 修改或添加此行,加载lualib库的lua脚本
28 lua_package_cpath "/usr/local/openresty/lualib/?.so;;"; # 修改或添加此行,加载so脚本
29 #init_by_lua_file "/usr/local/openresty/nginx/conf/waf/init.lua";
30 #access_by_lua_file "/usr/local/openresty/nginx/conf/waf/access.lua";
31 sendfile on;
32 #tcp_nopush on;
33
34 #keepalive_timeout 0;
35 keepalive_timeout 65;
36 charset utf-8;
37
38 #gzip on;
39 upstream prod1 { # 设置七层负载均衡服务器组,组名prod1
40 server 192.168.15.201:5001;
41 }
42
43 upstream prod2 { # 服务器组,组名prod2
44 server 192.168.15.201:5000;
45 }
46
47 server {
48 listen 80;
49 server_name localhost;
50
51
52 #access_log logs/host.access.log main;
53
54 location / {
55 content_by_lua_file /usr/local/openresty/nginx/lua/gray.lua; # 为每一个请求执行gray.lua脚本
56 }
57
58 location @prod1 { # @表示分隔符,类似“/”,但该location不可被外部客户端访问,可以用“/”,但生产环境使用灰度发布还是得用@
59 proxy_pass http://prod1; # 反向代理,代理到服务器组prod1
60 }
61
62 location @prod2 {
63 proxy_pass http://prod2; # 反向代理,和上面location一个意思
64 }
....省略部分内容.....
100 server { # 因为本次实验没有apache或tomcat等后端主机,所以为了方便演示,这里加一个server虚拟主机,有#号需要取消掉
101 listen 5001; # 该虚拟server的监听端口
102 # listen somename:8080;
103 # server_name somename alias another.alias;
104
105 location / { # #号取消掉,添加该server的跳转location
106 root html; # #号取消
107 index testa.html; # #号取消,修改该行
108 } # 取消注释
109 } # 取消注释
110
111 server { # 和上面的server操作方式一样,下面有#号注释的都要取消
112 listen 5000;
113 location / {
114 root html;
115 index testb.html; # 修改改行
116 } # 取消注释
117 } # 取消注释
......省略部分内容......
:wq # 保存退出
[root@cen01 ~]# kill $(cat /usr/local/openresty/nginx/logs/nginx.pid) # 停掉nginx,如果nginx未启动会报没有那个目录或文件,此时不用管,说明nginx已停止了
3. Lua 灰度发布脚本
[root@cen01 ~]# vim /usr/local/openresty/nginx/lua/gray.lua
local redis = require "resty.redis" -- 引入 resty.redis 模块
local cache = redis.new() -- 创建一个新的 redis 实例
cache:set_timeout(60000) -- 设置超时时间为 60000 毫秒
local ok, err = cache.connect(cache, '127.0.0.1', 6379) -- 连接到本地的 Redis 服务器
if not ok then
ngx.say("failed to connect:", err) -- 如果连接失败,打印错误信息并返回
return
end
local red, err = cache:auth("123456") -- 进行身份验证
if not red then
ngx.say("failed to authenticate: ", err) -- 如果身份验证失败,打印错误信息并返回
return
end
local local_ip = ngx.req.get_headers()["X-Real-IP"] -- 获取客户端真实 IP 地址
if local_ip == nil then
local_ip = ngx.req.get_headers()["x_forwarded_for"] -- 如果 X-Real-IP 不存在,尝试获取 x_forwarded_for 的 IP 地址
end
if local_ip == nil then
local_ip = ngx.var.remote_addr -- 如果 x_forwarded_for 也不存在,获取远程地址
end
local intercept = cache:get(local_ip) -- 从缓存中获取 IP 地址
if intercept == local_ip then
ngx.exec("@prod1") -- 如果缓存中包含该 IP 地址,重定向到 "@prod1"
return
end
ngx.exec("@prod2") -- 如果缓存中不包含该 IP 地址,重定向到 "@prod2"
local ok, err = cache:close() -- 关闭与 redis 的连接
if not ok then
ngx.say("failed to close:", err) -- 如果关闭连接失败,打印错误信息并返回
return
end
4. 配置 HTML 页面
[root@cen01 ~]# vim /usr/local/openresty/nginx/html/testa.html
gray release app(test) # 这个是灰度发布演示页面
[root@cen01 ~]# vim /usr/local/openresty/nginx/html/testb.html
Real production environment(hello world) # 真实生产环境已发布的页面
5. 启动 Nginx
[root@cen01 ~]# /usr/local/openresty/nginx/sbin/nginx
[root@cen01 ~]# netstat -anpt | grep nginx
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN 72192/nginx: master
tcp 0 0 0.0.0.0:5001 0.0.0.0:* LISTEN 72192/nginx: master
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 72192/nginx: master
6. 访问测试
6.1. 灰度测试用户访问
# 之前在redis内已配置了本机为接收灰度发布的用户,所以先用本机IP进行测试
[root@cen01 ~]# curl 192.168.15.201 # 接收到灰度发布的页面,所以本机IP属于测试用户
gray release app(test)
6.2. 非灰度测试用户访问
6.2.1. Windows 客户端访问
使用 Windows 浏览器访问时,服务端接收到的客户端 IP 为 192.168.15.1,但该 IP 并未在数据库内,所以不在测试用户范围内。
回到 cen01 的终端,登录 redis,将 192.168.15.1 加入到数据库键值对内,就可以访问到灰度发布的测试页面了
[root@cen01 ~]# /usr/local/redis/redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set 192.168.15.1 192.168.15.1
OK
回到浏览器,刷新
6.2.2. Linux 客户端访问
使用另一台虚拟机 cen02 (192.168.15.202)对 cen01 进行访问
[root@cen02 ~]# curl 192.168.15.201
Real production environment(hello world) # 访问到了生产环境,确定cen02非灰度测试用户
回到 cen01,将 cen02 的 IP 加入到灰度测试用户
[root@cen01 ~]# /usr/local/redis/redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set 192.168.15.202 192.168.15.202
OK
再回到 cen02,访问 cen01
[root@cen02 ~]# curl 192.168.15.201
gray release app(test)
# cen02可以访问灰度发布页面,成为灰度测试用户