Step Functions内でCodeBuildを実行する

Step Functions内でCodeBuildを実行する

Step Functionsは様々なサービスと統合されています。

AWS Step Functions と AWS のサービスを統合し、ワークフローから各サービスの API アクションを呼び出すことができます。

その他の AWS のサービスを呼び出す

今回はStep FunctionsからCodeBuildを呼び出す方法をご紹介します。

構築する環境

Diagram of executing CodeBuild within Step Functions.

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テンプレートを配置しています。

GitHub
awstut-fa/150 at main · awstut-an-r/awstut-fa Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

テンプレートファイルのポイント解説

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ステートマシンを作成します。

ステートマシンに関する基本的な事項については、以下のページをご確認ください。

あわせて読みたい
CFNでStep Functions入門 【CloudFormationでStep Functions入門】 AWS DVAの出題範囲であるリファクタリングに関する内容です。 Step Functionsはサーバーレスオーケストレーションサービスです...

ポイントは2つ目のステート(DownloadVideoState)です。

Resourceプロパティには、実行するAPIを記述します。

CodeBuildにおいて実行可能なAPIについては、以下のページをご確認ください。

あわせて読みたい
Step AWS CodeBuild Functions による呼び出し - AWS Step Functions Step Functions AWS は特定のサービスを (ASL) から直接制御できます。詳細については、「 」および「 」を参照してください。

今回は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を実行する上で設定可能なパラメータについては、以下のページをご確認ください。

あわせて読みたい
StartBuild - AWS CodeBuild Starts running a build with the settings defined in the project. These setting include: how to run a build, where to get the source code, which build environmen...

今回は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つ目のポリシーです。

以下のページを参考にしています。

あわせて読みたい
の IAM ポリシー AWS CodeBuild - AWS Step Functions 以下のサンプルテンプレートは、ステートマシン定義内のリソースに基づいて IAM AWS Step Functions ポリシーを生成する方法を示しています。詳細については、「 」および...

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につきましては、以下のページをご確認ください。

あわせて読みたい
CodeBuild – Lambdaバージョン 【CodeBuild - Lambdaバージョン】 2023年11月6日に、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スタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

AWS Management Consoleから各リソースの作成状況を確認します。

Step Functionsを確認します。

Detail of Step Functions 01.

正常にステートマシンが作成されています。

チャート見ると、確かに3つのステートが用意されていることがわかります。

CodeBuildを確認します。

Detail of CodeBuild 01.
Detail of CodeBuild 02.

確かにLambdaタイプのCodeBuildプロジェクトが作成されています。

2つのLambda関数を確認します。

Detail of Lambda 01.
Detail of Lambda 02.

両関数とも正常に作成されています。

動作確認

準備が整いましたので、ステートマシンを実行します。

しばらく待つと、正常に完了しました。

Detail of Step Functions 02.

3つのステートを通過して正常に完了しました。

ログから各ステートの実行結果を確認します。

1つ目のログを確認します。

Detail of Step Functions 03.

1つ目のLambda関数が実行されて、IDが返されました。

2つ目のログを確認します。

Detail of Step Functions 04.

上記はログの一部です。
BuildStatusの値を見ると、「SUCCEEDED」とあります。
確かにビルドが完了していることがわかります。

ちなみにCodeBuild StartBuild APIを実行した結果は、以下のフォーマットとなります。

あわせて読みたい
StartBuild - AWS CodeBuild Starts running a build with the settings defined in the project. These setting include: how to run a build, where to get the source code, which build environmen...

3つ目のログを確認します。

Detail of Step Functions 05.

ダウンロードし、S3バケットに保存された動画のファイル名が返されました。

最後にS3バケットを確認します。

Detail of S3 01.

確かにバケットに動画が保存されてました。

まとめ

Step FunctionsからCodeBuildを呼び出す方法をご紹介しました。