Mackerel事始め mkr(4) dashboards

mkr v0.11.1 で dashboardsサブコマンドが追加されています。
公式に詳細説明があります。
が、どういう風に見えるのかは載っていないので、説明にある内容でのダッシュボード表示を試してみます。
dashboards
mkr v0.11.1 以上で dashboards コマンドを使用できます。
$ mkr help | grep -A 1 -e VERSION -e dashboards
VERSION:
0.11.3
--
dashboards
help, h Shows a list of commands or help for one command
dashboards help
機能は今の所 generate のみです。
-p 付与で標準出力へ、オプション無しだと Mackerel への反映となります。
同一名称(url_path)のダッシュボードが既に存在する場合でも、上書きされます。
$ mkr dashboards generate -h
NAME:
generate - Generate custom dashboard
USAGE:
mkr generate
DESCRIPTION:
A custom dashboard is registered from a yaml file.
Requests "POST /api/v0/dashboards". See https://mackerel.io/ja/api-docs/entry/dashboards#create.
OPTIONS:
--print, -p markdown is output in standard output.
ホストグラフ指定
ホストとメトリックを指定するホストグラフの一覧
ホストグラフの例を表示します。
複数ホスト・メトリックを縦横に並べたダッシュボードの生成になります。

個別グラフ指定
サービスメトリックや式によるグラフなどを個別に指定するグラフの一覧
- service_name のみの指定でサービスグラフ
- service_name, role_name の指定でロールグラフ
- host_id の指定でホストグラフ
- query の指定で式によるグラフ
ここで言うサービスグラフは サービスメトリック であり、サービス名指定でロールを跨いでの表示ができるわけでは無いようです。
個別グラフの例を表示します。手頃なメトリックがなかったので指定しているメトリックは変えています。

yamlを定義しておくことで履歴管理、ある程度の使い回しができるようになります。 WebのUIでURLコピー&ペーストで作成するよりは作成しやすいかなと思いました。
Mackerel事始め AWSインテグレーション(EC2)
Mackerel の AWS インテグレーションに EC2 が追加されました。
とある環境で mackerel-agent のバージョンアップの機会があったので導入してみました。
AWSインテグレーションの導入は公式の手順で特に躓くこと無く導入できました。
導入時の注意点
適用する際の注意点としてはこの辺りかと思います。
- mackerel-agent 未導入でも EC2 の監視が可能
- mackerel-agent 0.34.0 以上 導入済みの場合、ホスト情報は統合される(重複カウントされない)
- mackerel-agent 0.34.0 未満 は統合されない(重複カウントされる)
- Free プランでは利用不可
取得内容の確認
当方環境では下記項目のグラフが表示されました。 ()内はメトリック名です。
- CPU (custom.ec2.cpu)
- CPU Credit Balance/Usage (custom.ec2.cpu_credit.*)
- Disk IO Read/Write (custom.ec2.disk_io.*)
- Disk OPS Read/Write (custom.ec2.disk_ops.*)
- Network Packets (custom.ec2.network_packets.*)
- Network Traffic (custom.ec2.network.*)
- Status Check Failed (custom.ec2.status_check_failed.*)
取得間隔は 5分と記載がありますが、 EC2側で Detailed Monitoring が有効となっている場合は 1分のグラフ表示となっていました。
mackerel-agent 無し
- mackerel-agent 未導入、もしくはバージョンが 0.34.0 未満の場合
- mackerel-agent 導入済みホストとは別のホストとして登録される

mackerel-agent 有り
- mackerel-agent バージョン 0.34.0 以上が導入済みの場合
- 同一ホストとして登録される

