連載
» 2017年09月05日 05時00分 公開

AWS Lambdaを活用したSlackとGitHubの連携&サーバレス活用事例3選AWS Lambdaで始めるサーバレスアーキテクチャ入門(終)(3/3 ページ)

[先崎一樹,三菱総研DCS]
前のページへ 1|2|3       

Lambda関数の作成

 続いて、Slackへの通知を行うLambda関数を作成します。

 Lambda関数の作成手順は前回の記事を参照ください。なお今回は、Lambdaからその他のAWSサービスを呼び出すことはないため、ログをCloudWatch Logsへと出力可能な権限「AWSLambdaBasicExecutionRole」が付与されていれば十分です。

 ソースコードは下記の通りです。handlerの外で定義している「const slack」を冒頭で確認した「Webhook URL」に、「const mention」はGitHubとSlackのユーザー名へと書き換えてください。

'use strict';
 
// httpsモジュールの読み込み
const https = require('https');
 
//SlackのIncoming Webhooks設定で取得したWebhook URLをセット
const slack = 'https://hooks.slack.com/services/********/********/********************';
 
//GitHubとSlackのユーザー名マッピングを定義
// KeyがGitHubのユーザー名、ValueがSlackのユーザー名
const mention = {
  '@kmassaki': '@dcs-kmassaki'
};
 
exports.handler = (event, context, callback) => {
 
  //GitHubの通知メッセージをSNS経由で取得
  console.log(JSON.stringify(event));
  const message = JSON.parse(event.Records[0].Sns.Message);
  console.log(JSON.stringify(message));
 
  //GitHubのイベントタイプを取得
  const eventType = event.Records[0].Sns.MessageAttributes['X-Github-Event'].Value;
 
  let text = '';
  switch (eventType) {
    // イベントタイプが "issue_comment"の場合
    case 'issue_comment': {
      const repositoryUrl = message.repository.html_url;
      const repository = '[' + message.repository.full_name + ']';
      const author = message.issue.user.login;
      const issueUrl = message.issue.html_url;
      const number = message.issue.number;
      const title = message.issue.title;
      const issue = '#' + number + ':' + title;
      const comment = mapping(message.comment.body);
      text += link(repositoryUrl, repository) \
            + ' New comment by ' + author + ' on issue ' + link(issueUrl, issue) + '\n';
      text += comment;
      break;
    }
 
    default: {
      break;
    }
  }
 
  if (text.length === 0) {
    callback(null, 'success');
  } else {
    const body = {
      text: text
    };
    console.log(JSON.stringify(body));
 
    const options = {
      host: slack.split('/')[2],
      port: 443,
      path: '/' + slack.split('/').slice(3).join('/'),
      headers: {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(JSON.stringify(body))
      },
      method: 'POST'
    };
    console.log(JSON.stringify(options));
 
    const req = https.request(options, (res) => {
      res.setEncoding('utf8');
      console.log(JSON.stringify({statusCode: res.statusCode}));
      console.log(JSON.stringify(res.headers));
      res.on('data', (chunk) => {
        console.log(JSON.stringify({chunk: chunk}));
      });
      res.on('end', () => {
        console.log(JSON.stringify({message: 'No more data in response.'}));
        callback(null, 'success');
      });
    });
 
    req.write(JSON.stringify(body));
 
    req.on('error', (e) => {
      console.log(e);
      callback(e);
    });
 
    req.end();
  }
 
  // リンクを生成する関数
  function link(url, text) {
    return '<' + url + '|' + text + '>';
  }
 
  //GitHubとSlackのユーザー名をマッピングする関数
  function mapping(comment) {
    const result = comment.replace(/@[a-zA-Z0-9_\-]+/g, (match) => {
      return mention[match] || match;
    });
    return result;
  }
};

