LoginSignup
0
0

More than 1 year has passed since last update.

CICD CodeDeployアーティファクトサイズリミットの対応(その2)

Last updated at Posted at 2021-07-30

1. 概要

AWS CodePipelineのCodeCommitによるCICDのBlue/Greenを実装するには、Deployステージに渡されたアーティファクトのサイズ制限があり、前回の投稿ではS3のPipelineに変更と別のappspec.yml、taskdef.jsonだけを格納するCodeCommitリポジトリを作成の二つ対処方法を紹介した。

S3 Pipelineの対処方法には、作成されたCodeCommitタイプのPipelineのCloudFormationのソースファイルの変更作業が多いの短所があり、別のCodeCommitリポジトリの対処では改めてCodeCommitリポジトリの作成が必要もあるため、両対処とも少し手間が掛かる。

本文は、両対処方法の長所を連携し、S3バーケットを事前に作成し、Dockerファイルをこのバーケットにおいて置き、AWS::CodeBuild::Project段階まずCodeCommitリポジトリにある古いパッケージファイル(target/*.jarなど)cleanし、S3バーケットを利用してCodePipelineのSourceステージで作成されたアーティファクトのサイズの抑えることができ、別のCodeCommitリポジトリを作成しなくてもオリジナルのCodeCommitリポジトリのままでCICDを実現する方法を紹介する。

2. 対処法

Step1:S3バーケットを作る。Dockerfileを格納する。
作成されたS3バーケットと格納されたDockerfile を下記の図をご参照ください。実際、このStepによりS3バーケットにDockerfileをアップロードしておけば、DockerfileをCodeCommitリポジトリに格納しなくてもCodeDeployを起動することが出来る。

image.png

FROM amazoncorretto:11-al2-jdk
EXPOSE 22
EXPOSE 80
EXPOSE 8080
RUN yum install -y iputils
RUN yum install -y net-tools
RUN yum install -y iputils
RUN yum -y install procps

RUN mkdir /usr/local/bin/api
RUN mkdir /usr/local/bin/batch
RUN mkdir /usr/local/bin/common
RUN mkdir /usr/local/bin/database
RUN mkdir /usr/local/bin/stubs
RUN mkdir /usr/local/bin/lib
ADD target/xxxxxxx_api-0.0.1-SNAPSHOT.jar /usr/local/bin/api/xxxxxxx_api-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java", "-jar", "/usr/local/bin/api/xxxxxxx_api-0.0.1-SNAPSHOT.jar"]

Step2:buildspec.ymlを編集する

Buildする際使用するDockerfileを、S3バーケットからコピーする、とDockerImageを作るにPathを“xxxxxxx-api/.”を指定することをご注意。
このbuildspec.ymlファイルをCodeBuildのProjectに埋め込み。

buildspec.yml
version: 0.2
env:
  parameter-store:
    DOCKER_USER: dockerhub-user
    DOCKER_TOKEN: dockerhub-token
phases:
  install:
    runtime-versions:
      java: corretto11
    commands:
      - mvn clean
      - aws s3 cp s3://xxx-dev-xxxx-s3-01/Dockerfile-xxxx-api-s3 .
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --no-include-email)
      - REPOSITORY_URI=xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxx-dev-xxxx-app-ecr
      - COMMIT_HASH=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HAST:=latest}
      - echo Logging in to Docker Hub...
      - echo ${DOCKER_TOKEN} | docker login -u ${DOCKER_USER} --password-stdin
  build:
    commands:
      - echo Build started on `date`
      - mvn package --also-make --projects xxxxxxx-api -Dmaven.test.skip=true
      - echo Building the Docker image...
      # - docker build -t ${REPOSITORY_URI}:latest .
      - docker build -t $REPOSITORY_URI:latest xxxxxxx-api/. -f ./Dockerfile-xxxx-api-s3
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker images...
      # - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - echo Writing imageDetail json...
      - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
artifacts:
  files:
    - imageDetail.json

Step3:CodeCommitのリポジトリに応用開発のソースコード、及びappspec.yml、taskdef.jsonを格納する。下記図は例である。

image.png

appspec.yml
version: 0.0
Resources:
        - TargetService:
                Type: AWS::ECS::Service
                Properties:
                        TaskDefinition: "<TASK_DEFINITION>"
                        LoadBalancerInfo:
                                ContainerName: "xxx-dev-xxxx-app-container"
                                ContainerPort: "80"

3. 完成したCloudFormationYamlファイル

参照するため、完成したCodePipelineを作成するCloudFormationのYamlファイルを添付する。

pipeline-s3.yml
AWSTemplateFormatVersion: 2010-09-09
Description: CodePipeline For ECS Fargate Blue/Green Deploy with PlaceHolder
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
Parameters:
  AwsXxxxxRegion:
    Type: String
    Default: xx-xxxxxxxxx-1
  Service:
    Type: String
    Default: xxxx
  Env:
    Type: String
    Default: dev

  ECRName:
    Type: String
    Default: xxx-dev-xxxx-app-ecr
  ContainerName:
    Type: String
    Default: xxx-dev-xxxx-app-container
  CodeCommitRepositoryName:
    Type: String
    Default: xxx-dev-xxxx-codecommit
  CodeDeployAppName:
    Type: String
    Default: xxx-dev-xxxx-deploy-app1
  CodeDeployGrpName:
    Type: String
    Default: xxx-dev-xxxx-deploy-grp1

  NameTagPrefix:
    Type: String
    Default: test
    Description: Prefix of Name tags.
  ServiceName:
    Type: String
    Default: xxxx
    Description: Prefix of Service tags.


# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
Resources:
  # ------------------------------------------------------------#
  # IAM Roles
  # ------------------------------------------------------------#
  # CodeWatchEventを実行できるIAMRole
  CloudwatchEventRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub  cwe-tko-${Service}-${Env}-phld-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: CloudWatchEventsPipelineExecution
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: codepipeline:StartPipelineExecution
                Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}

  # CodeBuildに適用するIAMRole
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub codebuild-tko-${Service}-${Env}-phld-service-role
      Path: /
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: SampleCodeBuildAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Resource: '*'
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
              - Effect: Allow
                Resource: !Sub arn:aws:s3:::${ArtifactBucket}/*
                Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketAcl
                  - s3:GetBucketLocation
              - Effect: Allow
                Action:
                  - codebuild:CreateReportGroup
                  - codebuild:CreateReport
                  - codebuild:UpdateReport
                  - codebuild:BatchPutTestCases
                  - codebuild:BatchPutCodeCoverages
                Resource: '*'
              - Effect: Allow
                Action:
                  - ecr:GetAuthorizationToken
                  - ecr:BatchCheckLayerAvailability
                  - ecr:GetDownloadUrlForLayer
                  - ecr:GetRepositoryPolicy
                  - ecr:DescribeRepositories
                  - ecr:ListImages
                  - ecr:DescribeImages
                  - ecr:BatchGetImage
                  - ecr:InitiateLayerUpload
                  - ecr:UploadLayerPart
                  - ecr:CompleteLayerUpload
                  - ecr:PutImage
                Resource: '*'

# add policy to get parameter from SSM parameter store
              - Effect: Allow
                Action:
                  - ssm:DescribeParameters
                  - ssm:GetParameters
                Resource: '*'

  # CodePipelineに適用するIAMRole
  CodePipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub codepipeline-tko-${Service}-${Env}-phld-role
      Path: /
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: codepipeline.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: SamplePipeline
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action:
                  - iam:PassRole
                Resource: '*'
                Effect: Allow
                Condition:
                  StringEqualsIfExists:
                    iam:PassedToService:
                      - ecs-tasks.amazonaws.com
              - Resource:
                  - !Sub arn:aws:s3:::${ArtifactBucket}/*
                Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketVersioning
              - Action:
                  - codecommit:CancelUploadArchive
                  - codecommit:GetBranch
                  - codecommit:GetCommit
                  - codecommit:GetRepository
                  - codecommit:GetUploadArchiveStatus
                  - codecommit:UploadArchive
                Resource: '*'
                Effect: Allow
              - Action:
                  - codedeploy:CreateDeployment
                  - codedeploy:GetApplication
                  - codedeploy:GetApplicationRevision
                  - codedeploy:GetDeployment
                  - codedeploy:GetDeploymentConfig
                  - codedeploy:RegisterApplicationRevision
                  - codedeploy:*
                Resource: '*'
                Effect: Allow
              - Action:
                  - elasticbeanstalk:*
                  - ec2:*
                  - elasticloadbalancing:*
                  - autoscaling:*
                  - cloudwatch:*
                  - sns:*
                  - cloudformation:*
                  - rds:*
                  - sqs:*
                  - ecs:*
                Resource: '*'
                Effect: Allow
              - Action:
                  - codebuild:BatchGetBuilds
                  - codebuild:StartBuild
                  - codebuild:BatchGetBuildBatches
                  - codebuild:StartBuildBatch
                Resource: '*'
                Effect: Allow

  # CodeDeployに適用するIAMRole
  CodeDeployRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: 'Allow'
            Principal:
              Service:
                - 'codedeploy.amazonaws.com'
            Action:
              - 'sts:AssumeRole'
      Path: '/'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
      RoleName: !Sub codedeploy-tko-${Service}-${Env}-phld-role

  # S3Bucket
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  # CloudWatchEventの実行ルール
  AmazonCloudWatchEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.codecommit
        detail-type:
          - CodeCommit Repository State Change
        resources:
          - Fn::Join:
              - ''
              - - 'arn:aws:codecommit:'
                - !Ref 'AWS::Region'
                - ':'
                - !Ref 'AWS::AccountId'
                - ':'
                - !Ref CodeCommitRepositoryName
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - master
      Targets:
        - Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
          RoleArn: !GetAtt CloudwatchEventRole.Arn
          Id: codepipeline-AppPipeline

  # CodeBuild
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      ServiceRole: !Ref CodeBuildServiceRole
      Artifacts:
        Type: CODEPIPELINE
      Source:
        Type: CODEPIPELINE
        BuildSpec: |
          version: 0.2
          env:
            parameter-store:
              DOCKER_USER: dockerhub-user
              DOCKER_TOKEN: dockerhub-token
          phases:
            install:
              runtime-versions:
                java: corretto11
              commands:
                - mvn clean
                - aws s3 cp s3://xxx-dev-xxxx-s3-01/Dockerfile-xxxx-api-s3 .
            pre_build:
              commands:
                - echo Logging in to Amazon ECR...
                - $(aws ecr get-login --no-include-email)
                - REPOSITORY_URI=xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxx-dev-xxxx-app-ecr
                - COMMIT_HASH=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7)
                - IMAGE_TAG=${COMMIT_HAST:=latest}
                - echo Logging in to Docker Hub...
                - echo ${DOCKER_TOKEN} | docker login -u ${DOCKER_USER} --password-stdin
            build:
              commands:
                - echo Build started on `date`
                - mvn package --also-make --projects xxxxxxx-api -Dmaven.test.skip=true
                - echo Building the Docker image...
                # - docker build -t ${REPOSITORY_URI}:latest .
                - docker build -t $REPOSITORY_URI:latest xxxxxxx-api/. -f ./Dockerfile-xxxx-api-s3
                - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
            post_build:
              commands:
                - echo Build completed on `date`
                - echo Pushing the Docker images...
                - docker push $REPOSITORY_URI:$IMAGE_TAG
                - echo Writing imageDetail json...
                - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
          artifacts:
            files:
              - imageDetail.json

      Environment:
        PrivilegedMode: true
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:4.0
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: AWS_DEFAULT_REGION
            Value: !Ref AWS::Region
          - Name: REPOSITORY_URI
            Value: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRName}
          - Name: ContainerName
            Value: !Ref ContainerName
          - Name: DOCKER_BUILDKIT
            Value: '1'
      Name: !Sub ${Service}-${Env}-phld-project1
#      Name: !Ref AWS::StackName

#  Following was original from pre_build
#                - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
#  Following 2 lines was the last part in build
#                - docker build -t $REPOSITORY_URI:$IMAGE_TAG .
#                - docker tag $REPOSITORY_URI:$IMAGE_TAG $REPOSITORY_URI:$IMAGE_TAG
#  Following 1 line was the last part in post_build
#                - docker push $REPOSITORY_URI:$IMAGE_TAG


# Create Code deploy application
#  CodeDeployApplication:
#    Type: AWS::CodeDeploy::Application
#    Properties:
#      ApplicationName: !Ref CodeDeployAppName
#      ComputePlatform: ECS

#  CodeDeployDeploymentGroup:
#    Type: AWS::CodeDeploy::DeploymentGroup
#    Properties:
#      ApplicationName: !Ref CodeDeployAppName
#      DeploymentGroupName: !Ref CodeDeployGrpName
#      DeploymentConfigName: CodeDeployDefault.ECSAllAtOnce
#      DeploymentStyle:
#        DeploymentType: BLUE_GREEN
#        DeploymentOption: WITH_TRAFFIC_CONTROL
#      ServiceRoleArn: !GetAtt CodeDeployRole.Arn
#      LoadBalancerInfo:
#        ElbInfoList:
#          - Name: !ImportValue DevXxxxAppNLB
#        TargetGroupInfoList:
#          - Name: !ImportValue DevXxxxAppTG1
#          - Name: !ImportValue DevXxxxAppTG2


  # ------------------------------------------------------------#
  # CodePipeline 
  # ------------------------------------------------------------#
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn: !GetAtt CodePipelineServiceRole.Arn
      Name: !Sub ${ServiceName}-phld-pipeline1
      ArtifactStore:
        Type: S3
        Location: !Ref ArtifactBucket
      Stages:
        - Name: Source
          Actions:
            - Name: SourceAction
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: '1'
                Provider: CodeCommit
              Configuration:
                RepositoryName: !Ref CodeCommitRepositoryName
                PollForSourceChanges: false
                BranchName: master
              RunOrder: 1
              OutputArtifacts:
                - Name: App
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: '1'
                Provider: CodeBuild
              Configuration:
                ProjectName: !Ref CodeBuildProject
              RunOrder: 1
              InputArtifacts:
                - Name: App
              OutputArtifacts:
                - Name: BuildOutput
        # - Name: Approval
        #   Actions:
        #     - Name: Manual_Approval
        #       ActionTypeId:
        #         Category: Approval
        #         Owner: AWS
        #         Version: '1'
        #         Provider: Manual
        #       Configuration:
        #         CustomData: !Sub '${ServiceName} will be updated. Do you want to deploy it?'
        #         NotificationArn: arn:aws:sns:ap-xx-xxxx-2:xxxxxxxx:hogehoge
        - Name: Deploy
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: '1'
                Provider: CodeDeployToECS
              Configuration:
                AppSpecTemplateArtifact: App
                AppSpecTemplatePath: appspec.yml
                TaskDefinitionTemplateArtifact: App
                TaskDefinitionTemplatePath: taskdef.json
                ApplicationName: !Ref CodeDeployAppName
                DeploymentGroupName: !Ref CodeDeployGrpName
#                StackName: xxxx-dev-ecs
#                ClusterName: !ImportValue DevXxxxEcsAppCluster
#                ServiceName: !ImportValue DevXxxxEcsAppService
                Image1ArtifactName: BuildOutput
                Image1ContainerName: IMAGE1_NAME
              RunOrder: 1
              InputArtifacts:
                - Name: App
                - Name: BuildOutput
              Region: !Ref AWS::Region
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
Outputs:
  PipelineDev:
    Description: Dev Xxxx Pipeline
    Value: !Ref Pipeline
    Export:
      Name: DevPhldAppPipeline

4. 作成されたアーティファクトのサイズ

CodePipelineのSourceステージで作成されたアーティファクト(本文はAPPの名前にした)のサイズは、CloudFormationにて作成されたRsourceのS3で調べられる。本文の場合は609KBになった。

5. まとめ

CodePipelineのCodeCommitによるCICDのBlue/Greenを実装するには、現状のDeployステージに渡されたアーティファクトの3MBサイズ制限に対し、本文のS3バーケットを事前に作成、Dockerファイルをこのバーケットにおいて置き、CodeBuildの作成された中間JarファイルもS3バーケットを利用し、CodePipelineのSourceステージで作成されたアーティファクトのサイズの抑えることができた。この方法では、オリジナルのCodeCommitリポジトリままでCICDを実現することができる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0