Step Functions内でCodeBuildを実行する
Step Functionsは様々なサービスと統合されています。
AWS Step Functions と AWS のサービスを統合し、ワークフローから各サービスの API アクションを呼び出すことができます。
その他の AWS のサービスを呼び出す
今回はStep FunctionsからCodeBuildを呼び出す方法をご紹介します。
構築する環境
Step Functionsステートマシンを作成します。
このステートマシンはYouTubeから動画をダウンロードし、S3バケットに保存します。
このステートマシンに3つのステートを作成します。
1つ目のステートはLambda関数を呼び出します。
ダウンロードする動画のIDを返します。
2つ目のステートはCodeBuildを呼び出します。
Lambdaタイプ(Pythonバージョン)のビルド環境を選択します。
yt-dlpを使用して、YouTubeから動画をダウンロードします。
ダウンロードする動画は、前ステートから渡されたIDのものです。
ダウンロードした動画は、S3バケットに保存します。
3つ目のステートはLambda関数を呼び出します。
S3バケットに配置されているオブジェクトの一覧を取得します。
今回作成するLambda関数のランタイム環境はPython3.12とします。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLに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)
Step Functionsステートマシンを作成します。
ステートマシンに関する基本的な事項については、以下のページをご確認ください。
ポイントは2つ目のステート(DownloadVideoState)です。
Resourceプロパティには、実行するAPIを記述します。
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」となります。
Parametersプロパティで、APIを実行する上での各種パラメータを設定することができます。
StartBuild APIを実行する上で設定可能なパラメータについては、以下のページをご確認ください。
今回は2つのパラメータを設定します。
1つ目は環境変数です。
EnvironmentVariablesOverrideを指定することで、環境変数を設定することができます。
今回は環境変数としてダウンロードする動画のIDを設定します。
このように環境変数にIDを設定することで、CodeBuildを実行するための引数とします。
EnvironmentVariablesOverrideを指定して、CodeBuildプロジェクトを実行する際の引数を指定します。
今回はダウンロードする動画のIDを渡します。
2つ目は実行するCodeBuildプロジェクトの名前です。
ProjectNameに実行するプロジェクト名を指定します。
以下が本ステートマシン用の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)
ポイントは1つ目と2つ目のポリシーです。
以下のページを参考にしています。
1つ目はCodeBuildに関する内容です。
CodeBuildの起動や停止等の権限を与えます。
2つ目はEventBridgeに関する内容です。
こちらに関しては、AWS公式で以下の通りに説明されています。
AWSサービスから Amazon EventBridge に送信されるイベントは、マネージドルールを使用して Step Functions に送られevents:PutTargets、、events:PutRule、の権限が必要ですevents:DescribeRule。
Run a Job (ジョブ実行) パターンを使用したタスクの追加許可
(参考)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
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関数です。
この文字列はCodeBuildでダウンロードするYouTubeの動画のIDです。
なおこの動画ははAWS公式チャンネルの動画です。
(参考)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
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タイプ(Pythonバージョン)のCodeBuildプロジェクトを作成します。
yt-dlpをインストールし、同パッケージを使用して、YouTubeから動画をダウンロードします。
ダウンロードする動画のIDは環境変数という形で受け取ります。
ダウンロードした動画はS3バケットに保存します。
LambdaタイプのCodeBuildにつきましては、以下のページをご確認ください。
(参考)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
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)
S3バケットに保存されているオブジェクトの一覧を取得し、そのオブジェクト名を返します。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
AWS Management Consoleから各リソースの作成状況を確認します。
Step Functionsを確認します。
正常にステートマシンが作成されています。
チャート見ると、確かに3つのステートが用意されていることがわかります。
CodeBuildを確認します。
確かにLambdaタイプのCodeBuildプロジェクトが作成されています。
2つのLambda関数を確認します。
両関数とも正常に作成されています。
動作確認
準備が整いましたので、ステートマシンを実行します。
しばらく待つと、正常に完了しました。
3つのステートを通過して正常に完了しました。
ログから各ステートの実行結果を確認します。
1つ目のログを確認します。
1つ目のLambda関数が実行されて、IDが返されました。
2つ目のログを確認します。
上記はログの一部です。
BuildStatusの値を見ると、「SUCCEEDED」とあります。
確かにビルドが完了していることがわかります。
ちなみにCodeBuild StartBuild APIを実行した結果は、以下のフォーマットとなります。
3つ目のログを確認します。
ダウンロードし、S3バケットに保存された動画のファイル名が返されました。
最後にS3バケットを確認します。
確かにバケットに動画が保存されてました。
まとめ
Step FunctionsからCodeBuildを呼び出す方法をご紹介しました。