重複登録後に統合を行いたい場合
重複登録された後に mackerel-agent のアップデートを行いましたが、
EC2上で mackerel-agent をアップデート だけでは反映されませんでした。
アップデート時に mackerel-agent の再起動が掛かっており、
コマンドで確認しても正常に更新されている状態です。
- EC2 上の mackerel-agent Version
- 最新版(0.34.0) へ更新済み
$ /usr/bin/mackerel-agent version mackerel-agent version 0.34.0 (rev 694915a) [linux 386 go1.6.2]
- Mackerel 上のホスト情報
- 未更新(0.32.2) のまま

解消方法
ホストIDファイルを削除し新規登録することで、 ホスト情報のMackerelエージェントのバージョンが最新版になり、 AWSインテグレーションでの取得情報との統合が成されました。
# ホストID削除 $ sudo rm /var/lib/mackerel-agent/id # mackerel-agent 再起動 $ sudo /etc/init.d/mackerel-agent restart
尚、ホストの新規登録のため、既存情報への影響があります。
- 既存のメトリックスは引き継がれない
- 既存のホストは Poweroff となる
- 退役忘れに注意
これまで別の方法で監視していた Status Check Failed が取得できるようになったのは嬉しいです。
mackerel-agent の更新で新規ホスト登録となる点は改善して欲しいと思います。
AWS EC2 インスタンスの復旧(Auto Recovery)設定の落とし穴
AWS EC2 インスタンスには、 Status Checked Failed 発生時に自動的に復旧を試みる機能があります。
設定自体は正しく行えているように見えるのに、いざ異常発生時に復旧に失敗するケースに当たりました。
Action failed. Encountered error calling EC2 recover. (401: AWS was not able to validate the provided access credentials)
復旧に失敗した RecoveryAlarm は IAM Role を使用して CloudFormation で作成していましたが、作成(設定)自体は正常に行えていました。
結論としてはドキュメントに記載があるのですが、IAM Role で復旧アラームを作成している場合、復旧アクションは動作しません。
IAM ロール (たとえば、Amazon EC2 インスタンスプロファイル) を使用している場合は、アラームアクションを使用してインスタンスを停止、終了、または再起動することはできません。
尚、復旧(recover)アクションと同様に、 停止(stop)、終了(terminate)、再起動(reboot) を実行するアラームを作成できますが、 復旧(recover)とその他のアクションでは使用される実行権限が異なります。 (アラーム作成時の権限が使用されるのは 復旧(revocer) の場合のみ)
IAM ロールに基づいて、アラームアクションを使用してインスタンスを停止、終了、または再起動する場合は、EC2ActionsAccess ロールしか使用できません。他の IAM ロールはサポートされていません。別の IAM ロールを使用している場合は、インスタンスを停止、終了、または再起動できません。
AWS Security Token Service (AWS STS) を用いて許可された一時的な認証情報を使用している場合は、アラームアクションを用いて Amazon EC2 インスタンスを復旧することはできません。
ドキュメントの内容だけではわかり難かったので、実際に復旧アクションの挙動を確認してみました。
IAM 準備
IAM Role と IAM User での比較を行います。
IAM Role / IAM User
IAM Role と IAM User を準備します。今回はいずれも PowerUserAccess を付与しています。
- IAM Role

- IAM User

