この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部の若槻です。
AWSのETLサービスであるAWS Glueのジョブ失敗時の通知はCloudWatch Eventsを使用することにより実装が可能です。以下の記事ではコンソールを用いた設定方法が紹介されています。
今回は、上記で紹介されているAWS Glueのジョブ失敗時の通知設定をCloudFormationで実装してみました。
作ってみた
CloudFormationテンプレート
Glueジョブ含めたリソース定義を行っています。
% touch template.yaml
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Resources:
RawDataBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
BucketName: !Sub raw-data-${AWS::AccountId}-${AWS::Region}
GlueJobExecuteRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- glue.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: etl-glue-job-policy
PolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Action:
- glue:*
- cloudwatch:PutMetricData
- s3:ListAllMyBuckets
- s3:ListBucket
- s3:GetBucketAcl
- s3:GetBucketLocation
Resource: "*"
-
Effect: Allow
Action:
- logs:CreateLogStream
- logs:CreateLogGroup
- logs:PutLogEvents
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws-glue/jobs/*
-
Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:DeleteObject
Resource:
- !Sub arn:aws:s3:::${RawDataBucket}/*/*
- !Sub arn:aws:s3:::${GlueJobTempDirBucket}/admin/*
- !Sub arn:aws:s3:::${GlueJobScriptBucket}/admin/*
GlueJobTempDirBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub glue-job-temporary-${AWS::AccountId}-${AWS::Region}
GlueJobScriptBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub glue-job-script-${AWS::AccountId}-${AWS::Region}
SJIStoUTF8GlueJob:
Type: AWS::Glue::Job
Properties:
Name: sjis-to-utf8-job
Command:
Name: pythonshell
PythonVersion: 3
ScriptLocation: !Sub s3://${GlueJobScriptBucket}/admin/sjis-to-utf8.py
DefaultArguments:
--TempDir: !Sub s3://${GlueJobTempDirBucket}/admin
--BUCKET_NAME: !Sub ${RawDataBucket}
--SRC_OBJECT_KEY: sjis-data/raw-sjis-data.csv
--SRC_FILE_ENCODING: shift_jis
--DEST_OBJECT_PREFIX: utf8-data
ExecutionProperty:
MaxConcurrentRuns: 1
MaxRetries: 0
Role: !Ref GlueJobExecuteRole
GlueJobFailureNotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: job-failure-notification-topic
SJIStoUTF8JobFailureEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.glue
detail-type:
- Glue Job State Change
detail:
state:
- FAILED
jobName:
- !Ref SJIStoUTF8GlueJob
State: ENABLED
Targets:
-
Arn: !Ref GlueJobFailureNotificationTopic
Id: !GetAtt GlueJobFailureNotificationTopic.TopicName
GlueJobFailureEventTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref GlueJobFailureNotificationTopic
PolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sns:Publish
Resource: !Ref GlueJobFailureNotificationTopic
Glueジョブスクリプト
スクリプトは、試しにエラーを起こせれば何でも良いですが、今回は以下記事のスクリプトを流用します。
% touch sjis-to-utf8.py
import boto3
import sys
import uuid
from awsglue.utils import getResolvedOptions
# ジョブパラメータの読み込み
args = getResolvedOptions(sys.argv, ['BUCKET_NAME', 'SRC_OBJECT_KEY', 'SRC_FILE_ENCODING', 'DEST_OBJECT_PREFIX'])
# S3 Service Resource 準備
s3 = boto3.resource('s3')
# ファイルを文字コード変換してロード
src_obj = s3.Object(args['BUCKET_NAME'], args['SRC_OBJECT_KEY'])
body = src_obj.get()['Body'].read().decode(args['SRC_FILE_ENCODING'])
# ファイルを保存
dest_obj_file_name = str(uuid.uuid4())
dest_obj = s3.Object(args['BUCKET_NAME'], args['DEST_OBJECT_PREFIX'] + '/' + dest_obj_file_name)
dest_obj.put(Body = body)
# ファイルを削除
src_obj.delete()
このスクリプトはS3バケットに特定のキーのファイルが存在しなければエラーとなります。
デプロイ
CloudFormationスタックをデプロイします。
% aws cloudformation deploy \
--template-file template.yaml \
--stack-name Glue-Job-Failure-Notify-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
GlueジョブのスクリプトをS3バケットにアップロードします。
% ACCOUNT_ID=<Account ID>
% AWS_REGION=<AWS Region>
% aws s3 cp sjis-to-utf8.py s3://glue-job-script-${ACCOUNT_ID}-${AWS_REGION}/admin/sjis-to-utf8.py
サブスクリプション登録
SNSトピックのサブスクリプションに通知先のメールアドレスを登録します。
% to_address=<Mail Address>
% aws sns subscribe \
--topic-arn arn:aws:sns:${AWS_REGION}:${ACCOUNT_ID}:job-failure-notification-topic \
--protocol email \
--notification-endpoint ${to_address}
上記コマンドを実行すると下記のような登録確認メールが届くので、Confirm subscription
をクリックして登録を完了させます。
動作確認
通知を発生させてみる
ジョブを実行します。
% aws glue start-job-run --job-name sjis-to-utf8-job
すると下記のようなメールが届きます。
開始 AWS Notifications <no-reply@sns.amazonaws.com>
宛先: <xxxxxxxxxxxxxxxxxx>
件名 AWS Notification Message
{"version":"0","id":"e240736b-0903-610f-1ce8-e6f1eeef7b7d","detail-type":"Glue Job State Change","source":"aws.glue","account":"0123456789","time":"2020-12-28T13:16:53Z","region":"ap-northeast-1","resources":[],"detail":{"jobName":"sjis-to-utf8-job","severity":"ERROR","state":"FAILED","jobRunId":"jr_f41dd4aeed489bff491de6cc8f1d9b73383b601d174e180a87450ceb4f5664a8","message":"NoSuchKey: An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist."}}
detail - jobNameよりエラー通知がsjis-to-utf8-job
ジョブで発生したことが分かります。またdetail - messageにNoSuchKey: An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist.
とあるため、S3バケットからオブジェクト取得時に指定のキーが存在しなかったためエラーとなっていることが分かります。
ジョブ失敗のメトリクスの確認
CloudWatchのマネジメントコンソールで該当のルールを開き、[ルールのメトリクスを表示]をクリックします。
メトリクス名TriggeredRules
にチェックを入れると、グラフにジョブ失敗のメトリクスが記録されていることが確認できます。
おわりに
AWS Glueのジョブ失敗時の通知設定をCloudFormationで実装してみました。
Glueジョブを使用する際は是非ともセットで実装したいですね。
参考
以上