天天看点

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应用程序的错误处理程序发送事件。

From: https://hackernoon.com/devops-shouldnt-be-hard-reporting-s8k2k2r