Step Functions内でCodeBuildを実行する

目次

Step Functions内でCodeBuildを実行する

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

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

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

本記事では、Step FunctionsからCodeBuildを呼び出し、YouTube動画をS3に保存する一連のステートマシンの構築を解説します。この記事を通して、CodeBuildの自動化が可能となり、実際のビルド状況を確認する方法も学べます。

構成

Diagram of executing CodeBuild within Step Functions.
  • ステートマシンの作成
    1. Lambda関数1を呼び出し、ダウンロードする動画のIDを取得
    2. CodeBuildを呼び出し、動画をダウンロードしてS3に保存
    3. Lambda関数2を呼び出し、S3バケット内のオブジェクト一覧を取得

リソース

Step Functions

ステートマシン

Detail of Step Functions 01.

1つ目のステートGetVideoIdStateでは、Lambda関数1を呼び出し、ダウンロードするYouTube動画のIDを取得します。この関数は文字列(動画ID)を返します。

2つ目のステートDownloadVideoStateでは、APIを実行して、CodeBuildを呼び出します。CodeBuildにおいて実行可能なAPIについては、以下のページをご確認ください。

あわせて読みたい
管理 AWS CodeBuild Step Functions を使用したビルド - AWS Step Functions Step Functions を と統合する方法について説明します。 AWS CodeBuild ビルドをトリガー、停止、管理する

今回は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つを設定します。

あわせて読みたい
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...

1つ目は環境変数です。EnvironmentVariablesOverrideを指定することで、環境変数を設定することができます。今回は環境変数としてダウンロードする動画のIDを設定します。このように環境変数にIDを設定することで、CodeBuildを実行するための引数とします。2つ目は実行するCodeBuildプロジェクトの名前です。ProjectNameに実行するプロジェクト名を指定します。

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

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

IAMロール

Detail of IAM role 01.
Detail of IAM role 02.

信頼ポリシーでstates.amazonaws.comサービスがこのIAMロールを引き受けることを許可します。IAMロールにアタッチしたIAMポリシーでは、CodeBuildの起動や停止、EventBridgeのイベント操作、Lambda関数の実行に必要な権限を付与します。

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

あわせて読みたい
管理 AWS CodeBuild Step Functions を使用したビルド - AWS Step Functions Step Functions を と統合する方法について説明します。 AWS CodeBuild ビルドをトリガー、停止、管理する

またEventBridgeの権限に関しては、AWS公式で以下の通りに説明されています。

AWSサービスから Amazon EventBridge に送信されるイベントは、マネージドルールを使用して Step Functions に送られevents:PutTargets、、events:PutRule、の権限が必要ですevents:DescribeRule。

Run a Job (ジョブ実行) パターンを使用したタスクの追加許可

CodeBuild

ビルドプロジェクト

Detail of CodeBuild 01.
Detail of CodeBuild 02.

CodeBuildプロジェクトでは、LambdaタイプのPython環境を使用します。yt-dlpをインストールし、環境変数で受け取った動画IDを使用してYouTubeから動画をダウンロードします。ダウンロードした動画は、指定したS3バケットにアップロードします。

LambdaタイプのCodeBuildにつきましては、以下のページをご確認ください。

あわせて読みたい
CodeBuild – Lambdaバージョン 【CodeBuild - Lambdaバージョン】 2023年11月6日に、CodeBuildのビルド環境に関するアップデートが発表されました。 ビルド実行の新しいコンピューティングモードとし...

IAMロール

Detail of IAM role 03.
Detail of IAM role 04.

このプロジェクトに必要なIAMロールには、S3バケットにオブジェクト、つまりダウンロードした動画を保存する権限を与えます。

Lambda 1

関数

Detail of Lambda 01.

この関数は、特定のYouTube動画のIDを返すシンプルなものです。ランタイム環境はPython 3.12を使用し、コード内で動画IDを直接返します。

IAMロール

Detail of IAM role 05.
Detail of IAM role 06.

IAMロールには、AWS管理ポリシーAWSLambdaBasicExecutionRoleをアタッチし、関数実行に必要な最小限の権限を与えます。

Lambda 2

関数

Detail of Lambda 02.

この関数は、S3バケット内のオブジェクト一覧を取得し、その名前を返します。Python 3.12をランタイム環境とし、boto3を使用してS3バケットを操作します。

IAMロール

Detail of IAM role 07.

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)

テンプレート全体

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のコンソールからステートマシンを開始します。しばらく待つと、実行が正常に完了します。

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.

最後のステートでは、Lambda関数2が実行され、S3バケット内のオブジェクト一覧が取得されます。ダウンロードした動画ファイルの名前がリストに含まれており、S3バケットへの保存が成功していることがわかります。

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

Detail of S3 01.

S3バケットを直接確認すると、指定した動画ファイルが正しく保存されています。これにより、ステートマシン全体が期待通りに動作していることが確認できます。

まとめ

AWS Step FunctionsからCodeBuildを呼び出し、YouTube動画をS3バケットに自動的に保存する方法を紹介しました。Lambda関数を活用して動画IDの取得とS3バケット内の確認を行い、CodeBuildで実際のダウンロードと保存を自動化しました。この手順により、動画ダウンロードのプロセスを効率的に自動化できます。ぜひ、この記事を参考に自動化フローを構築してみてください。

目次