CloudWatchEvents的主要用例是跟踪整个AWS基础架构中的更改。 当前,它支持在Auto Scaling组,EC2,EBS和其他各种事件中发出的事件。 为了对这些事件进行有意义的处理,我们需要一种消耗它们的方法。 AWS使用术语“ targets
来指代任何想要消耗事件并支持AWS Lambda以及其他几个东西的事物。
在本文中,我们将看到如何设置AWS Lambda函数以使用CloudWatch中的事件。 到本文结尾,我们将拥有一个AWS Lambda函数,该函数会将通知发布到Slack通道。 但是,由于该机制是通用的,因此您应该能够根据用例对其进行自定义。 让我们开始吧!
设置和一般信息
可以在这里找到本文的代码存储库。 它具有两个子目录:
-
functions
,其中包含Lambda函数的源代码。 -
terraform
,具有基础结构配置。
要继续,我们将需要:
- 一个AWS用户账户
- 地貌
- Python 3
- Bash / Powershell /实用程序
AWS用户账户和CLI配置
我们将需要一个具有以下IAM策略的AWS账户:
-
AWSLambdaFullAccess
-
IAMFullAccess
AWS CLI和terraform
将使用标准AWS配置,并在AWS配置文件中设置适当的凭证。
请注意,尝试演示可能需要付费。
地貌
我们将使用Terraform设置整个基础架构,包括上传Lambda函数。
Python 3
我们的Lambda函数将用Python 3编写,并且我们将在用于部署和更新AWS基础设施的脚本中使用Python。
Bash / Powershell /实用程序
如果您使用的是Linux / OS X,则需要bash
来运行脚本。 对于Windows,您将需要powershell
。 在Linux / OS X上,我们将使用zip
命令创建Lambda部署工件。
体系结构概述
我们将在本文中构建的解决方案的整体体系结构如下所示:
AWS CloudWatch event -> Lambda function invoked -> Notifications
我们将重点关注两个事件:
- EC2状态更改事件:当AWS EC2实例更改状态–启动新的EC2实例或终止现有的EC2实例时,将发生此事件。
- CloudWatch运行状况 事件:当您的AWS账户中发生与运行状况相关的基础架构更改时,就会发生CloudWatch 运行状况事件 。
要使CloudWatch事件自动触发Lambda函数,我们需要设置cloudwatch rule
。 无论我们正在处理事件还是处理事件,接收事件的Lambda函数都将具有相同的基本结构。
我们将在Python 3.6中编写Lambda函数,一个完全正常运行的函数如下所示:
def handler(event, context):print(event)
函数名称是handler
,它带有两个参数: event
和context
。 event
对象具有触发Lambda函数的事件的有效负载, context
对象具有与特定事件相关的各种元数据 。
为了了解如何完成上述所有工作,我们将首先实现一个解决方案,该解决方案将在EC2实例更改状态时调用Lambda函数。
演示:EC2实例运行通知
此通知的Lambda函数如下所示,并保存在文件main.py
:
def handler(event, context):print(event)
每当调用它时,它将事件主体打印到标准输出,该输出将自动记录到AWS CloudWatch日志中。 我们将讨论如何尽快上载Lambda函数。 首先,让我们简要介绍一下要调用的Lambda函数的基础结构设置。
可以在文件ec2_state_change.tf
找到Terraform配置。 它定义了以下主要地形资源:
aws_cloudwatch_event_rule
这定义了我们希望调用lambda函数的规则。 EC2实例状态更改的event_pattern
定义为:
"source": [ "aws.ec2" ],
"detail-type": [ "EC2 Instance State-change Notification" ]
aws_cloudwatch_event_target
接下来,我们定义使用此资源在事件发生时调用的内容。 关键参数是:
target_id = "InvokeLambda"
arn = "${aws_lambda_function.ec2_state_change.arn}"
}
arn
参数为Lambda函数指定Amazon资源名称。
aws_lambda_function
该资源注册了lambda函数,并具有以下关键参数:
function_name = "ec2_state_change"
role = "${aws_iam_role.ec2_state_change_lambda_iam.arn}"
handler = "main.handler"
runtime = "python3.6"s3_bucket = "aws-health-notif-demo-lambda-artifacts"
s3_key = "ec2-state-change/src.zip"
s3_object_version = "${var.ec2_state_change_handler_version}"
上面的function_name
是AWS的标识符,与代码中的函数名称没有任何关系。 由另一资源指定的Lambda函数的IAM角色具有默认的sts:AssumeRole
策略和允许将函数日志推送到CloudWatch的策略。
该handler
的格式为<python-module>.<function>
并指定要调用的Python函数名称。 runtime
指定AWS Lambda运行时。
s3_bucket
指定将存储Lambda代码的存储区, s3_key
是Lambda代码的键名,而s3_object_version
允许我们部署上述对象的特定版本。
ec2_state_change_cloudwatch
定义的最后一个关键资源允许CloudWatch调用我们的Lambda函数,并具有以下参数:
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.ec2_state_change.function_name}"
principal = "events.amazonaws.com"
source_arn = "${aws_cloudwatch_event_rule.ec2_state_change.arn}"
上载Lambda函数
正如我们在Lambda函数的配置中看到的那样,Lambda函数的代码将存在于S3中。 因此,在每次代码更改后,我们将使用AWS CLI在S3中更新代码,如下所示。 在Linux上,这看起来类似于:
# Create a .zip of src
$ pushd src
$ zip -r ../src.zip *
$ popd$ aws s3 cp src.zip s3://aws-health-notif-demo-lambda-artifacts/ec2-state-change/src.zip
我们可以使上述执行成为连续集成管道的一部分。
部署最新版本的代码
将代码上传到S3之后,我们可以运行terraform
来更新Lambda函数,以使用新版本的代码,如下所示:
$ version=$(aws s3api head-object --bucket aws-health-notif-demo-lambda-artifacts --key ec2-state-change/src.zip)
$ version=$(echo $version | python -c 'import json,sys; obj=json.load(sys.stdin); print(obj["VersionId"])')# Deploy to demo environment
$ pushd ../../terraform/environments/demo
$ ./tf.bash cloudwatch_event_handlers apply -var ec2_state_change_handler_version=$version \-target=aws_lambda_function.ec2_state_change \-target=aws_lambda_permission.ec2_state_change_cloudwatch \-target=aws_cloudwatch_event_target.ec2_state_change \-target=aws_iam_role_policy.ec2_state_change_lambda_cloudwatch_logging
$ popd
可以将上述两个步骤封装在一个脚本中,该脚本成为创建EC2状态更改CloudWatch事件处理程序以及更新处理它的Lambda函数的单个入口点。
运行演示
要在AWS账户中设置上述Lambda函数和所有必要的基础架构,我们只需要运行functions\ec2_state_change\deploy.bash
或functions\ec2_state_change\deploy.ps1
脚本即可。 完成后,如果您创建一个新的EC2实例或停止/终止现有实例,您将看到CloudWatch日志,如下所示:
[2018-07-04T09:46:18+10:00] (2018/07/03/[$LATEST]aa226226b6b24a0cae83a948dcc29b95) START RequestId: 4798542c-7f1b-11e8-8493-836165a23514 Version: $LATEST[2018-07-04T09:46:18+10:00] (2018/07/03/[$LATEST]aa226226b6b24a0cae83a948dcc29b95) {'version': '0', 'id': '73c10269-00a0-644d-b92b-820846bb19db', 'detail-type': 'EC2 Instance State-change Notification', 'source': 'aws.ec2', 'account': '033145145979', 'time': '2018-07-03T23:46:16Z', 'region': 'ap-southeast-2', 'resources': ['arn:aws:ec2:ap-southeast-2:033145145979:instance/i-0e1153ece20b77590'], 'detail': {'instance-id': 'i-0e1153ece20b77590', 'state': 'pending'}}[2018-07-04T09:46:18+10:00] (2018/07/03/[$LATEST]aa226226b6b24a0cae83a948dcc29b95) END RequestId: 4798542c-7f1b-11e8-8493-836165a23514
演示:AWS Health Events-> Slack
接下来,我们将编写一个Lambda函数,它将AWS Health Health事件发布到您选择的Slack通道。 首先,我们将为Slack频道配置一个传入的Webhook。 请查看此链接以开始如何为您的频道添加一个。 如果按照设置进行操作,您将拥有一个类似于https://hooks.slack.com/services/string/<string>/<string>
的webhook URL。 在此阶段之后,我将假定我们具有此Webhook URL。
编写Lambda函数
Lambda函数将如下所示:
import os
import sys
import jsonCWD = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, os.path.join(CWD, "libs"))import requestsdef handler(event, context):WEBHOOK_URL = os.getenv("WEBHOOK_URL")if not WEBHOOK_URL:print("WEBHOOK_URL not defined or empty")return# see: https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html#health-event-types for event structure r = requests.post(WEBHOOK_URL,json = {'text': '*New AWS Health event* ```{0}```'.format(str(event))})print(r)
基础架构配置
Lambda函数的基础结构配置与我们先前的功能完全相同,除了aws_cloudwatch_event_rule
定义event_pattern
方式如下:
"source": [ "aws.health" ],
"detail-type": [ "AWS Health Event" ]
部署Lambda函数
与上面的EC2状态更改演示类似,要部署上述功能,我们将在functions/health_event
目录中运行部署脚本:
$ HEALTH_EVENT_WEBHOOK_URL="<your webhook url>" ./deploy.bash
除了部署Lambda函数之外,这还将创建必要的CloudWatch事件规则并设置目标。
一切完成后,您可以直接使用AWS CLI调用Lambda函数:
$ aws lambda invoke --invocation-type RequestResponse --function-name health_event --log-type Tail --payload '{"message":"hello"}' outfile.txt
您应该在配置的频道中看到一条松弛消息:
摘要
在本文中,我们学习了如何将Lambda函数设置为CloudWatch事件的目标。 Slack通知演示有效,但可以通过以下两种方式进行改进:
- 可以使用AWS Secrets Manager静态加密webhook URL。
- 通过处理传入消息,可以使通知更丰富。
本文使用的存储库位于此处 。
以下资源应有助于进一步了解:
- CloudWatch活动
- 在Python中编写Lambda函数的指南
- 适用于AWS的Terraform指南
翻译自: https://www.javacodegeeks.com/2018/07/cloudwatch-event-notifications-aws.html