Step Functions内でCodeBuildを実行する
Step Functionsは様々なサービスと統合されています。
AWS Step Functions と AWS のサービスを統合し、ワークフローから各サービスの API アクションを呼び出すことができます。
その他の AWS のサービスを呼び出す
本記事では、Step FunctionsからCodeBuildを呼び出し、YouTube動画をS3に保存する一連のステートマシンの構築を解説します。この記事を通して、CodeBuildの自動化が可能となり、実際のビルド状況を確認する方法も学べます。
構成
- ステートマシンの作成
- Lambda関数1を呼び出し、ダウンロードする動画のIDを取得
- CodeBuildを呼び出し、動画をダウンロードしてS3に保存
- Lambda関数2を呼び出し、S3バケット内のオブジェクト一覧を取得
リソース
Step Functions
ステートマシン
1つ目のステートGetVideoIdStateでは、Lambda関数1を呼び出し、ダウンロードするYouTube動画のIDを取得します。この関数は文字列(動画ID)を返します。
2つ目のステートDownloadVideoStateでは、APIを実行して、CodeBuildを呼び出します。CodeBuildにおいて実行可能なAPIについては、以下のページをご確認ください。
今回はCodeBuildプロジェクトを実行するためのStartBuild APIを実行します。このAPIはジョブの実行(.sync)統合パターンをサポートしています。
AWS Batch や Amazon ECS など統合サービスの場合、Step Functions は次の状態に進む前にリクエストが完了するまで待機します。Step Functions を待機させるには、タスクの状態定義で “Resource” フィールドを指定し、リソース URI の後に .sync サフィックスを追加します。
ジョブの実行 (.sync)
以上をまとめますと、Resourceプロパティに指定する値は「arn:aws:states:::codebuild:startBuild.sync」となります。
StartBuild APIを実行する上で設定可能なパラメータについては、以下のページで確認できますが、今回は以下の2つを設定します。
1つ目は環境変数です。EnvironmentVariablesOverrideを指定することで、環境変数を設定することができます。今回は環境変数としてダウンロードする動画のIDを設定します。このように環境変数にIDを設定することで、CodeBuildを実行するための引数とします。2つ目は実行するCodeBuildプロジェクトの名前です。ProjectNameに実行するプロジェクト名を指定します。
ステートマシンに関する基本的な事項については、以下のページをご確認ください。
IAMロール
信頼ポリシーでstates.amazonaws.comサービスがこのIAMロールを引き受けることを許可します。IAMロールにアタッチしたIAMポリシーでは、CodeBuildの起動や停止、EventBridgeのイベント操作、Lambda関数の実行に必要な権限を付与します。
以下のページを参考にしています。
またEventBridgeの権限に関しては、AWS公式で以下の通りに説明されています。
AWSサービスから Amazon EventBridge に送信されるイベントは、マネージドルールを使用して Step Functions に送られevents:PutTargets、、events:PutRule、の権限が必要ですevents:DescribeRule。
Run a Job (ジョブ実行) パターンを使用したタスクの追加許可
CodeBuild
ビルドプロジェクト
CodeBuildプロジェクトでは、LambdaタイプのPython環境を使用します。yt-dlpをインストールし、環境変数で受け取った動画IDを使用してYouTubeから動画をダウンロードします。ダウンロードした動画は、指定したS3バケットにアップロードします。
LambdaタイプのCodeBuildにつきましては、以下のページをご確認ください。
IAMロール
このプロジェクトに必要なIAMロールには、S3バケットにオブジェクト、つまりダウンロードした動画を保存する権限を与えます。
Lambda 1
関数
この関数は、特定のYouTube動画のIDを返すシンプルなものです。ランタイム環境はPython 3.12を使用し、コード内で動画IDを直接返します。
IAMロール
IAMロールには、AWS管理ポリシーAWSLambdaBasicExecutionRoleをアタッチし、関数実行に必要な最小限の権限を与えます。
Lambda 2
関数
この関数は、S3バケット内のオブジェクト一覧を取得し、その名前を返します。Python 3.12をランタイム環境とし、boto3を使用してS3バケットを操作します。
IAMロール
AWS管理ポリシーAWSLambdaBasicExecutionRoleに加えて、S3バケット内のオブジェクトの一覧を取得するための権限を与えます。
CloudFormationテンプレート
Step Functions
ステートマシン
Resources:
StateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
Definition:
Comment: !Sub "${Prefix}-statemachine"
StartAt: GetVideoIdState
States:
GetVideoIdState:
Type: Task
Resource: !Ref FunctionArn1
ResultPath: $.video_id
Next: DownloadVideoState
DownloadVideoState:
Type: Task
Resource: arn:aws:states:::codebuild:startBuild.sync
Parameters:
EnvironmentVariablesOverride:
- Name: VIDEO_ID
Type: PLAINTEXT
Value.$: $.video_id
ProjectName: !Ref CodeBuildProjectName
ResultPath: $.codebuild_response
Next: CheckVideoNameState
ListBucketState:
Type: Task
Resource: !Ref FunctionArn2
End: true
LoggingConfiguration:
Destinations:
- CloudWatchLogsLogGroup:
LogGroupArn: !GetAtt StateMachineLogGroup.Arn
IncludeExecutionData: true
Level: ALL
RoleArn: !GetAtt StateMachineRole.Arn
StateMachineName: !Sub "${Prefix}-statemachine"
StateMachineType: STANDARD
Code language: YAML (yaml)
IAMロール
Resources:
StateMachineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- states.amazonaws.com
Policies:
- PolicyName: StateMachinePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- codebuild:StartBuild
- codebuild:StopBuild
- codebuild:BatchGetBuilds
Resource:
- !Sub "arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuildProjectName}"
- Effect: Allow
Action:
- events:PutTargets
- events:PutRule
- events:DescribeRule
Resource:
- !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventForCodeBuildStartBuildRule"
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource:
- !Ref FunctionArn1
- !Ref FunctionArn2
- Effect: Allow
Action:
- logs:CreateLogDelivery
- logs:GetLogDelivery
- logs:UpdateLogDelivery
- logs:DeleteLogDelivery
- logs:ListLogDeliveries
- logs:PutLogEvents
- logs:PutResourcePolicy
- logs:DescribeResourcePolicies
- logs:DescribeLogGroups
Resource: "*"
Code language: YAML (yaml)
CodeBuild
ビルドプロジェクト
Resources:
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: NO_ARTIFACTS
Cache:
Type: NO_CACHE
Environment:
ComputeType: !Ref ProjectEnvironmentComputeType
EnvironmentVariables:
- Name: BUCKET_NAME
Type: PLAINTEXT
Value: !Ref BucketName
- Name: VIDEO_ID
Type: PLAINTEXT
Value: ""
Image: !Ref ProjectEnvironmentImage
ImagePullCredentialsType: CODEBUILD
Type: !Ref ProjectEnvironmentType
LogsConfig:
CloudWatchLogs:
GroupName: !Ref CodeBuildLogGroup
Status: ENABLED
Name: !Sub "${Prefix}-project"
ServiceRole: !GetAtt CodeBuildRole.Arn
Source:
Type: NO_SOURCE
BuildSpec: !Sub |
version: 0.2
phases:
install:
commands:
- pip3 install yt-dlp
build:
commands:
- echo $VIDEO_ID
- yt-dlp -o /tmp/$VIDEO_ID.mp4 $VIDEO_ID
- ls -al /tmp
- aws s3 cp /tmp/$VIDEO_ID.mp4 s3://$BUCKET_NAME/
Visibility: PRIVATE
Code language: YAML (yaml)
IAMロール
Resources:
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: CodeBuildPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub "arn:aws:s3:::${BucketName}/*"
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CodeBuildLogGroup}"
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CodeBuildLogGroup}:log-stream:*"
Code language: YAML (yaml)
Lambda 1
関数
Resources:
Function1:
Type: AWS::Lambda::Function
Properties:
Architectures:
- !Ref Architecture
Code:
ZipFile: |
def lambda_handler(event, context):
return 'TqqaSD2qTdY'
FunctionName: !Sub "${Prefix}-function-01"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole1.Arn
Code language: YAML (yaml)
IAMロール
Resources:
FunctionRole1:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Code language: YAML (yaml)
Lambda 2
関数
Resources:
Function2:
Type: AWS::Lambda::Function
Properties:
Architectures:
- !Ref Architecture
Environment:
Variables:
REGION: !Ref AWS::Region
BUCKET_NAME: !Ref BucketName
Code:
ZipFile: |
import boto3
import json
import os
from datetime import date, datetime
region = os.environ['REGION']
bucket_name = os.environ['BUCKET_NAME']
s3_client = boto3.client('s3', region_name=region)
def lambda_handler(event, context):
response = s3_client.list_objects_v2(
Bucket=bucket_name
)
return [obj['Key'] for obj in response['Contents']]
FunctionName: !Sub "${Prefix}-function-02"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole2.Arn
Code language: YAML (yaml)
IAMロール
Resources:
FunctionRole2:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: FunctionPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:ListBucket
Resource:
- !Sub "arn:aws:s3:::${BucketName}"
Code language: YAML (yaml)
テンプレート全体
動作確認
Step Functionsのコンソールからステートマシンを開始します。しばらく待つと、実行が正常に完了します。
3つのステートを通過して正常に完了しました。
ログから各ステートの実行結果を確認します。
1つ目のログを確認します。
1つ目のLambda関数が実行されて、IDが返されました。
2つ目のログを確認します。
上記はログの一部です。BuildStatusの値を見ると、「SUCCEEDED」とあります。確かにビルドが完了していることがわかります。
ちなみにCodeBuild StartBuild APIを実行した結果は、以下のフォーマットとなります。
3つ目のログを確認します。
最後のステートでは、Lambda関数2が実行され、S3バケット内のオブジェクト一覧が取得されます。ダウンロードした動画ファイルの名前がリストに含まれており、S3バケットへの保存が成功していることがわかります。
最後にS3バケットを確認します。
S3バケットを直接確認すると、指定した動画ファイルが正しく保存されています。これにより、ステートマシン全体が期待通りに動作していることが確認できます。
まとめ
AWS Step FunctionsからCodeBuildを呼び出し、YouTube動画をS3バケットに自動的に保存する方法を紹介しました。Lambda関数を活用して動画IDの取得とS3バケット内の確認を行い、CodeBuildで実際のダウンロードと保存を自動化しました。この手順により、動画ダウンロードのプロセスを効率的に自動化できます。ぜひ、この記事を参考に自動化フローを構築してみてください。