Основным вариантом использования CloudWatchEvents является отслеживание изменений в инфраструктуре AWS. В настоящее время он поддерживает события, генерируемые группами Auto Scaling, EC2, EBS и другими. Чтобы сделать что-то значимое с этими событиями, нам нужен способ их использовать. AWS использует термин targets
для обозначения всего, что хочет использовать события, и поддерживает AWS Lambda и некоторые другие.
В этой статье мы увидим, как мы можем настроить функцию AWS Lambda для приема событий из CloudWatch. К концу этой статьи у нас будет функция AWS Lambda, которая будет публиковать уведомления на канале Slack . Однако, поскольку механизм будет универсальным, вы сможете настроить его в соответствии со своими вариантами использования. Давайте начнем!
Настройка и общая информация
Хранилище кода для этой статьи можно найти здесь . Имеет две подкаталоги:
-
functions
, который имеет исходный код для лямбда-функций. -
terraform
, который имеет конфигурацию инфраструктуры.
Чтобы следовать, нам понадобится:
- учетная запись пользователя AWS
- Terraform
- Python 3
- Bash / Powershell / утилиты
Учетная запись пользователя AWS и настройка CLI
Нам потребуется аккаунт AWS со следующими политиками IAM:
-
AWSLambdaFullAccess
-
IAMFullAccess
Интерфейс командной строки AWS и terraform
будут использовать стандартную конфигурацию AWS с соответствующими учетными данными, установленными в профиле AWS.
Обратите внимание, что с вас могут взимать плату за демонстрацию.
Terraform
Мы будем использовать Terraform для настройки всей инфраструктуры, включая загрузку наших функций Lambda.
Python 3
Наши функции Lambda будут написаны на Python 3, и мы будем использовать Python в сценариях, используемых для развертывания и обновления нашей инфраструктуры AWS.
Bash / Powershell / утилиты
Если вы работаете в Linux / OS X, вам понадобится bash
для запуска сценариев. Для Windows вам потребуется powershell
. В Linux / OS X мы будем использовать команду zip
для создания артефактов развертывания Lambda.
Обзор архитектуры
Общая архитектура решения, которое мы будем строить в этой статье, будет выглядеть следующим образом:
1
|
AWS CloudWatch event -> Lambda function invoked -> Notifications |
Мы сосредоточимся на двух мероприятиях:
- Событие изменения состояния EC2. Это событие происходит, когда экземпляр AWS EC2 изменяет состояние — запускается новый экземпляр EC2 или завершается существующий экземпляр EC2.
- Событие работоспособности CloudWatch. Событие работоспособности CloudWatch происходит, когда в вашей учетной записи AWS происходят изменения инфраструктуры, связанные со здоровьем.
Чтобы событие CloudWatch автоматически запускало функцию Lambda, нам нужно настроить cloudwatch rule
. Независимо от того, какое событие мы обрабатываем или что мы делаем с этим событием, наша лямбда-функция, которая получает событие, будет иметь одинаковую базовую структуру.
Мы напишем нашу лямбда-функцию в Python 3.6, и полностью рабочая функция выглядит следующим образом:
1
2
|
def handler(event, context): print(event) |
Имя функции — handler
, который принимает два параметра: event
и context
. Объект event
имеет полезную нагрузку для события, которое запускает функцию Lambda, а объект context
имеет различные метаданные, связанные с конкретным событием.
Чтобы увидеть, как мы можем выполнить все вышеперечисленное, мы сначала реализуем решение, которое будет вызывать функцию Lambda всякий раз, когда экземпляр EC2 изменяет состояние.
Демонстрация: Уведомление о запуске экземпляра EC2
Лямбда-функция для этого уведомления выглядит следующим образом и сохраняется в файле main.py
:
1
2
|
def handler(event, context): print(event) |
Всякий раз, когда он вызывается, он выводит тело события в стандартный вывод, который автоматически регистрируется в журналах AWS CloudWatch. Мы скоро обсудим, как мы загрузим нашу функцию Lambda. Сначала давайте кратко рассмотрим настройку инфраструктуры для запуска нашей функции Lambda.
Конфигурация Terraform находится в файле ec2_state_change.tf
. Он определяет следующие ключевые ресурсы terraform:
aws_cloudwatch_event_rule
Это определяет правило, для которого мы хотим, чтобы наша лямбда-функция вызывалась. event_pattern
для изменения состояния экземпляра EC2 определяется как:
1
2
|
"source" : [ "aws.ec2" ], "detail-type" : [ "EC2 Instance State-change Notification" ] |
aws_cloudwatch_event_target
Далее мы определяем, что вызывается, когда событие происходит, используя этот ресурс. Основные параметры:
1
2
3
|
target_id = "InvokeLambda" arn = "${aws_lambda_function.ec2_state_change.arn}" } |
Параметр arn
указывает имя ресурса Amazon для функции Lambda.
aws_lambda_function
Этот ресурс регистрирует лямбда-функцию и имеет следующие ключевые параметры:
1
2
3
4
5
6
7
8
|
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}" |
Приведенное выше имя_функции является идентификатором AWS и не имеет никакого отношения к названию вашей функции в вашем коде. Роль IAM-функции лямбда-функции, заданная другим ресурсом, имеет политику sts:AssumeRole
по умолчанию и политику, которая позволяет передавать журналы наших функций в CloudWatch.
handler
имеет форму <python-module>.<function>
и указывает имя функции Python, которое вы хотите вызвать. runtime
определяет время выполнения AWS Lambda.
s3_bucket
указывает s3_bucket
в которой будет жить код нашей s3_key
, s3_key
— имя ключа для лямбда-кода, а s3_object_version
позволяет нам развертывать конкретную версию вышеуказанного объекта.
ec2_state_change_cloudwatch
Последний ключевой ресурс, который определен, позволяет CloudWatch вызывать нашу функцию Lambda и имеет следующие параметры:
1
2
3
4
|
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 будет жить в S3. Следовательно, после каждого изменения кода мы будем обновлять наш код в S3 с помощью интерфейса командной строки AWS следующим образом. В Linux это будет выглядеть примерно так:
1
2
3
4
5
6
|
# 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 для использования новой версии кода следующим образом:
01
02
03
04
05
06
07
08
09
10
11
|
$ 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 |
Оба вышеперечисленных шага могут быть инкапсулированы в один сценарий, который становится единой точкой входа для создания обработчика событий CloudWatch с изменением состояния EC2, а также для обновления функции Lambda, которая его обрабатывает.
Запуск демо
Чтобы настроить вышеуказанную лямбда-функцию и всю необходимую инфраструктуру в учетной записи AWS, нам просто нужно запустить functions\ec2_state_change\deploy.bash
или functions\ec2_state_change\deploy.bash
functions\ec2_state_change\deploy.ps1
. Как только это будет сделано, если вы создадите новый экземпляр EC2 или остановите / прекратите работу существующего, вы увидите журналы CloudWatch следующим образом:
1
2
3
4
5
|
[ 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 на выбранный вами канал Slack. Сначала мы настроим входящий веб-крючок для нашего канала Slack. Пожалуйста, перейдите по этой ссылке, чтобы начать, как вы можете добавить один для своего канала. Если вы выполните настройку, у вас будет URL-адрес, похожий на https://hooks.slack.com/services/string/<string>/<string>
. Помимо этого этапа, я предполагаю, что у нас есть этот URL-адрес веб-крючка.
Написание лямбда-функции
Лямбда-функция будет выглядеть следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
import os import sys import json CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.insert( 0 , os.path.join(CWD, "libs" )) import requests def 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) |
Конфигурация инфраструктуры
Конфигурация инфраструктуры для этой лямбда-функции точно такая же, как и предыдущая, за исключением aws_cloudwatch_event_rule
который определяет event_pattern
следующим образом:
1
2
|
"source" : [ "aws.health" ], "detail-type" : [ "AWS Health Event" ] |
Развертывание лямбда-функции
Как и в приведенной выше демонстрации изменения состояния EC2, для развертывания вышеуказанной функции мы запустим сценарий развертывания из каталога functions/health_event
:
1
|
$ HEALTH_EVENT_WEBHOOK_URL= "<your webhook url>" ./deploy.bash |
Это создаст необходимые правила событий CloudWatch и установит цели в дополнение к развертыванию функции Lambda.
После того, как все будет завершено, вы можете вызвать функцию Lambda напрямую с помощью интерфейса командной строки AWS:
1
|
$ aws lambda invoke --invocation-type RequestResponse --function-name health_event --log-type Tail --payload '{"message":"hello"}' outfile.txt |
Вы должны увидеть сообщение Slack в вашем настроенном канале:
Резюме
В этой статье мы узнали, как мы можем настроить функции Lambda в качестве целей для событий CloudWatch. Демонстрация Slack уведомлений работает, но может быть улучшена несколькими способами:
- URL-адрес webhook может быть зашифрован в состоянии покоя с помощью AWS Secrets Manager.
- Уведомление может быть обогащено за счет возможности обработки входящих сообщений.
Репозиторий, используемый для этой статьи, доступен здесь .
Следующие ресурсы должны быть полезны для получения дополнительной информации:
См. Оригинальную статью здесь: Уведомления о событиях CloudWatch с использованием AWS Lambda.
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |