DevOps配置管理
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 = ; 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部署