はじめに
Serverless Advent Calendar 2018 の18日目です。
Serverless な Ops に関連した、ちょっとした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の前後で何が起こっているのかログを調べよう!ということで、
- AWSコンソールにログイン、
- CloudWatchのサービスページに移動して、
- CloudWatch Logsを開いて、
- 対象のLambda Functionのロググループを探して、
- 対象のログストリームからエラーが発生したrequestIdを検索して、
- 該当のrequestIdが付与された一連のトランザクションのログを表示
..と、これでようやくログの調査ができます。
このOpsを、SlackのSlach Commandで簡単に行えるようにしたいと思います。
開発
当然ですが、ChatOpsな機能もServerlessを使って開発します。
何かしらのPaaSのような、アイドル時に課金されてしまうサービスを使うと負けです。
構成
- Slackで、Slash Command (例えば
/logsearch
) とRequest IDを入力する - SlackからのコマンドはAPI Gatewayで受ける
- LambdaをInvokeし、AWS SDKを使って
CloudWatchLogs.filterLogEvents
を使ってログを検索する - 結果をLambdaのレスポンスで返す
- 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を挟むのが良いかと思います。
わざわざ構成図を描く必要はないと思いますが、あえて描くとこんな感じです。
- Slackで、Slash Command (例えば
/logsearch
) とRequest IDを入力する - SlackからのコマンドはAPI Gatewayで受ける
- LambdaをInvokeし、SNSのTopicにデータをPublishして、すぐにSlackにResponseを返す
- SNSにAsyncTask用のLambdaをSubscribeさせておき、AWS SDKを使って
CloudWatchLogs.filterLogEvents
を使ってログを検索する - 結果をSlackに送信する
- 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
な時代に向けて少しずつ進んでいきたい次第でございます。
投稿内容は個人の意見であり、所属企業の意見を代表するものではありません。