Mackerelの公式プラグインをAWS Lambdaで実行してAmazon RDS for MySQL を監視する
Mackerelの公式プラグイン集や公式チェックプラグイン集は、各種ミドルウェアの詳細監視ができたり、AWS Integrationを使わなくてもRDSやELBなどのマネージドサービスのメトリック情報を取得することができたりと、大変便利なものです。
このプラグインはAWSのEC2など mackerel-agentがインストールできる環境からは簡単に使うことができるのですが、例えばAWS上に Web-アプリケーション-DB の3層アーキテクチャを構成している場合に、EC2がAutoScaling対象のWebサーバやアプリケーションサーバしかないことがあり、DB(RDS)を監視するのにこのプラグインをどのEC2から使うか、少々悩ましいことがあります。
- AutoScaling対象のEC2全てからプラグインを実行する場合
- チェックプラグインの場合、RDSに異常が発生するとAutoScaling対象のEC2の台数分(重複して)アラートが上がってしまう
- AutoScaling対象のEC2とは別に、RDS監視用のEC2を用意する場合
- 監視用EC2に障害が発生するとRDSの監視が止まってしまうので、冗長構成にするなど監視用EC2の可用性を高める工夫をしなければならない
- 監視用EC2自体の監視も必要になるため、Mackerel監視対象のホスト数が増えてしまう = コストが増えてしまう ことになる
そこで、この便利なプラグインをAWS Lambdaから定期的に実行できれば、安く*1、アラートも重複せず、安定してRDSなどのマネージドサービスを監視できるのでは、と考えました。
この記事では、MySQLのメトリックを取得する mackerel-plugin-mysql を使ってAmazon RDS for MySQL を監視する例をまとめます。
事前準備
AWSやMackerelのアカウントは取得済みとします。
またAWS上にすでにシステムは稼働しており、監視対象の RDS for MySQLの構築やその他セキュリティグループ等の設定は済んでいるものとします。
公式プラグインのバイナリを用意する
AWS Lambdaで実行できる形式のバイナリファイルを作成するため、一時的にEC2を立ち上げます。
まずはAWS公式サイトの情報を元に、AWS Lambdaの実行基盤となっているAmazon LinuxのAMIイメージを探します。
2017/10/15 時点だと amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2 です。
当該AMIを使ってEC2インスタンスを起動します。
起動したEC2にSSHでログインし、mackerel-agent, 公式プラグイン集 mackerel-agent-plugins をインストールします。
$ curl -fsSL https://mackerel.io/file/script/amznlinux/setup-all-yum.sh | MACKEREL_APIKEY='<YOUR API KEY>' sh $ sudo yum install mackerel-agent-plugins
Mackerelのプラグインが正しくインストールされたかを確認するため、手動でpluginのコマンドを実行してみます。
-host
オプションで指定するRDSのエンドポイントはAWSマネジメントコンソールのRDSのメニューから確認してください。
$ mackerel-plugin-mysql -host=sample-db.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -username=<USER_NAME> -password=<PASSWORD>
以下のように、{metric name}\t{metric value}\t{epoch seconds} (\t はタブ文字) の形式でたくさんの情報が標準出力に表示されれば成功です。
mysql.innodb_buffer_pool.pool_size 38208.000000 1507986274 mysql.innodb_buffer_pool.database_pages 2717.000000 1507986274 mysql.innodb_buffer_pool.free_pages 35484.000000 1507986274 mysql.innodb_buffer_pool.modified_pages 0.000000 1507986274 mysql.innodb_row_lock_waits.Innodb_row_lock_waits 0.000000 1507986274 mysql.innodb_adaptive_hash_index.hash_index_cells_total 1238989.000000 1507986274 (中略) mysql.innodb_semaphores.spin_waits 0.000000 1507986274 mysql.innodb_semaphores.spin_rounds 0.000000 1507986274 mysql.innodb_semaphores.os_waits 0.000000 1507986274
MackerelにRDS用のホストを登録し、メトリックを投稿する
先ほど立ち上げたAmazonLinuxのEC2に、Mackerel の CLIツールである mkr コマンドをインストールします。
$ sudo yum install mkr
Mackerelに監視対象のRDSをホストとして登録します。
以下の例ではホスト名をtest-RDS、Mackerel上のロール名を TEST:DB としてホストを作成しています。
$ mkr create test-RDS -R TEST:DB created SAMPLE12345
成功するとHostIDが表示されるので、これを控えておきます。
今回だと SAMPLE12345 です(実際には11文字のランダム文字列)。
Mackerelの画面でもホストとサービス・ロールが登録されていることが確認できます。
続いて今登録したホストのカスタムメトリックとしてRDS上のMySQLのメトリック情報を投稿します。
先ほど動作確認に使ったコマンドの結果をパイプで mkr throw
に渡してMackerelに投稿します。
$ mackerel-plugin-mysql -host=sample-db.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -username=<USER_NAME> -password=<PASSWORD> | mkr throw --host SAMPLE12345
以下のような結果が標準出力に表示されれば成功です。
thrown SAMPLE12345 'custom.mysql.join.Select_full_join 0.000000 1507987901' thrown SAMPLE12345 'custom.mysql.join.Select_full_range_join 0.000000 1507987901 ' thrown SAMPLE12345 'custom.mysql.join.Select_range 0.000000 1507987901' thrown SAMPLE12345 'custom.mysql.join.Select_range_check 0.000000 1507987901' (中略) thrown SAMPLE12345 'custom.mysql.innodb_buffer_pool_read.read_evicted 0.000000 15 07987901' thrown SAMPLE12345 'custom.mysql.innodb_buffer_pool_read.read_random_ahead 0.000000 15 07987901' thrown SAMPLE12345 'custom.mysql.innodb_checkpoint_age.uncheckpointed_bytes 0.000000 15 07987901'
Mackerel上で見てもメトリックが投稿されグラフが作成されていることがわかります。
ここまでの手順で作成したプラグインや mkrコマンドのバイナリファイルを、普段お使いの開発マシンなどにコピーしておきます。
このAmazonLinux EC2についてはLambda上で実行できる形式のバイナリファイルを作成するのが目的だったので、もう停止・削除してしまって構いません。
AWS Lambdaから実行できるようにする
今までの手順で作成した (Lambdaの実行基盤であるAmazonLinux 上でインストールして生成された) mackerel-plugin-mysql と mkr のバイナリファイルをLambdaのコードと一緒に固めてアップロードし、ハンドラ関数の中でそのバイナリファイルを実行するようなLambdaファンクションを作ります。それをCloudWatch Eventsで定期スケジュール実行すればよいことになります。
今回はCloudWatch EventsやIAM Role等の周辺設定を自動で行うため Serverless Framework (v1.23.0)を使って Node.js 6.10 のLambdaファンクションを実装しました。 Serverless Framework のインストール手順やサービス作成手順等は公式サイトやネット上に情報がありますので割愛します。
(任意のディレクトリ)/
├ .gitignore
├ bin/
│ ├ mackerel-plugin-mysql
│ └ mkr
├ handler.js
├ package.json
└ serverless.yml
- serverless.yml
service: sls-postCustomMetricToMackerel # 任意のサービス名 provider: name: aws runtime: nodejs6.10 region: ap-northeast-1 # 監視対象のRDSがあるリージョン functions: mackerel: handler: handler.postCustomMetricToMackerel name: ${self:service} events: - schedule: rate(1 minute) # CloudWatch Eventsで1分毎にスケジュール実行 environment: DBHOST: sample-db.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com # 監視対象のRDSのエンドポイント DBUSER: sampleuser # 監視対象のRDSの接続ユーザ名 DBPASS: S@mple # 接続ユーザのパスワード MACKEREL_HOSTID: SAMPLE12345 # 監視対象のRDSのMackerel上のHostID MACKEREL_APIKEY: # MackerelのAPI KEY vpc: securityGroupIds: - sg-xxxxxxxx # 監視対象のRDSにMySQL接続できるセキュリティグループを指定 subnetIds: - subnet-yyyyyyyy # 監視対象のRDSにMySQL接続できるサブネットを指定 - subnet-zzzzzzzz # 監視対象のRDSにMySQL接続できるサブネットを指定
簡単のため、DBの認証情報をそのまま環境変数に渡していますが、実運用上はKMSなどで暗号化して渡し、Lambdaの中で復号して使うのが良いでしょう。
- handler.js
'use strict'; const exec = require('child_process').exec; const dbhost = process.env.DBHOST; const dbuser = process.env.DBUSER; const dbpass = process.env.DBPASS; const mackerelhostid = process.env.MACKEREL_HOSTID; const mackerelApi = process.env.MACKEREL_APIKEY; const basedir = process.env.LAMBDA_TASK_ROOT; const cmd = `${basedir}/bin/mackerel-plugin-mysql -host=${dbhost} -username=${dbuser} -password=${dbpass} | MACKEREL_APIKEY=${mackerelApi} ${basedir}/bin/mkr throw --host ${mackerelhostid}`; module.exports.postCustomMetricToMackerel = (event, context, callback) => { let child = exec(cmd, function(err, stdout, stderr){ if (!err) { console.log('standard out: ' + stdout); console.log('standard error: ' + stderr); callback(null, 'Success!'); } else { console.log("error code: " + err.code + "err: " + err); callback(err); } }); };
sls deploy
コマンドでデプロイすると、LambdaファンクションとそのトリガとなるCloudWatch Events、Lambdaファンクションに割り当てるIAM Roleが作成されます。
AWS Lambdaのコンソールからテスト実行して成功すれば、あとは放っておくだけで1分毎に RDS for MySQL のメトリック情報がMackerelに投稿されます。
まとめ
Mackerelの公式プラグインをAWS Lambdaで定期実行する仕組みを試作しました。これにより、監視専用のEC2インスタンスを立ち上げることなくRDSなどのマネージドサービスの監視を行うことができました。
ただし、実運用に投入する際はCloudWatch AlarmなどでこのLambdaファンクションが正常に実行されているかなどを監視する必要があります。