イベントトリガーの設定

 Lambda関数の作成が完了したらLambdaのイベントトリガーにSNSを追加して完了です。マネジメントコンソールのSNS管理画面から先ほど作成したSNS Topicを選択し、「Actions > Subscribe to topic」と選択します。

 「Protocol」に「AWS Lambda」、「Endpoint」に先ほど作成したLambda関数を選択し、「Create Subscription」を選択します。

 Lambda関数のトリガー画面でSNS Topicの「Arn」が確認できたら設定完了です。

テスト

 最後に、テストしてみましょう。

 GitHubリポジトリの「Issues」からメンション付きでコミットしてみます(※自分宛てのメンションとなっている点はご了承ください)。

 するとSlackに通知されることが確認できると思います。ユーザー名もきちんと変換され、Mention もされてます。

 以上で完了です。上述のLambda関数をカスタマイズすることで、Slackへ通知させるイベントの種類を追加したり、通知内容そのものを変更したりすることも可能です。興味のある方は試してみてください。

サーバレスアーキテクチャの活用事例3選

 その他、サーバレスアーキテクチャを活用した幾つかの事例を紹介します。

ChatOps環境の構築

 今回構築したサーバレスアーキテクチャはGitHubからSlackへ通知を行うものでしたが、Slack上でコマンドを実行し、GitHubで管理されるアプリケーションをリリースすることも可能です。

 システム構成は下記の通りで、Slack上でのリリースコマンドをAPI Gatewayで受け、LambdaがCodeDeployをキックすることでGitHub上のリソースがEC2(アプリケーション)に展開されます。CodeDeployの処理結果はSNSとLambda経由でSlackへと通知されます。

 GitHubからSlackへのプッシュ通知は今回構築した仕組みで実現しています。

自動運用ジョブの構築

 続いては、Lambdaを活用した自動運用ジョブの一例を紹介します。

 EC2を利用してサーバを構築した際、有事の際の備えとしてスナップショットを取得したり、サーバを利用していない時間帯は停止したりと、手動で運用しようとすると結構な手間がかかります。サーバの台数が少ないうちはいいですが、台数の増加に比例して運用がとても大変になり、手動運用によるミスが発生することも考えられます。

 本連載で紹介したサーバレスアーキテクチャの仕組みを活用することで、これらの運用を自動実行することが可能です。

 下記はEC2のスナップショットを自動で取得するシステム構成の一例です。AWSから提供されるEC2のAPIをLambdaから実行することでスナップショットが取得でき、CloudWatch EventsをLambdaのイベントトリガーに登録することで定期実行させます。Lambdaでのスナップショット取得処理はCloudWatchで監視され、処理に失敗した際にSNS経由で管理者へと通知します。

 Lambdaを作り込むことでスナップショットの世代管理を行うことも可能です。弊社ではEC2のタグを活用し、特定のタグに世代数を入力することで過去の不要なスナップショットを自動削除する運用も行っています。

静的ホスティングサイトのアクセスログ管理

 最後に、CloudFrontとS3で構築した静的ホスティングサイトのアクセスログ管理にサーバレスアーキテクチャを活用した事例を紹介します。

 CloudFrontとS3を利用すると、とても簡単にWebサイトを構築できますが、サービスの標準機能だけだとWebサイトのアクセスログはS3へ収集することになります。バックアップ目的であればS3への収集で十分ですが、特定の時間帯のログを確認したりキーワード検索を行ったりするとなると、Athenaなどのサービスを活用する必要があります。もっと手軽にログの確認を行うため、アクセスログをCloudWatch Logsへと転送する仕組みを構築しました。

 下記がシステム構成です。CloudFrontとS3のアクセスログがS3に書き込まれるのをイベントトリガーとし、LambdaでCloudWatch Logsへログ転送を行います。とてもシンプルですが非常に役立っています。

最後に

 本連載では、3回にわたりサーバレスアーキテクチャについて解説してきました。サーバレスアーキテクチャそのものの紹介からサンプルアプリケーションの構築と、最後までお付き合いいただきありがとうございます。本連載を通じて、サーバレスアーキテクチャに興味を持ち、システム開発に役立てていただくことを願っています。

前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。