写点什么

NJet Portal 应用门户管理介绍

作者:通明湖
  • 2025-06-10
    北京
  • 本文字数:5740 字

    阅读完需:约 19 分钟

nginx 向云原生演进,All in OpenNJet

1. 应用门户简介

NJet 应用引擎是基于 Nginx 的面向互联网和云原生应用提供的运行时组态服务程序,作为底层引擎,NJet 实现了 NGINX 云原生功能增强、安全加固和代码重构,利用动态加载机制可以实现不同的产品形态,如 Web 服务器、流媒体服务器、负载均衡、代理(Proxy)、应用中间件、API 网关、消息队列等产品形态等等。NJet 使用现有的 API Gateway 及各动态配置模块提供的能力,实现了一个 Portal 管理模块。通过该模块,对外提供应用门户的功能,以此来简化应用的开发及部署过程。应用可以只专注于业务逻辑的实现,将通用的安装配置及权限认证功能统一交给 NJet 应用门户管理模块。逻辑架构如下图所示:

2. 应用部署流程

用户使用管理员账号登录 Portal 门户,上传应用,添加用户/组/角色,最后进行应用的授权。完成上述操作后,使用普通用户账号登录门户,即可使用应用。

a. 管理员登录

在部署包含 Portal 管理模块的环境上,使用 api gateway 的管理员账号登录后,将显示 Portal 的管理界面,在该界面中可以进行应用的部署,及相关的授权。


b. 上传应用

应用管理中点击“新增”,选择 Portal 应用的相应 npk 文件(应用的结构在后续章节进行说明)。点击确认后,Portal 管理模块将自动创建应用需要的 Location/Upstream, 由于使用了 NJet 的动态配置功能,所有的改动将实时生效,不需要重启或重加载 NJet。

应用如果需要连接第三方组件,门户管理模块也提供了通用组件的配置能力。

c. 创建访问应用需要的用户/组/角色

应用门户使用 Api Gateway 提供的授权能力,其模型是“用户->组->角色”的授权模型,一个用户可以归属于不同的用户组,一个用户组可以分配多个角色,API 授权将授权到角色上。

应用门户的 UI 上可以对用户/组/角色及相互间的关系进行维护。

d. 对应用进行授权

在应用管理中,选择应用授权,对应用不同的访问路径可以授予不同的角色。

e. 普通用户登录

使用普通用户账号登录后,将显示应用一览页面,在改列表页面中点击对应的图标,将跳转至具体的应用中。

3. Portal 应用结构

