1. 前言
针对目前云平台方案,因为网络、主机状态等诸多因素,单台主机上的服务出现问题的几率大大增加。这就要求我们能够监控每台主机、每个微服务实例的健康状态。因此对于nodejs相关项目需要做相关的微服务健康检查接口。
在不改动原有express框架的基础上,我在express官方网站上查找到相应的健康检查的样例,做成demo供大家参考。
(链接https://expressjs.com/en/advanced/healthcheck-graceful-shutdown.html)
2. 方案实现demo
我是以agent做的demo,以下是我修改的app.js代码:红色代码为我添加的的部分。为容器提供对应的健康检查端口。
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
var config = require('./config/config').getInstance().config;
var logg = config.logger;
var moment = require('moment');
var comm = require('./middlewares/comm');
var routes = require('./routes/index');
var app = express();
app.set('env', config.debug ? 'development' : 'production');
app.set('port', process.env.PORT || config.port);
app.set('trust proxy', config.proxy); // 指定子网和 IP 地址
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//session redis存储
const store = new RedisStore({
host: config.redis.host,
port: config.redis.port,
pass: config.redis.passwd,
});
//设置session
app.use(session({
store: store,
name: 'ghjhgz',
secret: 'dfgdfgfdgdfgdfgderte435sd',
resave: true,
rolling: true,
saveUninitialized: false,
cookie: {domain: config.domain}
}));
// 添加模板必需的变量
app.use(function (req, res, next) {
res.locals.user = '';
next();
});
routes(app);
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
logg.error(err);
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
if(config.debug){
res.render('error');
}else{
res.render('404');
}
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(config.port, function () {
console.log('listening on port: ' + config.port);
});
}
module.exports = app;
1 const http = require('http');
2
3 const terminus = require('@godaddy/terminus');
4
5 const server = http.createServer(app);
6
7 function onSignal() {
8
9 console.log('server is starting cleanup');
10
11 // start cleanup of resource, like databases or file descriptors
12
13 }
14
15 async function onHealthCheck() {
16
17 // checks if the system is healthy, like the db connection is live
18
19 // resolves, if health, rejects if not
20
21 console.log('HealthCheck is starting');
22
23 }
24 terminus(server, {
25
26 signal: 'SIGINT',
27
28 healthChecks: {
29
30 '/healthcheck': onHealthCheck,
31
32 },
33
34 onSignal
35
36 });
37
38 server.listen(3000);
目前,只需要修改一下app.js,onHealthCheck函数接口为健康检查接口,后续可以提供检查对应的系统健康,比如数据库或者redis链接状态等。
2.1 依赖库terminus
安装依赖
npm i @godaddy/terminus --save
Terminus是一个开放源代码项目,它将健康检查和正常关闭添加到您的应用程序中,从而无需编写样板代码。您只需提供用于正常关闭的清理逻辑和用于运行状况检查的运行状况检查逻辑,而终点则处理其余部分。
2.2 有限的Windows支持
由于固有的平台限制,terminus对Windows的支持有限。你可以期望SIGINT工作,以及在SIGBREAK某种程度上SIGHUP。但是,SIGTERM在Windows上永远不会工作,因为在任务管理器中查杀进程是无条件的,也就是说,应用程序无法检测或阻止进程。
2.3 Terminus源码GitHub地址
https://github.com/godaddy/terminus
3. Kubernetes对应的接口
使用livenessProbe探针对开放的端口进行检测。
livenessProbe:
httpGet:
path: /healthcheck #对应应用的健康路径
port: 3000 #统一的健康检查端口,在云平台内部不会出现端口冲突
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 1