何を作ったか
MackerelでAWS Lambdaのログ監視をしたいという時に、EC2などのインスタンスが必要になってしまうのがどうしても気になって・・・。
サーバーレスで動くシステムの監視にサーバーが必要になるのは何か悲し気持ちになるは私だけなのかな?皆さんはどうでしょうか?
今回そんな思いを胸に2年ほど前から構想を温めつつ少しづつ書いていたサーバーレス(AWS Lambda)で動作するMackerel-agentをなんとか動かせるようにしたのでそれについてグタグダ書いてみました。
ソースコード
https://github.com/masahide/mackerel-awslambda-agent/
とりあえずチェック系のプラグイン(check-aws-cloudwatch-logs-insights等)がなんとか動く所までを作ったという程度で、ぜんぜんドキュメントなども整ってなくお粗末で申し訳ない状態ですが、これから暇を見て色々整えつつVPC lambda化してメトリック系プラグインを動かしてRDS,elasticacheなどの監視ができるようにしたいと思ってます。
全体構成
以下のように複数のLambda関数に分けた構造にしています。
処理の流れ:
大まかな処理の流れは以下の通りで、CloudwatchEventのcronで毎分起動実行されます
- s3に設置している
mackerel config
をinvoker(lambda関数)
が読む - コンフィグに従い
invoker
がchecker(lambda関数)
を非同期invoke -
checker
に同梱したプラグイン実行ファイルを起動 - プラグインのレポートをSQSの
Report Queue
にポスト -
sender(lambda関数)
がReport Queue
に溜まったレポートをまとめてMackerel
にポスト
工夫した点など
プラグインが利用するステートファイルの永続化
今回のシステムではchecker lambda関数
に必要なプラグインの実行ファイルを同梱し、lambda関数内からプロセス起動する形で実装しています。
その別プロセスとして起動するプラグインには大抵の場合、次回実行時に備えて状態をStateDirのディレクトリに保存する仕組みがあります。しかし、lambda関数の場合は、実行が終了してしまうと一時保存したファイルなどは次回の実行時まで維持される保証がありませんので、これらのファイルを関数が終了する前にどこか別の永続領域に退避する必要があります。
今回は、プラグインが実行終了したタイミングでそれらのステートファイルをシリアライズしdynamodbに保存するようにしました。(上記の図には見づらくなるので載せませんでしたが...)
ステートファイルパスの固定
mackerel-agentには、AWS_SECRET_ACCESS_KEY環境変数などに設定されている値を元にstateファイルパスを算出する実装があります。この実装には、同じプラグインを使う設定が複数個存在する場合でもそれらが利用するステートファイルが重複しないようにする重要な役目があるのですが、lambda
の場合は、AWS_SECRET_ACCESS_KEY環境変数には制限時間のある一時キーが設定されているため、この実装が原因でファイルパスが実行時毎に異なってしまいうまくステートファイルが読めなくなってしまいます。
そのため今回は、AWS_SECRET_ACCESS_KEY環境変数などに設定されているAWSクレデンシャル情報を全て~/.aws/credentialsファイルに保存し直し、AWS_SECRET_ACCESS_KEY環境変数をunsetすることで生成されるstateファイルのパスを固定化されるようにしました。
Mackerelのメンテナンスに備える再試行処理
Mackerel自体がメンテナンスで数時間サービスが止まることがあるのですが、その間でも監視を続行して欲しい(通知は受けれなくても記録は後でみたい)ので、メンテ中はプラグインの実行結果を溜めておいてメンテ終わった後にまとめてポストするようにします。今回はSQSを使ってこの処理を実現しました。SQSのキューで計測処理と送信処理を分離しているので、mackerelがメンテになって投稿処理がつまっても、計測処理には何も影響がありません。また、SQSは簡単に再試行処理を実装できるので大変便利です。特にlambda関数のeventトリガーとしてSQSを利用した場合の再試行処理はとても簡単で、必要な処理が失敗した場合はその関数をエラーとして返すだけの実装であとはSQSが良い感じに再試行してくれるようになります。再試行のタイムアウト時間や試行回数はSQSのQueue側の設定値を調整するだけす。(これについてはCDKで行います)
CDKでのデプロイ
複数のlambda関数やS3,dynamodb,SQS,IAM roleなど結構な数のAWSリソースを設定する必要があり、これらを手でひとつづつ登録するのは現実的ではありません。今回はこれらをCDKでdeployするようにしました。
CDKを利用するとAWSリソースへのアクセスに必要になるIAM roleやIAM Policyを最小限の権限に絞って設定する事がとても簡単で直感的に記述できます。また、大量に作ることになるAWSリソースを1つの「アプリケーション」という括りでAWSコンソール上でも一元管理できるようになっており。迷子リソースなどが出にくいのもCDKの良いところだと思います。
デプロイ方法
前提条件
ビルドとデプロイには以下のソフトウェアを利用します
- Node.js 10.3.0以降(CDKでデプロイ用)
- go 1.14以降(lambda関数のビルド用)
- GNU Make 3.81(lambda関数のビルド用)
- AWS CLI(CDKを利用するためのcredentials設定用)
CDKを利用しAWS環境にデプロイする際はAdministratorAccess権限のアカウントもしくはロールが必要になり、それらをAWS CLI等を利用し~/.aws/credentialsファイルを構成しておく必要があります。。詳しくはCDKの前提条件のページを参照してください。
全体の流れ
デブロイの一連の流れは、以下の3工程です。
- エージェントの設定ファイルの準備
- lambda関数のビルド
- 上記で準備したファイルをCDKでデプロイ
エージェントの設定ファイルの準備
エージェントの設定は、プラグインの設定ファイルとCDKの設定の2カ所です。
プラグインの設定
config/agent.conf.example
にサンプルのコンフィグファイルがあります。
$ git clone https://github.com/masahide/mackerel-awslambda-agent.git
$ cd mackerel-awslambda-agent
$ cp config/agent.conf.example config/agent.conf
として編集して下さい。中身は以下のような内容で、大体mackerel-agentと同じです。(と言ってもAPIkeyの指定とpluginの設定しかありません)
apikey = "APIKEY"
[plugin.checks.cloudwatch-logs]
command = "check-aws-cloudwatch-logs-insights --log-group-name=/aws/lambda/xxxxxxxxx --filter='filter @message like /ERROR/'"
このconfig/agent.confは後述のCDKデプロイでS3バケットにアップロードされます。
CDKの設定
以下のcdk.jsonのcontext内にあるORGANIZATION
とHOSTNAME
を修正します。
-
ORGANIZATION
はmackerelのオーガニゼーション名 -
HOSTNAME
はこのawslambda-agentをmackerelに登録するホスト名
{
"app": "npx ts-node bin/cdk.ts",
"context": {
"@aws-cdk/core:enableStackNameDuplicates": "true",
"aws-cdk:enableDiffNoFail": "true",
"@aws-cdk/core:stackRelativeExports": "true",
"@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true,
"env": "dev",
"appName": "mackerel-awslambda-agent",
"envs": {
"dev": {
"environment" : {
"HOSTNAME": "mackerel-awslambda-agent", <-- ここ
"ORGANIZATION": "test", <-- ここ
"S3KEY": "config/agent.conf"
}
},
"prd": {
"environment" : {
"HOSTNAME": "mackerel-awslambda-agent", <-- ここ
"ORGANIZATION": "test", <-- ここ
"S3KEY": "config/agent.conf"
}
}
}
}
}
node.jsとgolangのインストールはそれぞれのサイトにお任せしするとしてそれ以降を以下に記載します。
lambda関数のビルド
lambda関数はmakeコマンドで作成します
$ make build
上記で3つのlambda関数がビルドされ.dist/
以下に配置されます。一緒に、check-aws-cloudwatch-logs-insightsプラグインの実行ファイルをgithubから取得され.dist/checker/
に配置されます。
cdkによるデプロイ
cdkのインストール
cdk本体を入れていない場合は以下を実行しインストール
$ npm install -g aws-cdk
$ cdk --version
1.76.0 (build c207717)
cdkを対象のAWSアカウントに初めて利用する際は、cdkのブートストラップスタックをインストールする必要があります。以下のコマンドでインストールできます。
cdk bootstrap
デプロイ
# cdkディレクトリに移動
cd cdk
# 関連パッケージのインストール
npm i
# cdk build
npm run build
# cdk deploy
npm run cdk deploy
以上で完了です。
参考:
-
https://github.com/kevinslin/open-cdk の
Tips and Best Practices