使用 Portal 管理模块部署的应用,需要使用 Portal 模块可以识别的格式进行目录规划及应用打包,文件类型是 npk (NJet Package)。 典型的目录结构如下图所示:

  • META-INF 目录 manifest.json: 应用的基本信息,包括入口地址,配置地址,及 location / upstream 信息。图标文件: jpg 或 jpg 格式的文件 app_openapi.json: openapi 3.0 格式的文件,其中 path 支持 通配符*, 例如 /setting/*app_schema.json: 应用需要的组件配置项 (可选,非必须)

  • scripts 目录应用使用的脚本

  • static 目录静态页面,资源文件,javascript 脚本, css

manifest.json 示例该文件中定了入口地址(entry_point), 应用配置地址(cfg_url), 及应用需要的 location, upstream servers, \proxy_pass。Location 中可以直接配置属性("__access_control": “true” ) 来标识该访问地址需要使用门户提供的用户授权功能。


{  "manifest_version": "1.0.0",  "app": {    "name": "ollamaApp",    "version": "1.0.0",    "arch": "x86_64",    "description": "Ollma Chat application",    "icon_file": "ollama.jpg",    "api_file": "app_openapi.json"   },  "deployment": {    "type": "location",    "server_name": "",    "entry_point": "/ollama-app/open/chat",    "cfg_url": "/ollama-app/open/config",    "locations": [      {        "path": "/ollama-app/conversation",        "properties": {          " content_by_lua_file": "${APP_PREFIX}/scripts/chat_api.lua"        }      },      {        "path": "/ollama-app/setting",        "properties": {          "__access_control": "true",           " content_by_lua_file": "${APP_PREFIX}/scripts/chat_api.lua"        }      },      {        "path": "/ollama-app/chat",        "properties": {          "access_by_lua_file": "${APP_PREFIX}/scripts/access.lua",             "proxy_set_header": [            "Host 192.168.0.206",            "Origin http://192.168.0.206"          ],          "proxy_pass": {            "schema": "http",            "servers": [              {"server":"192.168.40.206:11434"}            ],            "url": "/api/chat"          }        }      },      {        "path": "/ollama-app",        "properties": {          "__access_control": "true",           "alias": "${APP_PREFIX}/static/",          "try_files": "$uri $uri/ /ollama-app/index.html"        }      }    ]  }}


复制代码

app_schema.json 示例应用需要连接第三方组件时,组件的配置通过 json 文件描述配置项,门户管理模块将根据 json 内容动态生成配置页面。该配置使用 formily (阿里巴巴表单框架 https://formilyjs.org/)定义的格式。 以下示例文件为连接 redis 组件时需提供的 json 文件。

{    "redis_host": {        "type": "string",        "x-component": "Input",        "x-component-props": {            "placeholder": "请输入ip地址"        },        "x-decorator": "Form.Item",        "x-decorator-props": {            "label": "Redis IP",            "tooltip": "请输入ip地址"        }    },    "redis_port": {        "type": "number",        "x-component": "InputNumber",        "x-component-props": {            "placeholder": "请输入端口号",            "min": 0,            "max": 65535        },        "x-decorator": "Form.Item",        "x-decorator-props": {            "label": "Redis Port",            "tooltip": "请输入端口号"        }    },    "redis_password": {        "type": "string",        "x-component": "Input.Password",        "x-component-props": {            "placeholder": "请输入 密码"        },        "x-decorator": "Form.Item",        "x-decorator-props": {            "label": "Redis密码",            "tooltip": "请输入密码"        }    }}



复制代码

4. Demo 应用完整实例

a. 通过 ftp 获取到 demo 应用包

地址: ftp.tmlake.com目录: /OpenNjet/Software/v3.2.2-portal 文件: demo_app_1.0.2.npk

b. 使用默认管理员账号 agw_admin /****** 登录 /portal1

c. 添加 demo 应用

在应用管理中,选择新增,添加获取的 demo_app_1.0.2.npk, 并点击确认

成功后,应用管理页面将出现 demo 应用的条目

d. 为用户添加用户/组/角色

添加一个 demo 用户角色

添加一个 demo 用户组

为这个组分配角色


添加一个 user1 用户,并指定 domain 为 “demo”

为这个用户分配组


e. 编辑应用的授权

在应用管理列表中点击 demo 的授权

该应用只有一个访问地址,选择后点击授权,在弹出的窗口下拉框中选择"demoUserRole"

f. 使用刚创建的普通用户账号登录 /portal

应用列表中显示出我们刚刚部署的 demo 应用

点击应用图标后,跳转到应用的页面

该 demo 应用只是简单的一些页面 Tab, 展示的也只是一些测试数据


  1. 后续改进目前部署的应用有新版本需要升级时,需要在应用管理中删除应用后,重新上传。后续将继续优化门户管理模块,提供应用的版本管理及回滚功能。

  2. 参考 a. 使用到的 APIAPI Gateway: 用户/组/权限的增删改查,api group 创建,oas3.0 格式文档导入,应用部署接口 https://gitee.com/njet-rd/njet/blob/master/doc/swagger/helper_api_gateway.yaml 动态 Location API: 动态添加及删除 Locationhttps://gitee.com/njet-rd/njet/blob/master/doc/swagger/helper_dy_loc.yaml 动态 Upstream API: 动态添加及删除 Upsteamhttps://gitee.com/njet-rd/njet/blob/master/doc/swagger/helper_dyn_http_ups.yaml\


b. Demo 应用包的下载地址: ftp.tmlake.com


目录: /OpenNjet/Software/v3.2.2-portal 文件: demo_app_1.0.2.npk


c. NJet 版本及 Portal 获取及安装 NJet 版本需要 > 3.2.2Portal 门户管理模块获取:地址: ftp.tmlake.com


目录: /OpenNjet/Software/v3.2.2-portal/文件: portal_1.0.2.npk , ssh_remote_mod.soPortal 门户管理模块安装:修改配置 /usr/local/njet/conf/njet.conf


worker_processes auto;
cluster_name njet;node_name node1;
error_log logs/error.log error;
helper ctrl modules/njt_helper_ctrl_module.so conf/njet_ctrl.conf;helper broker modules/njt_helper_broker_module.so;
load_module modules/njt_agent_dynlog_module.so; load_module modules/njt_dyn_ssl_module.so;load_module modules/njt_http_vtsc_module.so;load_module modules/njt_http_location_module.so;load_module modules/njt_http_lua_module.so;load_module modules/njt_http_dyn_upstream_module.so;load_module modules/njt_http_dyn_server_module.so; load_module modules/njt_http_token_sync_module.so;load_module modules/njt_http_upstream_member_module.so;load_module modules/njt_http_dyn_lua_module.so;
events { worker_connections 1024;}
shared_slab_pool_size 100m; http { token_sync zone=token:4M sync_time=5s clean_time=10s; dyn_kv_conf conf/iot-work.conf; include mime.types; access_log off; vhost_traffic_status_zone;
lua_package_path "$prefix/lualib/lib/?.lua;$prefix/modules/?.lua;$prefix/apps/?.lua;;"; lua_package_cpath "$prefix/lualib/clib/?.so;;"; init_by_lua_block { local _=require("lor.index") local _=require("lsqlite3complete") } server { listen 8080; error_page 401 =302 /portal; client_max_body_size 1000m; location / { root html; } location /icons/ { alias /usr/local/njet/apps/__icons/; try_files $uri =404; } }}
复制代码


lua_package_path "$prefix/lualib/lib/?.lua;$prefix/modules/?.lua;$prefix/apps/?.lua;;";lua_package_cpath "$prefix/lualib/clib/?.so;;";init_by_lua_block {    local _=require("lor.index")    local _=require("lsqlite3complete")}server {    listen       8080;    error_page 401 =302 /portal;    client_max_body_size 1000m;     location / {       root html;    }    location /icons/ {        alias /usr/local/njet/apps/__icons/;        try_files $uri =404;   }}}
复制代码


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;load_module modules/njt_http_lua_module.so;load_module modules/njt_http_dyn_upstream_module.so;load_module modules/njt_http_dyn_upstream_api_module.so;load_module modules/njt_http_dyn_server_api_module.so;load_module modules/njt_http_upload_module.so;
error_log logs/error_ctrl.log error;
events {worker_connections 1024;}
http {dyn_kv_conf conf/ctrl_kv.conf;lua_package_path "prefix/modules/?.lua;;";lua_package_cpath "$prefix/lualib/clib/?.so;;";init_by_lua_block {local _=require("lor.index")local _=require("lsqlite3complete")}include mime.types;access_log off;server {client_max_body_size 1000m;
listen 8081;

复制代码


    location / {        return 200 "njet control panel\n";    }
location /api { dyn_module_api; } location /doc { doc_api; } location /metrics { vhost_traffic_status_display; vhost_traffic_status_display_format html; }
location /api_gateway { access_by_lua_block { local ac=require("api_gateway.access.control") local access=ac.new("/api_gateway") access:check() } content_by_lua_block { local api_gateway=require("api_gateway") api_gateway.main() } }}
复制代码

拷贝 ssh_remote_mod.so

sudo cp ssh_remote_mod.so /usr/local/njet/lualib/clib/
复制代码

重启 njet

sudo systemctl stop njetsudo systemctl start njet
复制代码

将下载后的 portal_1.0.2.npk 文件上传到 njet 主机上,并且主机上安装 curl 及 jq 命令行工具

NJET_SITE="http://localhost:8081"
PORTAL_FILE=NJET_SITE/api/v1/upload" |jq -r '.file')
TOKEN=NJET_SITE/api_gateway/auth/login" | jq -r '.token')
curl -X 'POST'
"$NJET_SITE/api_gateway/deploy/app"
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{"uploaded_file": "$PORTAL_FILE"}"
复制代码

NJet 应用引擎通过内核重构实现了独特的运行时 动态配置加载 能力,是 新一代高性能 Web 应用引擎 。NJet 拥有高性能数据面处理能力,将集群、高可用、主动健康检查、声明式 API 等多种辅助功能,通过 NJet 独特的副驾驶 CoPilot 服务框架调度,从而方便功能扩展,隔离管理 / 控制功能对数据面的影响,NJet 应用引擎性能超过 CNCF 推荐 Envoy 应用引擎的三倍。 


官网:https://njet.org.cn/ 

邮件组:https://njet.org.cn/mailman/listinfo

发布于: 2025-06-10阅读数: 3
用户头像

通明湖

关注

让应用永远在线! 2022-10-13 加入

持续科技创新,信创应用交付领域的排头兵

评论

发布
暂无评论
NJet Portal 应用门户管理介绍_通明湖_InfoQ写作社区