Fargate+CodePipelineをCFnで構築してみる

2019.05.08

おはようございます、もきゅりんです。

Fargate+RDS(MySQL5.7)+FlaskをCFnで構築してみるの続きになります。

今回は、「Fargateを使ったCodePipelineをCFn構築」の対応となります。

特に特筆することがないため、テンプレートの記載と確認だけ行います笑

Cloudformationテンプレート

今回使うテンプレートのパラメータでは、前回利用したsample-fargate.yamlのパラメータの"ProjectName"を利用します。

(パラメータをDefaultから変更している場合は注意して下さい!)

下記のテンプレートおよびパラメータファイルを作成したら、こちらのコマンドでスタックを作成します。

aws cloudformation create-stack --stack-name YOUR_STACK_NAME \
--template-body file://`pwd`/sample-fargate-codepipeline.yml \
--parameters file://`pwd`/fargate-codepipeline-parameter.json \
--capabilities CAPABILITY_NAMED_IAM

sample-fargate-codepipeline.yml

AWSTemplateFormatVersion: 2010-09-09
Description: CodePipeline For ECS Fargate

Parameters:
  Cluster:
    Type: String
  Service:
    Type: String
  ContainerName:
    Type: String
  ECRName:
    Type: String
  CodeCommitRepositoryName:
    Type: String
  PipelineName:
    Type: String

Resources:
  # CodeWatchEventを実行できるIAMRole
  AmazonCloudWatchEventRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: cwe-pipeline-execution
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: codepipeline:StartPipelineExecution
                Resource: !Join
                  - ""
                  - - "arn:aws:codepipeline:"
                    - !Ref "AWS::Region"
                    - ":"
                    - !Ref "AWS::AccountId"
                    - ":"
                    - !Ref "PipelineName"

  # CodeBuildに適用するIAMRole
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      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:
              - Resource: "*"
                Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
              - Resource: !Sub arn:aws:s3:::${ArtifactBucket}/*
                Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:GetObjectVersion
                  - s3:GetBucketAcl
                  - s3:GetBucketLocation
              - 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

  # CodePipelineに適用するIAMRole
  CodePipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      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:
              - Resource:
                  - !Sub arn:aws:s3:::${ArtifactBucket}/*
                Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketVersioning
              - Resource: "*"
                Effect: Allow
                Action:
                  - codecommit:GetRepository
                  - codecommit:ListBranches
                  - codecommit:GetUploadArchiveStatus
                  - codecommit:UploadArchive
                  - codecommit:CancelUploadArchive
                  - codedeploy:CreateDeployment
                  - codedeploy:GetApplication
                  - codedeploy:GetApplicationRevision
                  - codedeploy:GetDeployment
                  - codedeploy:GetDeploymentConfig
                  - codedeploy:RegisterApplicationRevision
                  - codebuild:StartBuild
                  - codebuild:StopBuild
                  - codebuild:BatchGet*
                  - codebuild:Get*
                  - codebuild:List*
                  - codecommit:GetBranch
                  - codecommit:GetCommit
                  - s3:*
                  - ecs:*
                  - elasticloadbalancing:*
                  - autoscaling:*
                  - iam:PassRole

  # S3Bucket
  ArtifactBucket:
    Type: AWS::S3::Bucket

  # CloudWatchEventの実行ルール
  AmazonCloudWatchEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.codecommit
        detail-type:
          - "CodeCommit Repository State Change"
        resources:
          - !Join
            - ""
            - - "arn:aws:codecommit:"
              - !Ref "AWS::Region"
              - ":"
              - !Ref "AWS::AccountId"
              - ":"
              - !Ref "CodeCommitRepositoryName"
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - master
      Targets:
        - Arn:
            !Join
              - ""
              - - 'arn:aws:codepipeline:'
                - !Ref 'AWS::Region'
                - ':'
                - !Ref 'AWS::AccountId'
                - ':'
                - !Ref 'PipelineName'

          RoleArn: !GetAtt AmazonCloudWatchEventRole.Arn
          Id: codepipeline-AppPipeline

  # CodeBuild
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      Source:
        Type: CODEPIPELINE
        BuildSpec: |
          version: 0.2
          phases:
            pre_build:
              commands:
                - echo Logging in to Amazon ECR...
                - $(aws ecr get-login --no-include-email)
                - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
                - IMAGE_TAG=${COMMIT_HASH:=latest}
            build:
              commands:
                - echo Build started on `date`
                - echo Building the Docker image...
                - docker build -t $REPOSITORY_URI:latest .
                - 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 image definitions file...
                - echo "[{\"name\":\"${ContainerName}\",\"imageUri\":\"${REPOSITORY_URI}:${IMAGE_TAG}\"}]" > imagedefinitions.json
          artifacts:
            files: imagedefinitions.json
      Environment:
        PrivilegedMode: true
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/docker:18.09.0-1.7.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: !Ref AWS::StackName
      ServiceRole: !Ref CodeBuildServiceRole

  # CodePipeLine
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn: !GetAtt CodePipelineServiceRole.Arn
      Name: !Ref PipelineName
      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: Deploy
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: ECS
              Configuration:
                ClusterName: !Ref Cluster
                ServiceName: !Ref Service
                FileName: imagedefinitions.json
              RunOrder: 1
              InputArtifacts:
                - Name: BuildOutput

fargate-codepipeline-parameter.json

[
  {
    "ParameterKey": "Cluster",
    "ParameterValue": "ProjectName-cluster"
  },
  {
    "ParameterKey": "Service",
    "ParameterValue": "ProjectName-service"
  },
  {
    "ParameterKey": "ContainerName",
    "ParameterValue": "ProjectName-container"
  },
  {
    "ParameterKey": "ECRName",
    "ParameterValue": "ECR_NAME"
  },
  {
    "ParameterKey": "CodeCommitRepositoryName",
    "ParameterValue": "YOUR_CODECOMMIT_REPO_NAME"
  },
  {
    "ParameterKey": "PipelineName",
    "ParameterValue": "YOUR_PIPELINE_NAME"
  }
]

確認

パイプラインが作成されたら、ファイルを更新してCodeCommitにPushしてみます

titel change

こんな感じでクリクリしてます

code building

完了したら、またDNSからアクセスしてみます

code deployed

はい、タイトルが更新されていますね。

check the title changed

お疲れ様でしたー。 この記事がどなたかのお役に立てれば幸いです。

参考

チュートリアル: CodePipeline を使用した継続的なデプロイ

CodePipeline でパイプラインの実行を開始する

CodeCommit ソースの CloudWatch イベント ルールを作成する (AWS CloudFormation テンプレート)

ECS-refarch-Continuous-Development

[AWS] AWSCloudFormationでCI/CDパイプライン(CodePipeLine)を構築する