aws configure
デフォルトで IAM Role を使用し、profile=cfn で IAM User を使用できるよう設定します。
$ aws configure list
Name Value Type Location
---- ----- ---- --------
profile <not set> None None
access_key ****************EFEA iam-role
secret_key ****************dE0o iam-role
region ap-northeast-1 config-file ~/.aws/config
$ cat ~/.aws/credentials
[default]
region = ap-northeast-1
[cfn]
aws_access_key_id = ****************VO2A
aws_secret_access_key = ************************************QPgI
region = ap-northeast-1
Cloud Formation テンプレート準備
EC2 + RecoveryAlarm のテンプレートを用意します。
- ec2.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Outputs": {
"InstanceID" : {
"Value" : { "Ref" : "Ec2Instance" }
},
"RecoveryAlarm" : {
"Value" : { "Ref" : "RecoveryAlarm" }
}
},
"Resources": {
"Ec2Instance" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
"ImageId" : "ami-374db956",
"InstanceType" : "t2.micro",
"BlockDeviceMappings" : [
{
"DeviceName": "/dev/xvda",
"Ebs": {
"VolumeType": "gp2",
"VolumeSize": "8"
}
}
]
}
},
"RecoveryAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"Namespace": "AWS/EC2" ,
"MetricName": "StatusCheckFailed",
"Statistic": "Minimum",
"Period": "60",
"EvaluationPeriods": "5",
"ComparisonOperator": "GreaterThanThreshold",
"Threshold": "0",
"AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
"Dimensions": [{"Name": "InstanceId","Value": {"Ref": "Ec2Instance"}}]
}
}
}
}
RecoveryAlarm の作成
IAM Role と IAM User それぞれで CreateStack を実行します。
# IAM Role aws cloudformation create-stack \ --stack-name ec2-recoveryalarm-role \ --template-body file://ec2.json # IAM User aws cloudformation create-stack \ --stack-name ec2-recoveryalarm-user \ --template-body file://ec2.json \ --profile cfn
- IAM Role で作成したStack

- IAM User で作成したStack

- 作成したEC2インスタンス(Alarm付)

- 作成したRecoveryAlarm

RecoveryAlarm の実行確認
作成した RecoveryAlarm の状態を ALARM に更新し、挙動を確認します。 (システムステータスチェックのエラーを意図的に起こすことはできません。)
IAM Role で作成した RecoveryAlarm
# IAM Role で作成したRecoveryAlarm $ aws cloudwatch set-alarm-state \ --alarm-name "ec2-recoveryalarm-role-RecoveryAlarm-1SXN4O9QLTKH" \ --state-value ALARM \ --state-reason "Manual Update to ALARM"
401 エラーが発生し、Action が失敗します。

IAM User で作成した RecoveryAlarm
# IAM User で作成したRecoveryAlarm $ aws cloudwatch set-alarm-state \ --alarm-name "ec2-recoveryalarm-user-RecoveryAlarm-1HG4YDX2YZ90H" \ --state-value ALARM \ --state-reason "Manual Update to ALARM"
IAM User で作成した場合は問題無く、 Action が正常に終了します。

RecoveryAlarm を再作成
IAM Role で作成し、401エラーとなった RecoveryAlarm を IAM User からの実行で作成し直します。
$ diff ec2.json ec2_update.json 30a31 > "AlarmName": "ec2-recoveryalarm-role-RecoveryAlarm-renew", $ aws cloudformation update-stack --stack-name ec2-recoveryalarm-role --template-body file://ec2_update.json --profile cfn
- RecoveryAlarm の再作成(Delete/Update)

IAM User で "再作成" した RecoveryAlarm
作成し直した RecoveryAlarm の実行確認をします。
$ aws cloudwatch set-alarm-state \ --alarm-name "ec2-recoveryalarm-role-RecoveryAlarm-renew" \ --state-value ALARM \ --state-reason "Manual Update to ALARM"
IAM User で再作成した場合も、Action が正常に終了しました。

マネジメントコンソール上と、 describe-alarms で RecoveryAlarm を確認してみましたが、どの権限(IAM)で作成されたかの情報は保持していませんでした。
RecoveryAlarm を作成した際は実行確認を行い、権限エラーが発生しない事を確認しておいた方が良さそうです。
Mackerel事始め 将来予測機能
Mackerel の将来予測機能を試してみます。

