devops部署
以前,我们设法在每次commit时重新部署我们的应用程序 。 您可能还记得,我们通过处理脚本执行结果来获得部署状态。 因此,让我们在每次部署代码时使用它向自己发送通知。
为此,我们将在VPS上创建另一个Node.js服务器应用程序。 您可以扩展为连续部署而创建的应用程序,尽管我不建议这样做。 取而代之的是,我们可以采用Unix方式,每个应用程序都能很好地完成工作。 此外,我们可以使用报告服务器来通知我们有关应用程序其他部分(例如前端)的部署的信息。
如您所料,我们需要同时实现应用程序的客户端和服务器端。 首先,我们需要一个客户端(我们的CD服务器),该客户端将在成功(或失败)部署后发送请求。 其次,我们将使服务器监听这些请求,并将其进一步发送给所选的消息提供者。
说到用来发送那些消息的服务,那是100%的。 就个人而言,我使用Telegram机器人将消息传递回给我,因此我将以此为例,但是这种设计允许使用任何方法来传递消息,例如SMS,电子邮件,Slack或其他。
客户
与CD服务器一样,我们将需要一种检查源真实性的方法。 这次,我们将使用JWT或JSON Web令牌对消息进行签名。 另外,这次我们将同时执行签名和验证。
让我们从编写两个用于处理JWT生成的辅助函数开始。
function _getHash ( params ) {
const paramString = JSON .stringify(params);
const hash = crypto
.createHash( 'sha256' )
.update(paramString)
.digest( 'hex' );
return hash;
}
function _sign ( hash, secret ) {
const payload = {
iss : 'server' ,
sha256 : hash,
};
const token = jwt.sign(payload, secret);
return token;
}
在这里, _getHash
创建消息正文的SHA256哈希,然后_sign
使用机密对其进行签名。 让我们在客户中使用它。
const axios = require ( 'axios' );
const crypto = require ( 'crypto' );
const jwt = require ( 'jsonwebtoken' );
const client = axios.create({
baseURL : 'https://our.reporting.server.url' ,
});
async function sendSuccess ( app ) {
const params = {
success : true ,
app,
}
const secret = process.env.SECRET;
const hash = _getHash(params);
const token = _sign(hash, secret);
await client.post( '/cd/server' , params, {
headers : {
'X-Signature' : token,
},
});
}
在这里,我们从.env
文件中获得了秘密,使用它来签署请求正文,然后将其发送到我们的报告服务器。
几件事要注意:
- 报告服务器所在的URL,
our.reporting.server.url
用您的URL替换our.reporting.server.url
。 - 我们向其发送请求的端点; 我使用
/cd/server
因为我有Netlify等其他来源来接收更新,但是您可以使用任何东西,包括/
。 -
X-Signature
标头:同样,它几乎可以是任何东西,但是我建议您坚持使用类似的东西,因为这是一种标准。
那就是我们的客户。 现在让我们看一下服务器。
服务器
同样,我们从一个辅助函数开始。
function checkSignature ( data, signature, secret, issuer ) {
if (signature == undefined ) {
return false ;
}
let decoded;
try {
decoded = jwt.verify(signature, secret);
} catch (e) {
return false ;
}
const dataString = JSON .stringify(data);
const hash = crypto
.createHash( 'sha256' )
.update(dataString)
.digest( 'hex' );
const hashMatches = decoded.sha256 == hash;
const issuerMatches = decoded.iss == issuer;
if (!hashMatches || !issuerMatches) {
return false ;
}
return true ;
}
类似于CD服务器上的文章中的文章,此checkSignature
函数可验证签名是真实的。
这是其余的服务器代码。
const crypto = require ( 'crypto' );
const jwt = require ( 'jsonwebtoken' );
app.post( '/cd/server' , async (req, res) {
const data = req.body;
const signature = req.header( 'X-Signature' );
const secret = process.env.SERVER_SECRET;
const issuer = 'server' ;
if (!checkSignature(data, signature, secret, issuer)) {
res.status( 403 ).end();
}
const success = data.success;
const app = data.app;
const error = data.error;
bot.cd( 'Server' , app, success);
res.send( 'Hello server!' );
});
我们在这里所做的是检查签名并发送消息。 通过您选择的提供者发送一条消息。 在这里,它是Telegram机器人( bot.cd('Server', app, success);
)。
奖励:Netlify
再举一个例子,让我们尝试每次在Netlify上更新前端时发送一条消息。
现在,Netlify显然不需要像CD本身那样击中我们的CD服务器。 相反,Netlify Webhook将直接进入我们的报表服务器。
值得庆幸的是,这里我们可以重用之前编写的大多数代码(Netlify使用JWT签署Webhook请求)。
app.post('/cd/netlify' , async (req, res) {
const data = req.body;
const signature = req.header( 'X-Webhook-Signature' );
const secret = process.env.NETLIFY_SECRET;
const issuer = 'netlify' ;
if (!checkSignature(data, signature, secret, issuer)) {
res.status( 403 ).end();
}
const success = data.state == 'ready' ;
const app = data.name;
bot.cd( 'Netlify' , app, success);
res.send( 'Hello Netlify!' );
});
在这里,我们从标题中提取签名,将其与我们本地存储的密钥相匹配,如果签名有效,则发送一条消息。
注 : NETLIFY_SECRET
和SERVER_SECRET
不必是不同的,但我强烈建议让他们如此。 否则,如果一个密钥泄露(例如,由于对Netlify的黑客攻击),那么另一个密钥也将受到威胁,从而使堆栈的安全性降低。
要在Netlify上添加webhooks,请打开一个项目,然后单击Settings -> Build & Deploy -> Deploy notifications
,然后按Add notification -> Outgoing webhook
。 您可以为成功或失败的构建添加Webhook。
奖励2:错误处理
好的,我知道您现在已经累了,但是还有一件我想与您分享的令人兴奋的事情:错误记录。 换句话说,当您的应用出现错误时,它将使您得到通知。
从本质上讲,这与从CD服务器发送请求非常相似,只是这次我们将发送错误。
在您的Node.js应用中,添加自定义错误处理程序:
function errorWatcher ( err, req, res, next ) {
if (process.env.ENV == 'dev' ) {
console .log(err);
}
if (process.env.ENV == 'prod' ) {
_sendRuntimeFailure(err.toString());
}
next(err);
}
async function _sendRuntimeFailure ( error ) {
const app = 'my-app' ;
const params = {
app,
error,
};
const hash = _getHash(params);
const secret = process.env.SECRET;
const token = _sign(hash, secret);
await client.post( '/runtime' , params, {
headers : {
'X-Signature' : token,
},
});
}
函数_getHash
和_sign
与我们上面使用的相同。 我们还使用.env
将ENV变量设置为dev
或prod
。 这样,只会将生产错误发送给您。
剩下的唯一事情就是告诉快递我们的处理程序。
app.use(errorWatcher);
我们还需要包装异步路由,以确保将错误传递给我们的处理程序。
app.get('/endpoint' , wrapAsync(router.endpoint));
// Helper function to pass error down the middleware chain
function wrapAsync ( fn ) {
return function ( req, res, next ) {
fn(req, res, next).catch(next);
};
}
而已。 在报告服务器端,它与我们用于CD服务器和Netlify的服务器100%相同:获取签名,对其进行验证并发送消息表明签名有效。
结语
在这里,我们创建了另一个微服务器,这次用于报告。 服务器从多个来源收集事件,并将事件路由到单个位置,例如Telegram。 我们设法根据CD服务器,Netlify和express.js应用程序的错误处理程序发送事件。
翻译自: https://hackernoon.com/devops-shouldnt-be-hard-reporting-s8k2k2r
devops部署