本文记录了使用OpenNJet从零部署一个Web服务器的心得体会。

OpenNJet官方网站https://njet.org.cn/

一、基本信息

产品名称 OpenNJet
体验版本 2.1.0
体验设备 VMware16+Ubuntu18.04
体验时间 2024.4.23
体验耗时 1.5 h

二、产品信息

产品简介:OpenNJet是一个云原生应用引擎,其设计目标是为互联网和云环境中的应用程序提供运行时配置和服务管理能力。该应用引擎基于NGINX构建,并对NGINX进行了云原生功能增强、安全加固和代码重构,以适应现代云环境的需求。

产品类型:OpenNJet应用引擎是一个高性能、轻量级的WEB应用与代理软件。

产品定位:作为云原生服务网格的数据平面,NJet具备动态配置加载、主动式健康检测、集群高可用、声明式API等多种强大功能。通过CoPliot副驾驶服务框架,在隔离控制面和数据面的情况下实现了高可扩展性。NJet应用引擎助力企业实现云原生技术的平滑升级并大幅降低IT运营成本。

三、技术特点

OpenNJet在NGINX的架构上进行了扩充,对其框架进行了改写,增加了可持久化的动态存储能力,解决了指令配置变更动态生效的关键问题,扩展了OpenNJet的应用场景。其主要的技术特点如下。

  1. 环境感知:OpenNJet能够根据云环境的变化进行动态调整和适配。

  2. 安全控制:OpenNJet提供了安全相关的功能来保护运行在其上的应用。

  3. 加速优化:OpenNJet可以通过各种方式优化网络性能和资源使用效率。

  4. 动态加载机制:OpenNJet支持不同产品形态的灵活扩展,可以快速部署并作为Web服务器、流媒体服务器、负载均衡器、代理服务器、应用中间件、API 网关、消息代理等。

  5. 服务网格功能:支持东西向通信、透明流量劫持、熔断、遥测与故障注入、链路追踪等功能,便于微服务架构下的服务管理和运维。

  6. 容器化与云原生兼容性:与云原生基础设施无缝集成,支持蓝绿发布等云原生部署策略。

此外,OpenNJet成为了开放原子开源基金会的孵化项目,受到了业界的关注和支持,并且致力于通过开源社区的方式推动技术创新和生态建设。

四、产品结构

产品结构如图1所示。

img

图1 产品结构图

五、产品体验

基于OpenNJet搭建一个轻量级的Web服务器。分为环境搭建安装OpenNJet以及部署Web服务器等三大部分。

5.1 环境搭建

