AWS コンテナ Lambda の CI/CD 環境をサクっとつくる (最小構成)

こんにちは、広野です。

いわゆるコードだけ書いたらすぐ動く AWS Lambda 関数はいじったことのある方は多いと思いますが、コンテナイメージを AWS Lambda 関数として使ったことがある方は比較的少ないのではないでしょうか。(以降、コンテナ Lambda と表記) 

業務でやや重めの処理をするワークロードがありコンテナ Lambda をつくったのですが、手動でのビルドが面倒になってきたので CI/CD 環境までつくってみました。ネット上で紹介されている環境よりも若干簡易な構成になっています。

最終章に AWS CloudFormation テンプレートを貼り付けますので、AWS アカウントをお持ちの方はお気軽にお試しください。CI/CD の学習用にも良いサンプルになると思います。

アーキテクチャ

最初にどんな設計なのか説明します。

図の左上から。

  • 開発者は、AWS Cloud9 上で AWS Lambda 関数を開発します。本記事では Python 3.9 を使用します。図では省略していますが、ここで Dockerfile、buildspec.yml、requirements.txt、それと Lambda 関数をデプロイするための AWS CloudFormation テンプレートもソースコードと一緒に配置・管理します。
  • AWS Cloud9 で開発したコードやその他ファイルを、AWS CodeCommit にプッシュします。それを Amazon EventBridge が検知して、AWS CodePipeline を開始します。
  • AWS CodePipeline は、最初にソースコードを AWS CodeCommit に取りにいきます。ここでは、ソースコードがどこにあるか情報だけを JSON データにして取得するだけで、それをアーティファクト保存用 Amazon S3 バケットに保存します。
  • 次に AWS CodePipeline は AWS CodeBuild を呼び出します。あらかじめ設定済みのビルドプロジェクトを開始し、ビルドプロジェクトはアーティファクト保存用バケットに保存されたソースコード情報 JSON ファイルを読み込み、AWS CodeCommit にソースコードを取得しに行きます。
  • その後 AWS CodeBuild はソースコードおよび一緒に保存してあるその他ファイルを読み込み、その記述に従ってコンテナイメージをビルドします。コンテナイメージは Amazon ECR (Elastic Container Registry) に保存します。このとき、コンテナイメージを一意に識別するために AWS CodePipeline のパイプライン実行単位で割り当てられる「パイプライン実行 ID」をコンテナイメージの「イメージタグ」として付与します。後ほど必要になります。
  • AWS CodeBuild は最後に、ソースコードと同梱されていた AWS CloudFormation テンプレートをそのまま加工せずにアーティファクト保存用 Amazon S3 バケットに保存します。そうしないと、次のデプロイフェーズでスタック作成ができないためです。※このビルドフェーズで、SAM を使って AWS CloudFormation テンプレートを作成、保存する方法もあります。
  • デプロイフェーズでは、いよいよコンテナ Lambda 関数をデプロイします。アーティファクト保存用 Amazon S3 バケットから AWS CloudFormation テンプレートを受け取り、スタック作成を実行します。ここで、再度 AWS CodePipeline の「パイプライン実行 ID」を AWS CloudFormation にパラメータとして渡します。ビルドフェーズで使用したものと同じ情報になります。
  • AWS CloudFormation は「パイプライン実行 ID」をイメージタグに持つコンテナイメージをコンテナ Lambda 関数の関連付け対象に指名します。それにより、そのパイプライン実行で作成された最新のコンテナイメージを一意に指定して、コンテナ Lambda 関数をデプロイし直す(スタックの変更)ことができます。
  • Amazon ECR に保存されるコンテナイメージは直近 5 世代まで保存するようにしています。無尽蔵にイメージがたまって課金を増やすことのないようにしていますが、保管のポリシーによってこのライフサイクルポリシーは変更した方がよいでしょう。

使用方法

CI/CD 環境・開発環境準備

本記事最下部「サンプルテンプレート」に掲載している AWS CloudFormation テンプレートを実行して CI/CD 環境をプロビジョニングします。

