基于nginx+lua简单的灰度发布系统
upstream.conf
upstream grey_1 { keepalive 1000; server localhost:8020; } upstream grey_2 { keepalive 1000; server localhost:8021; }
8020 conf
#vhost conf server{ listen 8020;
index index.php index.html index.do; root /var/html/webroot/grey_1; access_log "/data/logs/nginx/access.log" ; error_log "/data/logs/nginx/error.log" warn; location / { if ( !-e $request_filename ) { rewrite ^/(.*) /index.php last; } } location ~ \.(php|do)($|/) { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; set $path_info $request_uri; if ( $request_uri ~ ^/(v\d)(\/.*)(\?.*)?$){ set $path_info $2; break; } fastcgi_param PATH_INFO $path_info; } }
8021 conf
#vhost conf server{ listen 8021; index index.php index.html index.do; root /var/html/webroot/grey_2 access_log "/data/logs/nginx/access.log" ; error_log "/data/logs/nginx/error.log" warn; location / { if ( !-e $request_filename ) { rewrite ^/(.*) /index.php last; } } location ~ \.(php|do)($|/) { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; set $path_info $request_uri; if ( $request_uri ~ ^/(v\d)(\/.*)(\?.*)?$){ set $path_info $2; break; } fastcgi_param PATH_INFO $path_info; } }
nginx.conf
#vhost conf server{ listen 8000; index index.php index.html index.do; root /var/html/www/webroot/index; access_log /data/logs/index_access.log; error_log /data/logs/index_error.log warn; lua_code_cache off; location /lua { content_by_lua ' ngx.say( "hello" ) '; } location / { if ( !-e $request_filename ) { rewrite ^/(.*) /index.php last; } } location /grey/ { default_type 'text/plain'; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Connection ""; proxy_http_version 1.1; set $backend "grey_1"; rewrite_by_lua_file conf/lua/grey.proxy.lua; proxy_pass http://$backend/?$args; }
grey.proxy.lua
local grey = require "greyrelease.grey" local upstream = grey.get_upstream_by_userid() -- ngx.say( upstream ) ngx.var.backend = upstream
grey.lua
local strings = require "resty.string" local _M = {} local hash_standard = 100 local hash_max_len = 10 local default_stream = "grey_1" local search_stream = "grey_2" local hash_map = { -- grey_0 = {range_start=0,range_end=9,flow="grey1"}, grey_0 = {range_start=0,range_end=9,flow="grey1"}, grey_1 = {range_start=10,range_end=19,flow="grey1"}, grey_2 = {range_start=20,range_end=29,flow="grey1"}, grey_3 = {range_start=30,range_end=39,flow="grey1"}, grey_4 = {range_start=40,range_end=49,flow="grey1"}, grey_5 = {range_start=50,range_end=59,flow="grey1"}, grey_6 = {range_start=60,range_end=69,flow="grey1"}, grey_7 = {range_start=70,range_end=79,flow="grey1"}, grey_8 = {range_start=80,range_end=89,flow="grey1"}, grey_9 = {range_start=90,range_end=99,flow="grey1"}, } function _M.get_upstream_by_userid() if ngx.var.arg_grey_test == "grey_1" then return search_stream elseif ngx.var.arg_grey_test == "grey_2" then return default_stream end local user_id=ngx.var.arg_user_id local upstream=default_stream if user_id == nil then return upstream end local hex_string = strings.to_hex( user_id ) local str_len = string.len( hex_string ) local hash_string = "" if str_len > hash_max_len then hash_string = string.sub( hex_string,0,hash_max_len ) else hash_string = hex_string end local int_mod = math.fmod( hash_string,hash_standard ) for k,v in pairs( hash_map ) do if v['range_start'] <= int_mod and int_mod < v['range_end'] then upstream = v['flow'] break end end return upstream end return _M