👌
ASGのインスタンス起動・停止時にSlackに通知するCloudFormationテンプレート
AWS Auto Scalingを利用することで、Amazon EC2 インスタンスを自動的に起動および停止させることでオートスケーリングやオートヒーリングを実現できます。
EC2インスタンスの起動および終了をSlackに通知することで、インスタンスの入れ替えを知ったり、入れ替えが頻発するなど障害発生の検知に役立ちます。
この記事では、SNSとLambdaの連携、および Lambda から Slack Incoming Webhook を叩く操作を、CloudFormationテンプレートでどのように表現するのかを紹介します。
通知の仕組み
- ASGのアクティビティ通知先として、Amazon SNS トピックを指定
- Amazon SNS トピックをLambda関数で購読
- Lambda関数でSlack Webhook URLにPOST
SNSトピックとLambda関数を作成するCloudFormationテンプレート
次のコードは、ASGのアクティビティ通知先として指定できるSNSトピックと、トピックを購読し、イベントの発生をトリガーに起動するLambdaを作成するテンプレートです。
テンプレートパラメータとして Slack Incoming Webhook のURLを与えます。
Parameters:
WebhookUrl:
Type: String
Resources:
TopicEC2ASGNotification:
Type: AWS::SNS::Topic
Properties:
DisplayName: asg-notification
SNSSubscriptionEC2ASGNotification:
Type: AWS::SNS::Subscription
Properties:
Endpoint: !GetAtt LambdaEC2ASGNotification.Arn
Protocol: lambda
TopicArn: !Ref TopicEC2ASGNotification
LambdaEC2ASGNotification:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |+
const url = require('url');
const https = require('https');
const util = require('util');
const { WebhookUrl, Region } = process.env;
const debug = (key, object) => { console.log(`DEBUG: ${key}\n`, JSON.stringify(object)); }
const notifySlack = async (subject, message) => {
const detail = `AccountId: ${message.AccountId}\nDescription: ${message.Description}\nCause: ${message.Cause}`;
const link = `https://${Region}.console.aws.amazon.com/ec2/home?region=${Region}#AutoScalingGroupDetails:id=${message.AutoScalingGroupName};view=activity`;
const blocks = {
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: subject + "\n```" + detail + "```\n<" + link + "|Link>"
}
}
]
};
const postData = JSON.stringify(blocks);
const url = new URL(WebhookUrl);
const requestOptions = {
hostname: url.host,
port: 443,
path: url.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
return new Promise((resolve, reject) => {
const req = https.request(requestOptions, (res) => {
const data = [];
res.on("data", (d) => data.push(d));
res.on("end", () => resolve(data.join("")));
});
req.on("error", reject);
req.write(postData);
req.end();
});
};
exports.handler = async (event, context, callback) => {
console.log("INFO: request Recieved.\nEvent:\n", JSON.stringify(event));
context.callbackWaitsForEmptyEventLoop = false;
const snsData = event.Records[0].Sns;
const message = JSON.parse(snsData.Message);
const results = await notifySlack(snsData.Subject, message);
debug("results", results);
return results;
};
Environment:
Variables:
WebhookUrl: !Ref WebhookUrl
Region: !Ref AWS::Region
Handler: index.handler
Role: !GetAtt LambdaEC2ASGNotificationRole.Arn
Runtime: "nodejs16.x"
MemorySize: 128
Timeout: 30
LambdaEC2ASGNotificationRole:
Type: "AWS::IAM::Role"
DeletionPolicy: Retain
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- "sts:AssumeRole"
Path: /
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
LambdaPermissionEC2ASGNotification:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt LambdaEC2ASGNotification.Arn
Principal: sns.amazonaws.com
SourceArn: !Ref TopicEC2ASGNotification
Lambda実行テスト
作成されたLambda関数のテストに次のテストイベントJSONを渡すと、通知を確認できます。
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:ap-northeast-1:012345678901:TEST-ASG-TopicEC2ASGNotification-Gx4PHPpQDYxR:800000000-0000-0000-0000-000000000000",
"Sns": {
"Type": "Notification",
"MessageId": "ece92d9b-504b-56fc-8d23-71dbd88bf54a",
"TopicArn": "arn:aws:sns:ap-northeast-1:012345678901:TEST-ASG-TopicEC2ASGNotification-Gx4PHPpQDYxR",
"Subject": "Auto Scaling: termination for group \"EC2AutoScalingGroup\"",
"Message": "{\"Origin\":\"AutoScalingGroup\",\"Destination\":\"EC2\",\"Progress\":60,\"AccountId\":\"012345678901\",\"Description\":\"Terminating EC2 instance: i-0000000000000000\",\"RequestId\":\"d413bc11-0548-4ec3-810f-1863ff8bbe0f\",\"EndTime\":\"2023-01-17T11:29:04.571Z\",\"AutoScalingGroupARN\":\"arn:aws:autoscaling:ap-northeast-1:012345678901:autoScalingGroup:a563dcba-2eb7-4d10-8f8d-c2e79a6ff460:autoScalingGroupName/EC2AutoScalingGroup\",\"ActivityId\":\"d413bc11-0548-4ec3-810f-1863ff8bbe0f\",\"StartTime\":\"2023-01-17T11:22:37.321Z\",\"Service\":\"AWS Auto Scaling\",\"Time\":\"2023-01-17T11:29:04.571Z\",\"EC2InstanceId\":\"i-0000000000000000\",\"StatusCode\":\"MidTerminatingLifecycleAction\",\"StatusMessage\":\"\",\"Details\":{\"Subnet ID\":\"subnet-0a7508392f1c3bbba\",\"Availability Zone\":\"ap-northeast-1a\"},\"AutoScalingGroupName\":\"EC2AutoScalingGroup\",\"Cause\":\"At 2023-01-17T11:22:37Z an instance was taken out of service in response to an instance refresh. At 2023-01-17T11:22:37Z instance i-0000000000000000 was selected for termination.\",\"Event\":\"autoscaling:EC2_INSTANCE_TERMINATE\"}",
"Timestamp": "2023-01-17T11:29:04.630Z",
"SignatureVersion": "1",
"Signature": "XiTi7Zs6lRwOuN05fGROkZK8Wy9StvI20U79tzCgHk0LCiPPSh0izW+8qLucnCp2HMO44Qq+ju6AyCExer+HpVpjDZIqh3DX28/Cv0KgkVCzR5ZGKWW5W7P1CIgGya7rl2CGnL8RqEVpcmOyjKUsQdDfdSYNsq/pTd2U+uQt+0DO27n1A/nU4hCF+nZV8g7+2KseDOD8KZldErh/lSx6Y5u5d4OUyuDsUaPwugqvSn8r7f1242Iwky561W1xh07w28Y/+RQPfcDlFSXHTFgQE/WXcpINJGMG7trZj+cGYXHy5JIHGE5SGFp/SoMJt2mIYqkCuaIObbBwFgHGUvBiqQ==",
"SigningCertUrl": "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-000000000000000000000000000000.pem",
"UnsubscribeUrl": "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:012345678901:TEST-ASG-TopicEC2ASGNotification-Gx4PHPpQDYxR:800000000-0000-0000-0000-000000000000",
"MessageAttributes": {}
}
}
]
}
EC2 ASGを作成して通知先としてトピックを設定するCloudFormationテンプレート
ASGのアクティビティ通知先は NotificationConfigurations
で次を指定します。
- 通知するイベントの種類
- 通知先のトピックARN
ASGを作成するテンプレートは案件により様々ですし長くなるので、通知の設定箇所のみ紹介します。
EC2AutoScalingGroup:
Type: 'AWS::AutoScaling::AutoScalingGroup'
Properties:
# (省略)
NotificationConfigurations:
- NotificationTypes:
- autoscaling:EC2_INSTANCE_LAUNCH
- autoscaling:EC2_INSTANCE_LAUNCH_ERROR
- autoscaling:EC2_INSTANCE_TERMINATE
- autoscaling:EC2_INSTANCE_TERMINATE_ERROR
TopicARN: !Ref TopicEC2ASGNotification
マネジメントコンソール上で設定する方法
CloudFormationを使用せずASGを構成している場合、公式ドキュメントの通知を送信するように Auto Scaling グループを設定するの手順に従って設定できます。
Discussion