この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
こんにちは、中山です。
米国時間03/06、AWSからAWS Health Toolsが発表されました。このリポジトリは、AWS Healthに発生したイベントに応じてCloudWatch Eventsで定義したルールを呼び出し、ターゲットとなるLambda関数を起動させるサンプルを集めたものです。サンプルには主にLambda関数のコードとCloudFromationのテンプレートが含まれています。GitHubで管理されているため、世界中の開発者によりコミュニティベースで開発可能なリポジトリになっています。早速使ってみたので本エントリにまとめたいと思います。ただし、そのまま使うのもあまりおもしろくないので、今回はAWS Serverless Application Model(以下AWS SAM)から使ってみます。
なお、本エントリを執筆する上で検証に利用した主要な各種ツールのバージョンは以下の通りです。バージョンによって結果が変更される可能性があるので、その点ご了承ください。
- AWS SAM: 2016-10-31
- AWS CLI: aws-cli/1.11.57 Python/2.7.12 Darwin/16.4.0 botocore/1.5.20
概要
上述のようにAWS Healthで発生したイベントをCloudWatch Eventsに通知することが可能です。CloudWatch Eventsは事前に定義しておいたルールに応じてターゲットを実行させることができます。この機能に関するドキュメントはこちらです。執筆時点(2017/03/07)で以下のターゲットがサポートされています。
- AWS Lambda functions
- Amazon Kinesis streams
- Amazon SQS queues
- Built-in targets (CloudWatch alarm actions)
- Amazon SNS topics
AWS Healthは基本的に障害情報を収集するためのサービスです。そのためこの機能の主なユースケースは、ある障害に応じてそれを通知/緩和/復旧させるためのアクションを自動化させるという点です。上記ドキュメントにユースケースが記載されているので以下に引用します。
Use a Lambda function to pass a notification to a Slack channel when an event occurs.
Send custom text or SMS notifications via Amazon SNS when an AWS Health event happens by using Lambda and CloudWatch Events.
特にLambda関数をターゲットに指定できるという点が大きいですね。各種言語用AWS SDKを使えば基本的に何でもできるので、自分の環境に合ったアクションを定義できます。更に、今回発表されたAWS Health Toolsを利用することで、他の開発者の方が作成したLambda関数を利用できるという点も便利なポイントだと思います。
使ってみる
それでは早速使ってみましょう。今回はAWS Health Toolsのサンプルの中から、ELBがスケールした場合に必要となるENIが枯渇した場合( AWS_ELASTICLOADBALANCING_ENI_LIMIT_REACHED
イベント)、利用していないENIを削除するサンプルをAWS SAMで定義してみます。ディレクトリ構成はi以下のようにしました。 LambdaFunction.js
はこちらのソースコードを所定のディレクトリに配置してください。
$ tree
.
├── sam.yml
└── src
└── handlers
└── handler
└── LambdaFunction.js
3 directories, 2 files
AWS SAMのテンプレートである sam.yml
は以下のようにしました。
---
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: Automatically delete unused ENIs that are blocking ELB scaling using Amazon Cloudwatch events and AWS Lambda
Parameters:
DryRun:
Type: String
Description: Set to true to test function without actually deleting ENIs
Default: true
AllowedValues: [ true, false ]
MaxENI:
Description: Number of ENIs to process. Set to 0 to do all the function finds (this may result in account throttling)
Type: Number
Default: 100
Metadata:
LICENSE: https://github.com/aws/aws-health-tools
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: General Configuration
Parameters:
- DryRun
- MaxENI
ParameterLabels:
DryRun:
default: Dry Run
MaxENI:
default: Maximum ENI to process
Resources:
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
Description: Delete unused ENIs in response to AWS health events
CodeUri: src/handlers/handler
Handler: LambdaFunction.handler
Runtime: nodejs4.3
Timeout: 120
Policies:
- Version: 2012-10-17
Statement:
- Sid: ENI
Effect: Allow
Action:
- ec2:DescribeNetworkInterfaces
- ec2:DeleteNetworkInterface
Resource: "*"
Environment:
Variables:
DRY_RUN: !Ref DryRun
MAX_ENI: !Ref MaxENI
Events:
AWSHealth:
Type: CloudWatchEvent
Properties:
Pattern:
source: [ aws.health ]
detail-type: [ "AWS Health Event" ]
detail:
service: [ ELASTICLOADBALANCING ]
eventTypeCategory: [ issue ]
eventTypeCode: [ AWS_ELASTICLOADBALANCING_ENI_LIMIT_REACHED ]
テンプレートの中で、今回の場合特有の設定を以下に補足します。
- 41 - 49行
- Lambda関数にアタッチするIAM Roleの権限を
Policies
プロパティで定義しています - ENIの表示/削除を実施しているため、それに応じた権限を付与しています
- この他にも
arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
が自動で付与されます - 54 - 64行
Events
プロパティのType
をCloudWatchEvent
にすることで、Lambda関数のイベントソースを定義していますPattern
以下に指定しているオブジェクトの詳細はこちらのドキュメントにまとまっています- 今回AWS Healthをソースとするため、
source
にaws.health
を指定しています
ちなみに、AWS SAMを使わずにCloudFromationだけでもAWS::Events::Ruleを利用すればCloudWatch Eventsは定義可能です。先程のリポジトリに(JSONですが)テンプレートがあるので、該当の部分を引用します。
"CloudWatchEventRule": {
"Type": "AWS::Events::Rule",
"Properties": {
"Description": "AWS_ELASTICLOADBALANCING_ENI_LIMIT_REACHED",
"EventPattern": {
"source": [
"aws.health"
],
"detail-type": [
"AWS Health Event"
],
"detail": {
"service": [
"ELASTICLOADBALANCING"
],
"eventTypeCategory": [
"issue"
],
"eventTypeCode": [
"AWS_ELASTICLOADBALANCING_ENI_LIMIT_REACHED"
]
}
},
"State": "ENABLED",
"Targets": [
{
"Arn": {
"Fn::GetAtt": [
"LambdaFunction",
"Arn"
]
},
"Id": "InsufficientENIsFunction"
}
]
}
JSONで記述されているということもあるのですが、やはりAWS SAMの Events
プロパティで定義した方がよりシンプルに記述できるかと思います。AWS SAMのデプロイはいつものようにAWS CLIを使うだけです。
$ aws cloudformation package \
--template-file sam.yml \
--s3-bucket <_YOUR_S3_BUCKET_> \
--output-template-file .sam/packaged.yml
$ aws cloudformation deploy \
--template-file .sam/packaged.yml \
--stack-name <_YOUR_STACK_NAME_> \
--capabilities CAPABILITY_IAM
デプロイ後、CloudWatch Eventsの設定を見るとAWS Healthをソースとしたルールが定義されていることを確認できます。
$ aws events describe-rule \
--name "$(aws events list-rules \
--query 'Rules[?contains(Name, `aws-health-tools`)].Name' \
--output text)"
{
"EventPattern": "{\"detail-type\":[\"AWS Health Event\"],\"source\":[\"aws.health\"],\"detail\":{\"eventTypeCode\":[\"AWS_ELASTICLOADBALANCING_ENI_LIMIT_REACHED\"],\"service\":[\"ELASTICLOADBALANCING\"],\"eventTypeCategory\":[\"issue\"]}}",
"State": "ENABLED",
"Name": "aws-health-tools-sample-de-LambdaFunctionAWSHealth-1BR2PT9E6MGW3",
"Arn": "arn:aws:events:ap-northeast-1:************:rule/aws-health-tools-sample-de-LambdaFunctionAWSHealth-1BR2PT9E6MGW3"
}
Lambda関数の設定を見ると、CloudWatch EventsにLambda関数をInvokeできる権限が設定されていることを確認できます。
$ aws lambda get-policy \
--function-name "$(aws lambda list-functions \
--query 'Functions[?contains(FunctionName, `aws-health-tools`)].FunctionName' \
--output text)" \
--output text | jq .
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "aws-health-tools-sample-dev-LambdaFunctionAWSHealthPermission-L00FLZXLXL8S",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": "lambda:invokeFunction",
"Resource": "arn:aws:lambda:ap-northeast-1:************:function:aws-health-tools-sample-dev-LambdaFunction-1IYBNJYYIJD1J",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:events:ap-northeast-1:************:rule/aws-health-tools-sample-de-LambdaFunctionAWSHealth-1BR2PT9E6MGW3"
}
}
}
]
}
まとめ
いかがだったでしょうか。
AWS SAMでAWS Health Toolsを利用する方法をご紹介しました。AWS HealthとCloudWatch Events及びLambda関数の組み合わせは障害復旧方法として非常に便利な組み合わせだと思います。積極的に使っていきたいですね。ただ、AWS Healthは基本的にAWSに起因する障害を通知するものなので、AWSユーザ自身が検証目的で意図的に障害をエミュレートするのは現状難しいです。障害が起きた時に本当に意図した動作をするのか事前に検証しておきたいので、そういった機能があると嬉しいなと思いました。
本エントリがみなさんの参考になれば幸いに思います。