機能としては式による監視で特定の関数(線形回帰)を使って実現するようです。
将来予測機能
式による監視の仕様
公式サイトの記載より
- 監視間隔は5分ごと
- 設定可能な式は、グラフの系列が1本になるものだけ
- 式が複雑過ぎる等で値が取れない場合はステータス Unknown としてアラートが発生
- 監視項目上限数20
- Free プランでは使用不可
線形回帰関数
使用できる関数は カスタマイズしたグラフを表示する - Mackerel ヘルプ で確認できます。
- linearRegression(metrics, duration)
- 現在時刻から duration 前 までのメトリック値をもとに線形回帰したメトリックを返します
- timeLeftForecast(metrics, duration, threshold)
- 現在時刻から duration 前 までのメトリック値をもとに線形回帰した値が threshold になるまでの残り秒数を返します
公式にある例では timeLeftForecast を使用しており、日数で閾値設定するため scale 関数を使用しています。
- scale(metrics, factor)
- 定数倍したメトリックを返します
1ホストのメモリ使用量について設定例
あまり良い例(グラフ)が無かったのですが、memory.usedに対して設定をしてみます。
対象グラフ
監視対象となる あるホストの1ヶ月のメモリ使用量のグラフ は以下になります。

監視設定
1ヶ月分のメトリックを使用して、メモリ使用量が 1.5GB となる日数を取得する式を設定してみます。
scale(timeLeftForecast(host('2KcXXXXXXXX', 'memory.used'),'1mo', 1500000000), 1/86400)
12.81日で到達するという予測となりました。

Excelの線形予測結果との比較
同metricsから値を取得し、Excelで線形予測を出した結果が以下になります。
取得したDatapoint、丸めなどで誤差が出てますが、概ね同じような予測となりました。

複数ホスト(role)に対しての設定例
hostIdに対しての設定だけだとホストが増えてきた場合に設定が追いつかなくなるので、role に対して設定します。
グラフの系列を1本だけにする という点に注意すれば他は1ホストの時と同じです。

ディスク使用量の予測設定例
予測機能の用途としては、やはり公式に記載されているディスク使用量に使用する事が多くなりそうです。
- 公式記載の式の例
scale(timeLeftForecast(host('host_id', 'filesystem.drive.used'),'3mo', 2000000000000), 1/86400)
式の例
- 特定ホスト/ドライブを対象
- hostId = 2KcXXXXXXXX 、 ドライブ = xvda3 の場合
host('2KcXXXXXXXX', 'filesystem.xvda3.used')
- 特定ホスト/全ドライブを対象
- ホストに紐付く全ドライブの中の最大値
- ドライブ指定を「*」
max(host('2KcXXXXXXXX', 'filesystem.*.used'))
- 特定ロール/全ドライブを対象
- ロールに紐付く全ドライブの中の最大値
- role = 'service:role' の場合
- ドライブ指定を「*」
max(role('service:role', 'filesystem.*.used'))
パーセンテージ設定
上記例だと絶対値で閾値設定を行う必要があるため、異なるディスクサイズの場合にそれぞれ設定する必要が出てきます。 となるとやはりパーセンテージで設定したくなるので、式を調整します。
- 対象ドライブ構成

ドライブ毎にディスクサイズが異なるので、ドライブ毎に設定が必要になるかと思います。 ロール内のディスク構成は同一である場合は以下のように定義可能です。
- ディスク使用率取得例
divide(
max(role('service:role','filesystem.xvda3.used'))
,max(role('service:role','filesystem.xvda3.size'))
)
- ディスク使用率の将来予測例
- 使用率が100%に到達する日数
scale(timeLeftForecast(divide(
max(role('service:role','filesystem.xvda3.used'))
,max(role('service:role','filesystem.xvda3.size'))
),'1mo',1), 1/86400)
通知例
通知メッセージには式の内容がそのまま入ります。 (少々見難いので、将来的には通知メッセージをカスタマイズできるようになると嬉しいですね。)

