蓝绿发布使用手册 - qintianjie/blue-green-pub GitHub Wiki
安装
OS: CentOS 7
参考:https://openresty.org
openresty 安装及验证
安装方法1
sudo yum-config-manager --add-repo https://openresty.org/yum/centos/OpenResty.repo
sudo yum install openresty
ls -l /usr/local/openresty
安装方法2
sudo yum install gcc-c++.x86_64
sudo yum install pcre.x86_64 pcre-devel.x86_64
sudo yum install openssl.x86_64 openssl-devel.x86_64
wget https://openresty.org/download/openresty-1.11.2.1.tar.gz
git clone https://github.com/cubicdaiya/ngx_dynamic_upstream.git
tar -zxvf openresty-1.11.2.1.tar.gz
cd openresty-1.11.2.1
sudo ./configure --add-module=/opt/software/ngx_dynamic_upstream -j2
sudo gmake
sudo gmake install
验证
qtj@qintianjie /opt/software $vim ~/.bashrc
export NGINX_HOME=/usr/local/openresty/nginx
export PATH=$PATH:$NGINX_HOME/sbin
qtj@qintianjie /opt/software $nginx -V
nginx version: openresty/1.11.2.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
built with OpenSSL 1.0.2j 26 Sep 2016
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt='-O2 -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --add-module=../ngx_devel_kit-0.3.0 --add-module=../echo-nginx-module-0.60 --add-module=../xss-nginx-module-0.05 --add-module=../ngx_coolkit-0.2rc3 --add-module=../set-misc-nginx-module-0.31 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.06 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.7 --add-module=../ngx_lua_upstream-0.06 --add-module=../headers-more-nginx-module-0.32 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.17 --add-module=../redis2-nginx-module-0.13 --add-module=../redis-nginx-module-0.3.7 --with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' --with-pcre-jit --with-ipv6 --with-stream --with-stream_ssl_module --with-http_v2_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_geoip_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-file-aio --with-dtrace-probes --with-http_ssl_module
试用
qtj@qintianjie /opt/service/nginx-test $tree
.
├── conf
│ └── nginx.conf
└── logs
其中 nginx.conf 内容:
worker_processes 2;
events {
worker_connections 1024;
accept_mutex off;
}
http {
server {
listen 8080;
server_name localhost;
location /echo {
echo "hello word.";
}
}
}
HTTP请求:
qtj@qintianjie /opt/service/nginx-test $curl http://localhost:8080/echo
hello word.
Redis 安装及验证
参考资料: https://redis.io/ ####安装
wget http://download.redis.io/releases/redis-3.2.7.tar.gz
tar -zxvf redis-3.2.7.tar.gz
cd redis-3.2.7
echo "requirepass 123456" >> redis.conf
sudo make
sudo make test
如报 tcl 版本过低,则需:
sudo yum install tcl.x86_64 tcl-devel.x86_64
####试用
qtj@qintianjie /opt/service/redis-3.2.7 $./src/redis-server redis.conf &
qtj@qintianjie /opt/service/redis-3.2.7 $./src/redis-cli
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK
系统搭建
##Redis数据初始化
HMSET biztech:gray:apollo graySwitch online_auto grayData 111,112,114 grayType uidin
HSET biztech:gray:apollo _g1 "{\"127.0.0.1:8091\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8092\":\"weight=1 max_fails=1 fail_timeout=10;\"}"
HSET biztech:gray:apollo _g2 "{\"127.0.0.1:8093\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8094\":\"weight=1 max_fails=1 fail_timeout=10 down;\"}"
上述设置一个服务对应的灰度数据值和两组 upstream 里的 server 数据。 注意 _g2 里第二个 server 为 down, 因此可以认为只有一个 server.
graySwitch: 灰度路由控制。其值为:
close: 紧急情况赢。 不走 lua 逻辑,直接选 server 多的 upstream.
test: 测试时用。 可以根据灰度数据,设置线上两组 upstream 同时工作。 满足灰度规则的落在 server 少的 upstream里。
online_auto: 上线时用。 根据算法 uid % (g1_size + g2_size) < g1_size 让流量与组内 upstream 成正比,达到动态上线效果。
grayType: 灰度操作类型。 其值为:
uidin: uid 落在一个数组内
uidmod: uid mod 数字为 0, 其中分母可以为逗号分隔的多个数字,一般用一个数字即可
unamein: uname 落在一个数组内,线上不建议使用。
grayData: 灰度操作数据
_g1: upstream_g1 里 server 信息,为 json 字符串。 一个item 格式为: "ip:port":"weight=1 max_fails=1 fail_timeout=10 down;"
_g2: upstream_g2 里 server 信息。
最终数据:
127.0.0.1:6379> HGETALL biztech:gray:apollo
1) "grayData"
2) "111,112,114"
3) "_g1"
4) "{\"127.0.0.1:8091\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8092\":\"weight=1 max_fails=1 fail_timeout=10;\"}"
5) "grayType"
6) "uidin"
7) "graySwitch"
8) "online_auto"
9) "_g2"
10) "{\"127.0.0.1:8093\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8094\":\"weight=1 max_fails=1 fail_timeout=10 down;\"}"
##Openresty 代码搭建
环境搭建
git clone https://github.com/qintianjie/blue-green-pub.git
cd blue-green-pub
git checkout v2.0-ok
cd output
vim lua/conf/configbase.lua 修改redis配置信息,如 ["server"] = "127.0.0.1:6379:123456,192.168.142.128:6378:123456"
pkill -9 nginx; nginx -p `pwd`; tail -f logs/*log
qtj@qintianjie /opt/service/blue-green-pub/output $curl http://localhost:8899/bgpub/rule/get?service=apollo
200, {"apollo.result":"succeed","apollo.grayType":"uidin","apollo.graySwitch":"online_auto","apollo.grayData":"111,112,114"}
###验证
g1_size: 代表 upstream_g1 里有效 server 数量
g2_size: 代表 upstream_g2 里有效 server 数量
switch: close
此刻 request 全部走 server 多的 upstream
Redis操作:
127.0.0.1:6379> HSET biztech:gray:apollo graySwitch close
演示结果:
switch: test, optype: uidin
此刻 request 满足 uidin 条件的,全部走 server 少的 upstream Redis操作:
127.0.0.1:6379> HSET biztech:gray:apollo graySwitch test optype uidin
演示结果:
switch: test, optype: uidmod, g1_size > g2_size
此刻 request 满足 uidmod 条件的,全部走 server 少的 upstream Redis操作:
127.0.0.1:6379> HSET biztech:gray:apollo graySwitch test optype uidmod
演示结果:
switch: test, optype: uidmod, g1_size < g2_size
此刻 request 满足 uidmod 条件的,全部走 server 少的 upstream Redis操作:
127.0.0.1:6379> HSET biztech:gray:apollo graySwitch test optype uidmod
127.0.0.1:6379> HSET biztech:gray:apollo _g2 "{\"127.0.0.1:8093\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8094\":\"weight=1 max_fails=1 fail_timeout=10 down;\",\"127.0.0.1:8095\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8096\":\"weight=1 max_fails=1 fail_timeout=10;\"}"
演示结果:
switch: online_auto, g1_size:g2_size = 2:1
此刻 request 满足 online_auto条件后,是按 g1, g2 两组 upstream 里 server 比例切分流量
算法 uid % (g1_size + g2_size) < g1_size
Redis操作:
127.0.0.1:6379> HSET biztech:gray:apollo graySwitch test optype online_auto
127.0.0.1:6379> HSET biztech:gray:apollo _g2 "{\"127.0.0.1:8093\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8094\":\"weight=1 max_fails=1 fail_timeout=10 down;\"}"
演示结果:
switch: online_auto, g1_size:g2_size = 2:3
此刻 request 满足 online_auto条件后,是按 g1, g2 两组 upstream 里 server 比例切分流量
算法 uid % (g1_size + g2_size) < g1_size
Redis操作:
127.0.0.1:6379> HSET biztech:gray:apollo graySwitch test optype online_auto
127.0.0.1:6379> HSET biztech:gray:apollo _g2 "{\"127.0.0.1:8093\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8094\":\"weight=1 max_fails=1 fail_timeout=10 down;\",\"127.0.0.1:8095\":\"weight=1 max_fails=1 fail_timeout=10;\",\"127.0.0.1:8096\":\"weight=1 max_fails=1 fail_timeout=10;\"}"
演示结果:
动态 upstream 操作
参考: https://github.com/cubicdaiya/ngx_dynamic_upstream
实例:
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1"
server 127.0.0.1:8090;
server 127.0.0.1:8091;
server 127.0.0.1:8092;
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1&verbose="
server 127.0.0.1:8090 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8091 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8092 weight=1 max_fails=1 fail_timeout=10;
qtj@qintianjie /opt/service/blue-green-pub/output $
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1&verbose=&server=127.0.0.1:8091&weight=10"
server 127.0.0.1:8090 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8091 weight=10 max_fails=1 fail_timeout=10;
server 127.0.0.1:8092 weight=1 max_fails=1 fail_timeout=10;
qtj@qintianjie /opt/service/blue-green-pub/output $
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1&verbose=&server=127.0.0.1:8091&down="
server 127.0.0.1:8090 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8091 weight=10 max_fails=1 fail_timeout=10 down;
server 127.0.0.1:8092 weight=1 max_fails=1 fail_timeout=10;
qtj@qintianjie /opt/service/blue-green-pub/output $
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1&verbose=&server=127.0.0.1:8091&up="
server 127.0.0.1:8090 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8091 weight=10 max_fails=1 fail_timeout=10;
server 127.0.0.1:8092 weight=1 max_fails=1 fail_timeout=10;
qtj@qintianjie /opt/service/blue-green-pub/output $
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1&verbose=&server=127.0.0.1:8093&add="
server 127.0.0.1:8090 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8091 weight=10 max_fails=1 fail_timeout=10;
server 127.0.0.1:8092 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8093 weight=1 max_fails=1 fail_timeout=10;
qtj@qintianjie /opt/service/blue-green-pub/output $
qtj@qintianjie /opt/service/blue-green-pub/output $curl "http://127.0.0.1:8899/dynamic?upstream=zone_apollo_g1&verbose=&server=127.0.0.1:8093&remove="
server 127.0.0.1:8090 weight=1 max_fails=1 fail_timeout=10;
server 127.0.0.1:8091 weight=10 max_fails=1 fail_timeout=10;
server 127.0.0.1:8092 weight=1 max_fails=1 fail_timeout=10;
#其他操作 已完成:
- 启动时更新 redis 数据到 nginx 缓存已通过 lua 实现。
- upstream_g1, upstream_g2 的 server 大小需要定时的刷新到 nginx 缓存中,供 online_auto 策略时用。
待处理:
- 需要有个 agent,监听ZK等,将变化的 upstream server 通过上述 http 接口同步到线上 nginx 缓存。
- agent 还需要处理将变化的 upstream server 同步到 redis 中去。
- 需要一个后台定时任务,定时将 redis 数据刷新到 nginx 缓存。
- 定时任务还需将 redis 的 _g1, _g2 定时更新到 nginx.conf 对应 upstream 配置文件中去,避免启动时内存数据丢失。
注意点:
- upstream 是不能 remove 最后一个 server 的,可以 update 其属性为 down,达到删除效果。