その前提で、以下 AWS 公式ドキュメントを参考に AWS Cloud9 環境を構築します。クローンする AWS CodeCommit のリポジトリ名は example-lmbd-xxxxx になっています。xxxxx はスタック作成時に任意に入力するパラメータです。リソース名に必ず入る文字列になります。

プロビジョニング完了直後、パイプラインが自動実行されてしまい、そして必ず失敗しますので失敗ステータスは気にしないで下さい。

開発環境への AWS Lambda 関数コード等アップロード

本記事最下部「サンプルテンプレート」に掲載している以下 5 つのファイルを AWS Cloud9 に作成またはアップロードします。ディレクトリは、AWS CodeCommit のリポジトリをクローンしたときに出来たディレクトリになります。

  • app.py
  • Dockerfile
  • requirements.txt
  • buildspec.yml
  • Cfn_LambdaContainer.yml

本記事で使用する AWS Lambda 関数のコードは、簡便化のため AWS 公式ドキュメントで紹介されているものを使用します。以下のリンクを参考に、app.py を作成してみて下さい。

Dockerfile も上記ページで紹介されている通りに作ればよいのですが、Python のバージョンは 3.9 にしたいので 3.8 を 3.9 に書き換えましょう。

requirements.txt は、pip を使用して必要な外部モジュールをインストールする際に使用します。(使用しなくてもいいのですが)
本記事のケースでは外部モジュールは必要ないのですが、学習のために以下のように書いてみましょう。書くことにより、ビルド時にこれらをインストールしてコンテナイメージに含めてくれます。ここでインストールしたモジュールは、関数コード内で import できるようになります。

requirements.txt
numpy==1.24.2
opencv-python==4.7.0.72

buildspec.yml はビルド内のフェーズごとに何をさせるか指定するためのファイルです。以下の AWS 公式ドキュメントのサンプルは汎用的にするために環境変数をしっかり設定してくれているので、これに合わせてビルドプロジェクトを作成すれば綺麗な CI/CD をつくれます。

ただし、本記事の構成では、AWS コンテナ Lambda 関数をデプロイするための AWS CloudFormation テンプレートをソースコードとともにビルド環境に持ってきており、次のデプロイフェーズにビルドアーティファクトとしてテンプレートを渡す必要があります。そのため buildspec.yml に上記サンプルに加えて artifacts: の設定を追加します。具体的には以下の記述になります。

buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - echo Building the Docker image...
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
artifacts:
  files:
    - Cfn_LambdaContainer.yml

Cfn_LambdaContainer.yml は AWS コンテナ Lambda 関数を作成または更新するための AWS CloudFormation テンプレートです。パイプラインのデプロイフェーズで同じテンプレートが実行されることになりますが、パラメータとして渡されるパイプライン実行 ID が毎回変わるため、2 回目の実行以降は必ず変更扱いになります。このファイルについては最下部の「サンプルテンプレート」の章をご確認ください。

最終的に、5 つのファイルを AWS Cloud9 に配置すると以下のようになります。

CI/CD パイプラインの発動

以降は、これらコードや設定ファイルを更新する度に AWS CodeCommit にプッシュすると CI/CD パイプラインが自動発動し AWS コンテナ Lambda 関数が自動的にビルド・デプロイされます。

  • AWS Cloud9 からの最も簡単なプッシュコマンド例
cd example-lmbd-xxxxx
git add -A
git commit -m "comment"
git push origin master

以下のように AWS CodePipeline の画面でパイプラインが実行されていることが確認できます。デプロイフェーズがグリーンで「成功しました」になれば完了です。

AWS コンテナ Lambda 関数のテスト実行

本記事の構成でデプロイされる AWS コンテナ Lamda 関数の名前は EXAMPLE-getPythonVersion-xxxxx になります。2 回目以降のデプロイでは関数の名前は変わらず、関連付けられているコンテナイメージが変わります。