通常の閾値設定によるアラート発生前に傾向を掴めるというのは中々面白いのではないでしょうか。
長期間のメトリクスを対象にした設定を行えていないので、ディスク使用量の予測設定をして観察してみたいと思います。
Mackerel事始め mkrで残アラートのクローズ
Mackerelを使用しているとアラート発生後に復旧せずに残り続けるアラートが出てきます。
AWS インテグレーションで CloudWatch 上に値が出力されない物(ELB の ERROR 等、CloudWatch上 0 ではなく、値が無い物)が良く残ります。
Web上から一つずつクリックしてCloseするのは数が多くなってくると厳しいので mkr を使用して一括Closeを行います。
今回の判定条件はアラート発生後 n秒経過した物を対象とします。
(Close実行部分はコメントアウトしています)
export MACKEREL_APIKEY='XXXXXXXXXX'
# 経過秒数を指定
_SEC=86400
# epoch秒生成
_EPOCH=$(expr $(date +'%s') - ${_SEC})
echo "Target: $(date --date "@${_EPOCH}" +'%Y-%m-%d %H:%M:%S')"
#BSD
#echo "Target: $(date -r "${_EPOCH}" +'%Y-%m-%d %H:%M:%S')"
# アラートをクローズ
for _ID in $(mkr alerts | jq -r '.[] | select(.openedAt < '${_EPOCH}').id')
do
echo "${_ID}"
# mkr alerts close ${_ID}
done
- Closed by API

Mackerel事始め mkrでホストの退役
Mackerel で mkr と WebAPI を使用して poweroff にしたホストを退役します。
今回の判定条件は n日前のメトリクスが無いホストとします。(poweroff 直後のホストは非対象としています)

ApiKey/URL/Metricsを設定
検索対象のメトリクスは loadavg5 等必ず存在する物を指定します。
export MACKEREL_APIKEY='XXXXXXXXXX' _MACKEREL_URL="https://mackerel.io/api/v0" _METRICS="loadavg5" # 処理実行当日を含む日数 _KEEP_DAY=1
日数(epoch秒)生成
_KEEP_TO=$(date --date ''${_KEEP_DAY}' days ago' +'%Y-%m-%d 15:00:00')
_KEEP_TO=$(TZ=UTC date --date "${_KEEP_TO}" +'%s')
_KEEP_FROM=$(expr ${_KEEP_TO} - 86400)
_KEEP_TO=$(expr ${_KEEP_TO} - 1)
echo "From: $(date --date "@${_KEEP_FROM}" +'%Y-%m-%d %H:%M:%S')"
echo " To: $(date --date "@${_KEEP_TO}" +'%Y-%m-%d %H:%M:%S')"
日数(epoch秒)生成 (BSD)
OSXの場合デフォルトのままだとこちらになります。(GNU date導入済みであれば上記)
_KEEP_TO=$(date -v-${_KEEP_DAY}d +'%Y-%m-%d 15:00:00')
_KEEP_TO=$(date -jf "%Y-%m-%d %H:%M:%S" "${_KEEP_TO}" +%s)
_KEEP_FROM=$(expr ${_KEEP_TO} - 86400)
_KEEP_TO=$(expr ${_KEEP_TO} - 1)
echo "From: $(date -r "${_KEEP_FROM}" +'%Y-%m-%d %H:%M:%S')"
echo " To: $(date -r "${_KEEP_TO}" +'%Y-%m-%d %H:%M:%S')"
Metrics が存在しない host を退役
status が poweroff 且つ 実行日 - n日 のmetrics存在チェックをし、データが存在しないホストを退役します。
(実行すると有無を言わさず退役になるので、実行部分はコメントアウトしています)
for _ID in $(mkr hosts --status poweroff | jq -c -r '.[].id')
do
_RES=$(curl -s -S -X GET -H "X-Api-Key: ${MACKEREL_APIKEY}" "${_MACKEREL_URL}/hosts/${_ID}/metrics?name=${_METRICS}&from=${_KEEP_FROM}&to=${_KEEP_TO}" | jq -r '.metrics | length')
echo "HostId: ${_ID} / DataPoint: ${_RES}"
#[ ${_RES} -eq 0 ] && mkr retire --force ${_ID}
done
cron等で定期的に実行すると退役漏れが無くせるかと思います。


