njet灰度发布

By 洪昕 2023-08-14

【最佳实践】利用 OpenNJet 实现灰度发布

在应用的新版本测试发布过程中,经常需要先使用部分选定的账号进行验证,待验证完成后,再逐步将业务流量切换到新版本,直至所有流量均切换到新的集群。

测试账号的检测可以使用多种方式,如通过 Header 中字段,Cookie 中的值,或者 URL 中的参数等方式。

在之后章节的配置及场景中,将使用 HTTP Header 中的 staffid 字段做为测试账号的判断依据,7xxxx 的账号将被认定为测试工号。

初始静态配置

初始配置中,将设置两组 upstream: backendA , backendB , 并通过 split_clients 指令设置使用 header 中的 staffid 值做为流量配比依据,并设置 100% 的流量将指向后端 backendA。

 split_clients $http_staffid $backend {
     100%    backendA;
     *       backendB;
   }

完整配置如下:

njet.conf
worker_processes auto;
cluster_name app1;
node_name node1;

error_log logs/error.log info;
load_module modules/njt_http_split_clients_2_module.so;
load_module modules/njt_http_dyn_bwlist_module.so;
load_module modules/njt_http_lua_module.so;
load_module modules/njt_dyn_ssl_module.so;
load_module modules/njt_agent_dynlog_module.so;  
load_module modules/njt_http_location_module.so;
helper ctrl modules/njt_helper_ctrl_module.so njet_ctrl.conf;
helper broker modules/njt_helper_broker_module.so ;

events {
    worker_connections  1024;
}

http {
   split_clients $http_staffid $backend {
     100%    backendA;
     *       backendB;
   }

   upstream backendA {
     server 192.168.1.4:18081;
   } 
   upstream backendB {
     server 192.168.2.4:18081;
   } 

   server {
       listen      18080 ssl; 
       ssl_certificate     cert/server.crt;  
       ssl_certificate_key  cert/server.key; 
       server_name www.test.com;
   
       location / {
         proxy_pass http://${backend};
       }
   }
}
njet_ctrl.conf
load_module modules/njt_http_sendmsg_module.so;
load_module modules/njt_ctrl_config_api_module.so; 
load_module modules/njt_helper_health_check_module.so;
load_module modules/njt_http_upstream_api_module.so; 
load_module modules/njt_http_location_api_module.so;
load_module modules/njt_doc_module.so;
load_module modules/njt_http_vtsd_module.so;

error_log logs/error_ctrl.log error;

events {
    worker_connections  1024;
}
http {
    include mime.types;
    access_log off;
    server {
        listen       8081;
        location / {
            return 200 "njet control panel\n";
        }
        location /hc {
            health_check_api;
        }
        location /api {
             api write=on;
        }
        location /kv {
            dyn_sendmsg_kv;
        }
        location /config {
            config_api;
        } 
        location /doc {
            doc_api;
        }
        location /dyn_loc {
           dyn_location_api;
        }  
        location /metrics {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format html;
        }
    }
}

灰度发布步骤

动态添加 location

当新版本已经部署到 backendB 集群后, 通过动态 location 提供的 API 添加一个条件 location, location 中设置所有的 7xxxx 测试工号将访问到 backendB。Njet 提供的条件表达式中,可以使用 $http_* 获取到请求 header 中的值, $http_staffid ~* “7.*” 表达式将匹配所有 header 中 staffid 为 7xxxx 的请求。

img

使用测试工号测试

通过上一个步骤添加条件 location 后, 所有非 7xxxx 的工号将继续访问到集群 backendA, 所有 7xxxx 做为测试工号,将访问到集群 backendB。

img

删除表达式 location

当测试完成后,可以使用动态 API 删除条件 location。

img

删除条件 location 后,所有的流量均指向 backendA, 包括 7xxxx 的测试工号。

逐步调整分流比例直至 100%

使用模块提供的动态配置 API, 逐步调整分流比例。

如调整到 50:50 的比例时:

img

最后调整到 0:100 的比例, 所有的流量将指向 backendB

img

这时,应用的新版本已经完成部署和切换 (A => B ), 当下一个版本发布时,可以使用相同的步骤,完成 (B => A) 的切换。


img

OpenNJet 最早是基于 NGINX1.19 基础 fork 并独立演进,随着 NGINX 版本迭代,吸收上游 NGINX 的更新,已经同步更新到 NGINX1.23.1 版本,OpenNJet 具有高性能、稳定、易扩展的特点,同时也解决了 NGINX 长期存在的难于动态配置、管理功能影响业务等问题。

作为底层引擎,OpenNJet 利用动态加载机制可以实现不同的产品形态,如 API 网关、消息代理、出入向代理,负载均衡,WAF 等等。在云原生架构中,OpenNJet 除了提供南北向通信网关的功能以外,还提供了服务网格中东西向通信、透明流量劫持、熔断、遥测与故障注入等新功能特性。

传送门:https://gitee.com/njet-rd