対象の AWS コンテナ Lambda 関数のテストを実行すると、app.py に書いたコードが実行され、以下のような Python のバージョンが戻り値として表示されます。

AWS Lambda 関数のテストをする方法は以下の AWS ドキュメントをご覧下さい。本記事のケースでは、テストイベントはデフォルトのままでかまいません。パラメータ渡しをしていないため。

まとめ

いかがでしたでしょうか?

コンテナ Lambda の基本的な CI/CD はできていると思いますので、細かいパラメータをカスタマイズするだけでご活用頂けると思います。

本記事が皆様のお役に立てれば幸いです。

サンプルテンプレート

AWS CloudFormation テンプレート (CI/CD 環境作成用)

AWSTemplateFormatVersion: 2010-09-09
Description: The CloudFormation template that creates a CICD environment for a container Lambda function.

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  SubName:
    Type: String
    Description: System sub name of EXAMPLE. (e.g. prod, test or your name)
    Default: yourname
    MaxLength: 10
    MinLength: 1

Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
  S3BucketArtifact:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub example-${SubName}-artifact
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}

  S3BucketLogs:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub example-${SubName}-logs
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}

# ------------------------------------------------------------#
# ECR
# ------------------------------------------------------------#
  EcrRepositoryLMBD:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Sub example-get-python-version-${SubName}
      EncryptionConfiguration:
        EncryptionType: AES256
      ImageScanningConfiguration:
        ScanOnPush: true
      ImageTagMutability: IMMUTABLE
      LifecyclePolicy:
        LifecyclePolicyText: |
          {
            "rules": [
              {
                "rulePriority": 1,
                "description": "Keep only 5 images, expire all others",
                "selection": {
                  "tagStatus": "any",
                  "countType": "imageCountMoreThan",
                  "countNumber": 5
                },
                "action": {
                  "type": "expire"
                }
              }
            ]
          }
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}

# ------------------------------------------------------------#
#  CodeCommit Repository
# ------------------------------------------------------------#
  CodeCommitRepoLMBD:
    Type: AWS::CodeCommit::Repository
    Properties:
      RepositoryName: !Sub example-lmbd-${SubName}
      RepositoryDescription: !Sub Source Code for EXAMPLE-LMBD-${SubName}
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}

# ------------------------------------------------------------#
# CodePipeline
# ------------------------------------------------------------#
  CodePipelineLMBD:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub EXAMPLE-${SubName}-LMBD
      ArtifactStore:
        Location: !Ref S3BucketArtifact
        Type: S3
      RestartExecutionOnUpdate: false
      RoleArn: !GetAtt CodePipelineServiceRoleLMBD.Arn
      Stages:
        - Name: Source
          Actions:
            - Name: Source
              RunOrder: 1
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              Configuration:
                RepositoryName: !GetAtt CodeCommitRepoLMBD.Name
                BranchName: master
                PollForSourceChanges: false
                OutputArtifactFormat: CODEBUILD_CLONE_REF
              Namespace: SourceVariables
              OutputArtifacts:
                - Name: Source
        - Name: Build
          Actions:
            - Name: Build
              RunOrder: 1
              Region: !Sub ${AWS::Region}
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              Configuration:
                ProjectName: !Ref CodeBuildProjectLMBD
                BatchEnabled: false
                EnvironmentVariables: |
                  [
                    {
                      "name": "IMAGE_TAG",
                      "type": "PLAINTEXT",
                      "value": "#{codepipeline.PipelineExecutionId}"
                    }
                  ]
              Namespace: BuildVariables
              InputArtifacts:
                - Name: Source
              OutputArtifacts:
                - Name: Build
        - Name: Deploy
          Actions:
            - ActionTypeId:
                Category: Deploy
                Owner: AWS
                Provider: CloudFormation
                Version: 1
              Configuration:
                StackName: !Sub EXAMPLE-${SubName}-LambdaContainer
                Capabilities: CAPABILITY_NAMED_IAM
                RoleArn: !GetAtt CodePipelineDeployCreateUpdateRoleLMBD.Arn
                ActionMode: CREATE_UPDATE
                TemplatePath: Build::Cfn_LambdaContainer.yml
                ParameterOverrides: !Sub '{"SubName": "${SubName}","ImageTag":"#{codepipeline.PipelineExecutionId}"}'
              InputArtifacts:
                - Name: Build
              Name: CreateOrUpdate
              RoleArn: !GetAtt CodePipelineDeployCreateUpdateActionRoleLMBD.Arn
              RunOrder: 1
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}
    DependsOn:
      - CodePipelineServiceRoleLMBD
      - CodeBuildProjectLMBD
      - CodePipelineDeployCreateUpdateActionRoleLMBD

