はじめに
今回やりたい事は、
- 毎日23:30にInstance自動停止アラートを通知する
- CloudWatch
- Lambda
- Slack
- 毎日23:59にInstanceを自動停止する
- CloudWatch
- Lambda
- Slackから自動停止ルールを制御する
- Slack
- AWS CLI
大別すると上記3つです。必要なコンポーネントも添えておきました。手順が多く面倒ですが一つ一つは何も難しい事はやっていません。
①自動停止アラートを通知する
Slackの設定は前回の記事を参考にして下さい。まずはLambda関数を作成します。
- 一から作成
- 関数名(任意)
- ランタイムはNode.jsを使用します。
- ※標準モジュールのみ使用します。
- アクセス権限
- 基本的なLambdaアクセス権限で新しいロールを作成
関数コードは次の通りです。
exports.handler = function(event, context) {
const https = require('https');
let postData = {
"attachments": [
{
"title": "【要確認!】",
"text": "t2.mediumインスタンス自動停止30分前!\n自動停止無効化コマンド実行して下さい"
}
]
};
let postDataStr = JSON.stringify(postData);
let options = {
hostname: 'hooks.slack.com',
port: '443',
path: '【Incomming Webhook URL パス部分】',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postDataStr)
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
context.succeed();
});
res.on('error', function (e) {
console.log("Got error: " + e.message);
context.done(null, 'FAILURE');
});
});
req.write(postDataStr)
req.end()
}
※個人的メモ
最初exports.handler = async function(event, context) {}
で定義していて実行されなかった(初回だけ)。これはreturn
が無いのでPromise
が終了した時点でイベントループが空になっていなかろうがプログラムが終了し、Promise
を宣言していない為にコネクションが確立する前に終わってしまったと考察。async
が無ければイベントループが空になるまでLambda関数は再施行される。
続いてCloudWatchにて定期実行のルールを作成する。
- スケジュール
- Cron式
- 世界標準時での指定
- 任意の曜日は「?」
- Cron式
- ターゲット
- Lambda関数
②Instance自動停止
これもLambdaで実装します。ランタイムはPython2.7を使用します。コードは次の通りです。今回は3台落とす体です。
import boto3
# setting RegionID & InstancesID
region = '【リージョンID】'
def lambda_handler(event, context):
# k8s-master
instances = ['【インスタンスID】']
ec2 = boto3.client('ec2', region_name=region)
ec2.stop_instances(InstanceIds=instances)
print 'stopped your instances: ' + str(instances)
# k8s-web1a
instances = ['【インスタンスID】']
ec2.stop_instances(InstanceIds=instances)
print 'stopped your instances: ' + str(instances)
# k8s-web1c
instances = ['【インスタンスID】']
ec2.stop_instances(InstanceIds=instances)
print 'stopped your instances: ' + str(instances)
またCloudWatchのスケジュールで Lambda関数を定期実行して下さい。
③Slackから自動停止ルールを制御
ここからは必要な物がある上に少し手間が掛かります。必要な物は以下の通りです。
- 独自ドメイン取得した証明書付きWebサーバ
- オレオレ認証局は×
- 多分ドメインがないと証明書は発行されない筈
- php 5.6 (動作保障環境)
- AWS CLI環境
- やって下さい。意外と簡単です。
SlackからCloudWatchのルールをどうやって制御するのかと言いますと、
- まずAWC CLIでルールを制御するシェルスクリプトを作成する
- そしてそれを実行出来るPHPを作成する
- さらにSlackからPOSTを送信し、PHPはそれをトリガーにシェルスクリプトを実行する
という運びです。まず1番のルールを制御するコマンドから見ていきます。
$ aws events enable-rule --name '【ルール名】'
$ aws events describe-rule --name '【ルール名】' --query 'State' --output text
ENABLED
$ aws events disable-rule --name '【ルール名】'
$ aws events describe-rule --name '【ルール名】' --query 'State' --output text
DISABLED
解説するまでもなく有効/無効を切り替えるコマンドと、ステータスを確認するコマンドです。ただ一つ注意が必要なことはSlackから呼び出す場合は後述の通りプロファイルを指定する必要があります。これをシェルスクリプトに纏めると次のようになります。
$ cat rule-control.sh
#!/bin/bash
if [ $1 = "STOP" ]; then
aws events disable-rule --name '【ルール名】' --profile default
elif [ $1 = "STATUS" ]; then
aws events describe-rule --name '【ルール名】' --query 'State' --output text
elif [ $1 = "START" ]; then
aws events enable-rule --name '【ルール名】' --profile default
fi
$ sh rule-control.sh STOP
$ sh rule-control.sh STATUS
DISABLED
$ sh rule-control.sh START
$ sh rule-control.sh STATUS
ENABLED
続いてシェルスクリプトを呼び出すPHPを作成します。
-<?php
header('content-type: application/json; charset=utf-8');
if ($_POST["trigger_word"] == "aws rule-stop --t2med") {
shell_exec("sudo sh /bin/rule-control.sh STOP");
$text = shell_exec("sudo sh /bin/rule-control.sh STATUS");
} else if ($_POST["trigger_word"] == "aws rule-status --t2med") {
$text = shell_exec("sudo sh /bin/rule-control.sh STATUS");
} else if ($_POST["trigger_word"] == "aws rule-start --t2med") {
shell_exec("sudo sh /bin/rule-control.sh START");
$text = shell_exec("sudo sh /bin/rule-control.sh STATUS");
}
$payload = array("text" => $text);
echo json_encode($payload);
?>
- trigger_word
- 後で詳しく述べますがSlackからPOSTされるワードのこと
- Slackで指定した特定のワードを打つと設定したURLにこれらが飛ぶ
- shell_exec()
- PHPから外部スクリプトを呼ぶ関数
- json_encode()
- SlackはJson形式でレスポンスを受け取る
- キー名は「text」
勘の良い方なら気づいているかもしれませんが、PHPから管理者権限で外部スクリプトを実行するにはOSの設定を少しいじる必要があります。次の一文を入れてください。
# visudo
apache ALL=(ALL) NOPASSWD: ALL
次はSlackの設定です。まずは「Outgoing Webhook」を追加して下さい。追加したら「インテグレーションの設定」を行います。
- コマンドを打てるチャンネル
- POSTを送る引き金となる言葉
- POSTを送るURL
- あとは任意
設定を保存したら完了です。
Slackからコマンドを叩きレスポンスがあれば成功です。
終わりに
長くなりましたが以上です。CloudWatchもLambdaも使うのは初めてでしたが、すごく便利だと感じました。但しNode.jsに関しては拡張モジュールを使用する為には外部からアップロードする必要があるので、結局オンプレでNode.jsインストールするやん..とも思いました。