Posted at

ServerlessなOpsを考える


はじめに

Serverless Advent Calendar 2018 の18日目です。

ServerlessOps に関連した、ちょっとしたTipsを紹介します。



No Opsな時代を目指して...


ServerlessなOpsに関する個人的な心得

私は日々のサービス開発で 意地のサーバーレス をモットーに、主にAWSのFaaSやFully Managed Servicesのみを使ってシステム開発をしているわけですが、他にもこだわりがあって、

AWSコンソールにログインしたら負け

というポリシーを持っています。 (※よく負ける)

昔は sshしたら負け とかよく言ってましたが、Serverlessをやっているとsshするケースなんてほとんど存在しないため、インスタンスへのsshログインの次はコンソールログインと闘い始めたわけであります。

いつか、 まだAWSコンソールで疲弊しているの? と言われないために...

(たぶんずっと言われない)


コンソールログインは邪悪か?

いいえ、邪悪ではありません。

ただ、管理しているAWSのRootアカウントやIAMユーザーの数が増えてくると、


  • ID / Passwordの管理が面倒

  • ログイン毎のMFAコードの入力がうざったい

  • 会社さんによってはAWSコンソールにログインできる場所や端末が限られている? (未確認)

  • IAMの権限管理が面倒

などなど、色々と課題は出てきます。

また、頻繁にコンソールにログインしているうちは No Ops とは遠い状態にいることは確かです。

とは言っても日々のサービス運用でコンソールへのログインが必要になるケースは発生します。

その際に、コンソールでの単純作業の運用手順書を作る...なんて仕事は間違ってもやりたくないですし、何回も同じ事象でコンソールログインしている場合、私は積極的にChatOps化を検討しています。

ここで言うChatOpsは、主にSlackのSlash Commandを使ったOpsだと思ってください。


ChatOpsの何が楽なのよ?

もちろんコンソールにログインしなくても作業できるので楽ができます。

Slackという 24/7 でAccessibleな、大変ブラックなツールが身近にあるのに、使わない手はないわけです。

コンソールへのログインを無くしてちょっとでも楽をして、より Less Ops な状態にし、 No Ops に向かって進化したいのです。


ChatBotに向いているOpsって?


  • 日々のOpsでAWSコンソールで行っている単純作業


    • ログ検索

    • IAMの権限管理

    • 各種リソースのパラメータ調整



  • 外部からの依頼で行う、ある程度手順が決まった作業


    • テストデータを投入してほしいんだけど、とか



などなど、色々あると思います。

従来はこういった作業を簡単に行うために、Scriptを書いてEC2インスタンスに置いて実行したりしていましたが、なんとサーバーレスな世界ではEC2インスタンスを立てられません!!

結果的にSlackのSlach Commandを使うのが最もお手軽でした。



ServerlessなChatOps

散々ポエムを書きましたが、ここからが本題 (?) です。

適当な課題をServerlessなChatOpsで解決してみます。


課題

Serverlessなマイクロサービス群でシステムを構築していて、とある HogeService でエラーが発生し、Slackに通知が飛んできました。

Alarmを読み解くと、

- DBからデータが取得できずにエラーが発生した

- どうやらLambdaで処理したrequestIdは 12345678-aaaa-bbbb-cccc-1234567890ab のようだ

このAlarmの前後で何が起こっているのかログを調べよう!ということで、


  1. AWSコンソールにログイン、

  2. CloudWatchのサービスページに移動して、

  3. CloudWatch Logsを開いて、

  4. 対象のLambda Functionのロググループを探して、

  5. 対象のログストリームからエラーが発生したrequestIdを検索して、

  6. 該当のrequestIdが付与された一連のトランザクションのログを表示

..と、これでようやくログの調査ができます。

このOpsを、SlackのSlach Commandで簡単に行えるようにしたいと思います。


開発

当然ですが、ChatOpsな機能もServerlessを使って開発します。

何かしらのPaaSのような、アイドル時に課金されてしまうサービスを使うと負けです。


構成


  1. Slackで、Slash Command (例えば /logsearch) とRequest IDを入力する

  2. SlackからのコマンドはAPI Gatewayで受ける

  3. LambdaをInvokeし、AWS SDKを使って CloudWatchLogs.filterLogEvents を使ってログを検索する

  4. 結果をLambdaのレスポンスで返す

  5. Slackに一連のログが表示される

Bot開発のフレームワークは何でもいいのですが、個人的には claudia-bot-builder が好きでよく使います。

3については、こんな感じの関数を作っておくと便利です。

(細かい説明は割愛します)

const queryLogs = (lambdaName, utcDate, requestId) => {

const params = {
logGroupName: `/aws/lambda/${lambdaName}`,
filterPattern: `"${requestId}"`,
logStreamNamePrefix: `${utcDate}`,
limit: 20
};

return new Promise((resolve, reject) => {
CloudWatchLogs.filterLogEvents(params).promise().then((data) => {
const rawLogs = data.events;
_.sortBy(rawLogs, 'timestamp');

const logs = [];
for (rawLog of rawLogs) {
logs.push(rawLog.message);
}

resolve(logs);
}).catch((err) => {
reject(err);
});
});
};


この構成には問題あり...

この構成で動くこともありますが、ログの検索に少し時間がかかるため、だいたいSlackのResponse時間制限の3秒が経過してしまってSlack側がタイムアウトします。

実運用する際は、最初のLambdaはSlackのコマンドを受け取って非同期タスクを実行し、すぐにResponseを返すべきです。

非同期タスクの実行は、通知の柔軟性を考慮するとSNSを挟むのが良いかと思います。

わざわざ構成図を描く必要はないと思いますが、あえて描くとこんな感じです。


  1. Slackで、Slash Command (例えば /logsearch) とRequest IDを入力する

  2. SlackからのコマンドはAPI Gatewayで受ける

  3. LambdaをInvokeし、SNSのTopicにデータをPublishして、すぐにSlackにResponseを返す

  4. SNSにAsyncTask用のLambdaをSubscribeさせておき、AWS SDKを使って CloudWatchLogs.filterLogEvents を使ってログを検索する

  5. 結果をSlackに送信する

  6. Slackに一連のログが表示される

結果的に、Slack上でこんな感じの結果が得られます。


Slash Commandの例

/logsearch 12345678


結果


まとめ

どうでしょう?


Before

1. AWSコンソールにログイン、

2. CloudWatchのサービスページに移動して、
3. CloudWatch Logsを開いて、
4. 対象のLambda Functionのロググループを探して、
5. 対象のログストリームからエラーが発生したrequestIdを検索して、
6. 該当のrequestIdが付与された一連のトランザクションのログを表示


After

1. /logsearch ${requestId} と、Slackにコマンドを打つだけ




コンソールへのログインを省略したおかげで、ずいぶんと楽になった気にならないでしょうか??

こんな感じで Less Ops 化を進め、 No Ops な時代に向けて少しずつ進んでいきたい次第でございます。


投稿内容は個人の意見であり、所属企業の意見を代表するものではありません。