# ------------------------------------------------------------#
# CodePipeline Service Role (IAM)
# ------------------------------------------------------------#
  CodePipelineServiceRoleLMBD:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-CodePipelineServiceRoleLMBD-${SubName}
      Description: This role allows CodePipeline to call each stages.
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - codepipeline.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: !Sub EXAMPLE-CodePipelineServiceRolePolicyLMBD-${SubName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "codecommit:CancelUploadArchive"
                  - "codecommit:GetBranch"
                  - "codecommit:GetCommit"
                  - "codecommit:GetRepository"
                  - "codecommit:GetUploadArchiveStatus"
                  - "codecommit:UploadArchive"
                Resource: !GetAtt CodeCommitRepoLMBD.Arn
              - Effect: Allow
                Action:
                  - "codebuild:BatchGetBuilds"
                  - "codebuild:StartBuild"
                  - "codebuild:BatchGetBuildBatches"
                  - "codebuild:StartBuildBatch"
                Resource: "*"
              - Effect: Allow
                Action:
                  - "cloudwatch:*"
                  - "s3:*"
                Resource: "*"
              - Effect: Allow
                Action:
                  - "lambda:InvokeFunction"
                  - "lambda:ListFunctions"
                Resource: "*"
              - Effect: Allow
                Action: "sts:AssumeRole"
                Resource:
                  - !GetAtt CodePipelineDeployCreateUpdateActionRoleLMBD.Arn
    DependsOn:
      - CodeCommitRepoLMBD
      - CodePipelineDeployCreateUpdateActionRoleLMBD

# ------------------------------------------------------------#
# CodePipeline Deploy Create Update Role (IAM)
# ------------------------------------------------------------#
  CodePipelineDeployCreateUpdateRoleLMBD:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-CdPlCreateUpdateRoleLMBD-${SubName}
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
        Version: "2012-10-17"
      Path: /
      Policies:
        - PolicyName: !Sub EXAMPLE-CdPlCreateUpdatePolicyLMBD-${SubName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action: "*"
                Effect: Allow
                Resource: "*"

# ------------------------------------------------------------#
# CodePipeline Deploy Create Update Action Role (IAM)
# ------------------------------------------------------------#
  CodePipelineDeployCreateUpdateActionRoleLMBD:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-CdPlCreateUpdateActionRoleLMBD-${SubName}
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
        Version: "2012-10-17"
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
      Policies:
        - PolicyName: !Sub EXAMPLE-CdPlCreateUpdatePolicyLMBD-${SubName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action: iam:PassRole
                Effect: Allow
                Resource: !GetAtt CodePipelineDeployCreateUpdateRoleLMBD.Arn
              - Action:
                  - s3:GetBucket*
                  - s3:GetObject*
                  - s3:List*
                Effect: Allow
                Resource:
                  - !Sub arn:aws:s3:::${S3BucketArtifact}
                  - !Sub arn:aws:s3:::${S3BucketArtifact}/*
    DependsOn:
      - CodePipelineDeployCreateUpdateRoleLMBD
      - S3BucketArtifact

# ------------------------------------------------------------#
# EventBridge Rule for Starting CodePipeline
# ------------------------------------------------------------#
  EventBridgeRuleStartCodePipelineLMBD:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub EXAMPLE-StartCpRuleLMBD-${SubName}
      Description: !Sub This rule starts CodePipeline for EXAMPLE-${SubName} LMBD when its source code in CodeCommit is changed.
      EventBusName: !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:event-bus/default"
      EventPattern:
        source:
          - "aws.codecommit"
        detail-type:
          - "CodeCommit Repository State Change"
        resources:
          - !GetAtt CodeCommitRepoLMBD.Arn
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - master
      RoleArn: !GetAtt EventBridgeRuleStartCpRoleLMBD.Arn
      State: ENABLED
      Targets:
        - Arn: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipelineLMBD}"
          Id: !Sub Target-EXAMPLE-CodePipelineLMBD-${SubName}
          RoleArn: !GetAtt EventBridgeRuleStartCpRoleLMBD.Arn
    DependsOn:
      - EventBridgeRuleStartCpRoleLMBD

# ------------------------------------------------------------#
# EventBridge Rule Start CodePipeline Role (IAM)
# ------------------------------------------------------------#
  EventBridgeRuleStartCpRoleLMBD:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-EventBridgeRuleStartCpRoleLMBD-${SubName}
      Description: !Sub This role allows EventBridge to start EXAMPLE-${SubName} LMBD CodePipeline.
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - events.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: !Sub EXAMPLE-EventBridgeRuleStartCpRolePolicyLMBD-${SubName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "codepipeline:StartPipelineExecution"
                Resource:
                  - !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipelineLMBD}"
    DependsOn:
      - CodePipelineLMBD

# ------------------------------------------------------------#
# CodeBuild Project
# ------------------------------------------------------------#
  CodeBuildProjectLMBD:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub EXAMPLE-${SubName}-BP-LMBD
      Description: !Sub The build project for EXAMPLE-${SubName} LMBD.
      ResourceAccessRole: !GetAtt CodeBuildResourceAccessRoleLMBD.Arn
      ServiceRole: !GetAtt CodeBuildServiceRoleLMBD.Arn
      ConcurrentBuildLimit: 1
      Visibility: PRIVATE
      Source:
        Type: CODEPIPELINE
      SourceVersion: refs/heads/master
      Environment:
        Type: LINUX_CONTAINER
        ComputeType: BUILD_GENERAL1_SMALL
        Image: "aws/codebuild/amazonlinux2-x86_64-standard:4.0"
        ImagePullCredentialsType: CODEBUILD
        PrivilegedMode: true
        EnvironmentVariables:
          - Name: AWS_DEFAULT_REGION
            Type: PLAINTEXT
            Value: !Sub ${AWS::Region}
          - Name: AWS_ACCOUNT_ID
            Type: PLAINTEXT
            Value: !Sub ${AWS::AccountId}
          - Name: IMAGE_REPO_NAME
            Type: PLAINTEXT
            Value: !Ref EcrRepositoryLMBD
      TimeoutInMinutes: 30
      QueuedTimeoutInMinutes: 60
      Artifacts:
        Type: CODEPIPELINE
      Cache:
        Type: NO_CACHE
      LogsConfig:
        CloudWatchLogs:
          GroupName: !Sub /aws/codebuild/EXAMPLE-${SubName}-LMBD
          Status: ENABLED
        S3Logs:
          EncryptionDisabled: true
          Location: !Sub arn:aws:s3:::${S3BucketLogs}/codebuildBuildlog
          Status: ENABLED
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}
    DependsOn:
      - EcrRepositoryLMBD
      - CodeBuildResourceAccessRoleLMBD
      - CodeBuildServiceRoleLMBD

# ------------------------------------------------------------#
# CodeBuild Resource Access Role (IAM)
# ------------------------------------------------------------#
  CodeBuildResourceAccessRoleLMBD:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-CodeBuildResourceAccessRoleLMBD-${SubName}
      Description: This role allows CodeBuild to access CloudWatch Logs and Amazon S3 artifacts for the project's builds.
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - codebuild.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: !Sub EXAMPLE-CodeBuildResourceAccessRolePolicyLMBD-${SubName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource:
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/EXAMPLE-${SubName}-LMBD"
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/EXAMPLE-${SubName}-LMBD:*"
              - Effect: Allow
                Action:
                  - "s3:PutObject"
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketAcl"
                  - "s3:GetBucketLocation"
                Resource:
                  - !Sub arn:aws:s3:::${S3BucketLogs}
                  - !Sub arn:aws:s3:::${S3BucketLogs}/*

# ------------------------------------------------------------#
# CodeBuild Service Role (IAM)
# ------------------------------------------------------------#
  CodeBuildServiceRoleLMBD:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-CodeBuildServiceRoleLMBD-${SubName}
      Description: This role allows CodeBuild to interact with dependant AWS services.
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - codebuild.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
      Policies:
        - PolicyName: !Sub EXAMPLE-CodeBuildServiceRolePolicyLMBD-${SubName}
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "codecommit:GitPull"
                Resource: !GetAtt CodeCommitRepoLMBD.Arn
              - Effect: Allow
                Action:
                  - "ssm:GetParameters"
                Resource:
                  - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/EXAMPLE_${SubName}_*"
              - Effect: Allow
                Action:
                  - "s3:*"
                Resource:
                  - !Sub arn:aws:s3:::${S3BucketArtifact}
                  - !Sub arn:aws:s3:::${S3BucketArtifact}/*
                  - !Sub arn:aws:s3:::${S3BucketLogs}
                  - !Sub arn:aws:s3:::${S3BucketLogs}/*
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource:
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/EXAMPLE-${SubName}-LMBD"
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/EXAMPLE-${SubName}-LMBD:*"
              - Effect: Allow
                Action:
                  - "codebuild:CreateReportGroup"
                  - "codebuild:CreateReport"
                  - "codebuild:UpdateReport"
                  - "codebuild:BatchPutTestCases"
                  - "codebuild:BatchPutCodeCoverages"
                Resource:
                  - !Sub "arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/EXAMPLE-${SubName}*"
    DependsOn:
      - CodeCommitRepoLMBD
      - S3BucketArtifact
      - S3BucketLogs

※ IAM ロールの権限が一部適当 (権限が多すぎ) な部分があります。申し訳ありませんが適宜変更下さいませ。

AWS CloudFormation テンプレート (AWS コンテナ Lambda 関数デプロイ用)

  • Cfn_LambdaContainer.yml
AWSTemplateFormatVersion: 2010-09-09
Description: The CloudFormation template that creates a Lambda function on container and a relevant IAM role.

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  SubName:
    Type: String
    Description: System sub name of EXAMPLE. (e.g. prod, test or your name)
    Default: yourname
    MaxLength: 10
    MinLength: 1
    
  ImageTag:
    Type: String
    Description: The image tag of container in ECR. This is accepted from CodePipeline.
    Default: latest
    MaxLength: 50
    MinLength: 1

Resources:
# ------------------------------------------------------------#
# Lambda TestInvocation Role (IAM)
# ------------------------------------------------------------#
  LambdaTestInvocationRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub EXAMPLE-LambdaTestInvocationRole-${SubName}
      Description: This role allows Lambda functions to invoke Test.
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess

# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------#
  LambdaTest:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub EXAMPLE-getPythonVersion-${SubName}
      Description: !Sub Lambda Function to get python version for EXAMPLE-${SubName}
      PackageType: Image
      Timeout: 30
      MemorySize: 128
      EphemeralStorage:
        Size: 512
      Architectures:
        - x86_64
      Role: !GetAtt LambdaTestInvocationRole.Arn
      Tags:
        - Key: Cost
          Value: !Sub EXAMPLE-${SubName}
      Code:
        ImageUri: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/example-get-python-version-${SubName}:${ImageTag}
    DependsOn:
      - LambdaTestInvocationRole
タイトルとURLをコピーしました