本部分较为基础,这里引用了一些不错的文章,供大家参考。(0.5h

5.1.1 安装VMware16虚拟机

安装步骤:最新超详细VMware虚拟机下载与安装

5.1.2 下载Ubuntu18.04镜像

下载地址:https://releases.ubuntu.com/18.04/

5.1.3 在VMware16中配置Ubuntu18.04

配置步骤:VMwareWorkstation16与Ubuntu 18.04.6 LTS下载与安装

5.2 安装OpenNJet

本部分将阐述安装OpenNJet的详细步骤。(0.5h

参考文章https://njet.org.cn/docs/quickstart/

5.2.1 更新软件包

命令如下

1
sudo install upgrade

该命令用于更新ubuntu自带的软件包。

截图如下(图2)

img

图2 更新软件包

5.2.2 安装必须的软件

命令如下

1
2
3
4
sudo apt install vim 
sudo apt install net-tools
sudo apt-get autoremove open-vm-tools
sudo apt-get install open-vm-tools-desktop

vim用于编辑文本,net-tools用于查看虚拟机的ip

open-vm-toolsopen-vm-tools-desktop用于设置桌面全屏,以及实现本机与虚拟机间的复制黏贴

注意】安装软件后需要重启虚拟机

5.2.3 安装需要用到的软件

软件如下

gcc g++ make cmake libpcre2-dev libpcre3-dev libssl-dev zlib1g-dev perl m4 libtool automake autoconf vim-common unzip libcap2-bin

命令如下

1
sudo apt install gcc g++ make cmake libpcre2-dev libpcre3-dev libssl-dev zlib1g-dev perl m4 libtool automake autoconf vim-common unzip libcap2-bin

截图如下(图3)

img

图3 安装需要的软件

5.2.4 添加gpg文件

命令如下

1
2
3
4
5
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://njet.org.cn/download/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/njet.gpg
sudo chmod a+r /etc/apt/keyrings/njet.gpg

截图如下(图4)

img

图4 添加gpg文件

5.2.5 添加apt源

命令如下

1
2
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/njet.gpg] https://njet.org.cn/download/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/njet.list > /dev/null
sudo apt-get update

截图如下(图5)

img

图5 添加apt源

5.2.6 安装并启动njet

命令如下

1
2
sudo apt-get install njet 
sudo systemctl start njet

截图如下(图6)

img

图6 安装并启动njet

5.2.7 测试web服务器是否启动

命令如下

1
curl localhost:8080/

此命令可以向localhost:8080发送GET请求,获取网页内容。

截图如下(图7)

img

图7 使用curl命令

此时打开Firefox浏览器,在地址栏中输入localhost:8080,会出现图8所示的欢迎页面

img

图8 欢迎页面

至此,成功安装OpenNJet

5.3 部署WEB服务器

本部分将使用OpenNJet部署一个炫酷的Web服务器。(0.5h

参考文章https://njet.org.cn/docs/user-guide/

5.3.1 查看conf文件

  1. OpenNJet的主要配置文件为njet.conf,可以通过修改该文件来配置OpenNJet。

该文件在/usr/local/njet/conf目录下,如图9所示。

img

图9 njet.conf文件的路径

  1. 可以双击njet.conf文件查看其内容,该文件的内容如图10所示。

img

图10 njet.conf文件的内容

5.3.2 修改conf文件

  1. 修改njet.conf文件的权限,并以笔记本(gedit命令)的方式打开该文件,代码如下。
1
2
3
4
sudo apt install gedit 
cd /usr/local/njet/conf
sudo chmod a+w njet.conf
gedit njet.conf

截图如图11所示。

img

图11 修改njet.conf文件的权限

  1. 修改njet.conf文件的内容,将listen的端口号修改为80,修改的文本如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http {
include mime.types;
access_log off;
vhost_traffic_status_zone;
#lua_package_path "$prefix/lualib/lib/?.lua;/usr/local/njet/modules/?.lua;;";
#lua_package_cpath "$prefix/lualib/clib/?.so;;";
server {
#modsecurity on;
#modsecurity_rules_file /usr/local/njet/conf/modsec/main.conf;

listen 80;
location / {
root html;
}
}
}

修改后的文本如图12所示。

img

图12 修改listen的端口号为80

  1. 最后保存文本并退出。

5.3.3 查看html文件

  1. 进入/usr/local/njet/html目录并查看index.html文件,如图13所示。

img

图13 index.html文件的路径

  1. 双击index.html文件并查看其内容,该文件的内容如图14所示。

img

图14 index.html文件的路径

注意到网址localhost:8080的内容就是该文件,修改这个文件即可修改localhost:8080的内容。

5.3.4 修改html文件

  1. 修改index.html文件的权限,并以笔记本(gedit命令)的方式打开该文件,代码如下。
1
2
3
cd /usr/local/njet/html 
sudo chmod a+w index.html
gedit index.html

截图如图15所示。

img

图15 修改index.html文件的权限

  1. 修改index.html文件,删除原有代码并填入以下代码。(该html代码实现了一个炫酷的爱心)

更多炫酷的html代码见:https://github.com/Want595/FunnyHTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>heart</title>
<style>
canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .2);
}
</style>
</head>
<body>
<canvas id="heart" width="1920" height="947"></canvas>
<script>
window.requestAnimationFrame =
window.__requestAnimationFrame ||
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
(function () {
return function (callback, element) {
var lastTime = element.__lastTime;
if (lastTime === undefined) {
lastTime = 0;
}
var currTime = Date.now();
var timeToCall = Math.max(1, 33 - (currTime - lastTime));
window.setTimeout(callback, timeToCall);
element.__lastTime = currTime + timeToCall;
};
})();
window.isDevice = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(((navigator.userAgent || navigator.vendor || window.opera)).toLowerCase()));
var loaded = false;
var init = function () {
if (loaded) return;
loaded = true;
var mobile = window.isDevice;
var koef = mobile ? 0.5 : 1;
var canvas = document.getElementById('heart');
var ctx = canvas.getContext('2d');
var width = canvas.width = koef * innerWidth;
var height = canvas.height = koef * innerHeight;
var rand = Math.random;
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.fillRect(0, 0, width, height);
var heartPosition = function (rad) {
//return [Math.sin(rad), Math.cos(rad)];
return [Math.pow(Math.sin(rad), 3), -(15 * Math.cos(rad) - 5 * Math.cos(2 * rad) - 2 * Math.cos(3 * rad) - Math.cos(4 * rad))];
};
var scaleAndTranslate = function (pos, sx, sy, dx, dy) {
return [dx + pos[0] * sx, dy + pos[1] * sy];
};
window.addEventListener('resize', function () {
width = canvas.width = koef * innerWidth;
height = canvas.height = koef * innerHeight;
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.fillRect(0, 0, width, height);
});
var traceCount = mobile ? 20 : 50;
var pointsOrigin = [];
var i;
var dr = mobile ? 0.3 : 0.1;
for (i = 0; i < Math.PI * 2; i += dr) pointsOrigin.push(scaleAndTranslate(heartPosition(i), 210, 13, 0, 0));
for (i = 0; i < Math.PI * 2; i += dr) pointsOrigin.push(scaleAndTranslate(heartPosition(i), 150, 9, 0, 0));
for (i = 0; i < Math.PI * 2; i += dr) pointsOrigin.push(scaleAndTranslate(heartPosition(i), 90, 5, 0, 0));
var heartPointsCount = pointsOrigin.length;

var targetPoints = [];
var pulse = function (kx, ky) {
for (i = 0; i < pointsOrigin.length; i++) {
targetPoints[i] = [];
targetPoints[i][0] = kx * pointsOrigin[i][0] + width / 2;
targetPoints[i][1] = ky * pointsOrigin[i][1] + height / 2;
}
};
var e = [];
for (i = 0; i < heartPointsCount; i++) {
var x = rand() * width;
var y = rand() * height;
e[i] = {
vx: 0,
vy: 0,
R: 2,
speed: rand() + 5,
q: ~~(rand() * heartPointsCount),
D: 2 * (i % 2) - 1,
force: 0.2 * rand() + 0.7,
f: "hsla(240," + ~~(40 * rand() + 60) + "%," + ~~(60 * rand() + 20) + "%,.3)", //修改颜色
trace: []
};
for (var k = 0; k < traceCount; k++) e[i].trace[k] = { x: x, y: y };
}

var config = {
traceK: 0.4,
timeDelta: 0.01
};
var time = 0;
var loop = function () {
var n = -Math.cos(time);
pulse((1 + n) * .5, (1 + n) * .5);
time += ((Math.sin(time)) < 0 ? 9 : (n > 0.8) ? .2 : 1) * config.timeDelta;
ctx.fillStyle = "rgba(0,0,0,.1)";
ctx.fillRect(0, 0, width, height);
for (i = e.length; i--;) {
var u = e[i];
var q = targetPoints[u.q];
var dx = u.trace[0].x - q[0];
var dy = u.trace[0].y - q[1];
var length = Math.sqrt(dx * dx + dy * dy);
if (10 > length) {
if (0.95 < rand()) {
u.q = ~~(rand() * heartPointsCount);
} else {
if (0.99 < rand()) {
u.D *= -1;
}
u.q += u.D;
u.q %= heartPointsCount;
if (0 > u.q) {
u.q += heartPointsCount;
}
}
}
u.vx += -dx / length * u.speed;
u.vy += -dy / length * u.speed;
u.trace[0].x += u.vx;
u.trace[0].y += u.vy;
u.vx *= u.force;
u.vy *= u.force;
for (k = 0; k < u.trace.length - 1;) {
var T = u.trace[k];
var N = u.trace[++k];
N.x -= config.traceK * (N.x - T.x);
N.y -= config.traceK * (N.y - T.y);
}
ctx.fillStyle = u.f;
for (k = 0; k < u.trace.length; k++) {
ctx.fillRect(u.trace[k].x, u.trace[k].y, 1, 1);
}
}
ctx.fillStyle = "rgba(255,255,255,1)";
for (i = u.trace.length + 13; i--;) ctx.fillRect(targetPoints[i][0], targetPoints[i][1], 2, 2);
window.requestAnimationFrame(loop, canvas);
};
loop();
};
var s = document.readyState;
if (s === 'complete' || s === 'loaded' || s === 'interactive') init();
else document.addEventListener('DOMContentLoaded', init, false);
</script>
</body>
</html>

修改后的代码如图16所示。

img

图16 修改后的index.html文件

  1. 最后保存代码并退出。

5.3.5 重启njet服务

使用以下代码重启njet服务。

1
2
sudo systemctl stop njet 
sudo systemctl start njet

截图如图17所示。

img

图17 重启njet

5.3.6 查看web服务器

最后打开浏览器,在地址栏中输入localhost:80,此时会出现如图18所示的炫酷页面。

img

图18 炫酷的页面

六、总结

很高兴受邀体验了OpenNJet开源项目,个人感觉该项目非常值得探索,感谢每一个为OpenNJet做出贡献的开发者。希望本文可以帮助小伙伴们快速入门OpenNJet,由于本人能力有限,如果有小伙伴在阅读本文时发现了BUG,欢迎提出宝贵的意见。