プロジェクト

全般

プロフィール

Memo 2023 03 final

3/29(水)17:15~18:30

  • 各自オレオレReactアプリ発表会
  • ".env"について
  • CodePiplelineによるデプロイの自動化

Adding Custom Environment Variables
Reactの環境変数をdotenv-cliで切り替えてみた

CodePiplelineによるデプロイの自動化

  • Reactプロジェクトフォルダのトップに下記の内容で"buildspec.yml"ファイルを追加
version: 0.2

phases:
  pre_build:
    on-failure: ABORT
    commands:
      - npm ci
  build:
    commands:
      - npm run build
  post_build:
    commands:
      - cd build
      - aws s3 sync --exact-timestamps --cache-control 'max-age=2592000' --exclude '*' --include 'static/**/*' . s3://${DEPLOY_BUKET}
      - aws s3 sync --exact-timestamps --cache-control 'no-cache' --delete . s3://${DEPLOY_BUKET}

S3+CloudFront用CloudFormationテンプレート(最新化版)

AWSTemplateFormatVersion: '2010-09-09'
Description: Sample template for S3Origin CloudFront

Parameters:
  CloudFrontPriceClass:
    Type: String
    Default: PriceClass_200
    AllowedValues: [PriceClass_100, PriceClass_200, PriceClass_All]

Resources:

  OriginS3Bucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  OriginS3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref OriginS3Bucket
      PolicyDocument:
        Statement:
          - Action: s3:GetObject
            Effect: Allow
            Resource: !Sub arn:${AWS::Partition}:s3:::${OriginS3Bucket}/*
            Principal:
              Service: cloudfront.amazonaws.com
            Condition:
              StringEquals:
                AWS:SourceArn: !Sub arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
          - Action: s3:ListBucket
            Effect: Allow
            Resource: !Sub arn:${AWS::Partition}:s3:::${OriginS3Bucket}
            Principal:
              Service: cloudfront.amazonaws.com
            Condition:
              StringEquals:
                AWS:SourceArn: !Sub arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Comment: !Sub 'Created by ${AWS::StackName}'
        DefaultCacheBehavior:
          TargetOriginId: myS3Origin
          ForwardedValues:
            QueryString: false
            Cookies:
              Forward: 'none'
          ViewerProtocolPolicy: redirect-to-https
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized
          OriginRequestPolicyId: acba4595-bd28-49b8-b9fe-13317c0390fa # UserAgentRefererHeaders
          Compress: true
        DefaultRootObject: index.html
        Enabled: true
        Origins:
          - DomainName: !Sub ${OriginS3Bucket}.s3.amazonaws.com
            Id: myS3Origin
            S3OriginConfig:
              OriginAccessIdentity: ''
            OriginAccessControlId: !GetAtt OriginAccessControl.Id
        PriceClass: !Ref CloudFrontPriceClass
        Restrictions:
          GeoRestriction:
            RestrictionType: whitelist
            Locations:
              - JP

  OriginAccessControl:
    Type: AWS::CloudFront::OriginAccessControl
    Properties:
      OriginAccessControlConfig:
        Description: !Sub 'OAC of ${OriginS3Bucket}. Created by ${AWS::StackName}'
        Name: !Sub 'OAC-${OriginS3Bucket}'
        OriginAccessControlOriginType: s3
        SigningBehavior: always
        SigningProtocol: sigv4

Outputs:
  OriginS3BucketName:
    Value: !Ref OriginS3Bucket
    Export:
      Name: !Sub ${AWS::StackName}-OriginS3Bucket
  CloudfrontDomainName:
    Value: !GetAtt CloudFrontDistribution.DomainName
    Export:
      Name: !Sub ${AWS::StackName}-CloudfrontDomainName

CodePipleline構成用CloudFormationテンプレート

AWSTemplateFormatVersion: '2010-09-09'
Description: Sample CodePipeline template for SPA(React) with S3+CloudFront.

Parameters:
  DeployBucketName:
    Type: String
  SourceRepositoryName:
    Type: String
  SourceBranch:
    Type: String
    Default: master

Resources:

  ### CodeBuild and CodePipeline ###
  CodeBuild:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub ${AWS::StackName}-CodeBuild
      Description: !Sub "Created by ${AWS::StackName}"
      Source:
        BuildSpec: buildspec.yml
        Type: CODEPIPELINE
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        Type: LINUX_CONTAINER
        ComputeType: "BUILD_GENERAL1_SMALL"
        Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
      ServiceRole: !GetAtt CodeBuildServiceRole.Arn
      LogsConfig:
        CloudWatchLogs:
          Status: ENABLED

  CodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub ${AWS::StackName}-CodePipeline
      RoleArn: !GetAtt CodepipelineServiceRole.Arn
      ArtifactStore:
        Location: !Ref ArtifactStoreBucket
        Type: S3
      RestartExecutionOnUpdate: false
      Stages:
        - Name: Source
          Actions:
            - Name: Source
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: CodeCommit
                Version: '1'
              Configuration:
                RepositoryName: !Ref SourceRepositoryName
                BranchName: !Ref SourceBranch
                PollForSourceChanges: false
              OutputArtifacts:
                - Name: SourceArtifact
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: '1'
              Configuration:
                ProjectName: !Ref CodeBuild
                EnvironmentVariables: !Sub |
                  [
                    {
                      "name":"DEPLOY_BUKET",
                      "type":"PLAINTEXT",
                      "value": "${DeployBucketName}"
                    }
                  ]
              InputArtifacts:
                - Name: SourceArtifact
              Namespace: BuildVariables

  ArtifactStoreBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Sub ${AWS::StackName}-artifactstore-${AWS::AccountId}
      LifecycleConfiguration:
        Rules:
          - Id: clear-old-objects-rule
            Status: Enabled
            ExpirationInDays: 7
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  ### ServiceRoles for CodeService ###
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /service-role/
      RoleName: !Sub ${AWS::StackName}-codebuild-ServiceRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AdministratorAccess

  CodepipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /service-role/
      RoleName: !Sub ${AWS::StackName}-codepipeline-ServiceRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codepipeline.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AdministratorAccess

  ### Resorces for EventBridge Rule ###
  EventBridgeIAMPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "codepipeline:StartPipelineExecution"
            Resource:
              - !Sub arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipeline}
      ManagedPolicyName: !Sub "${CodePipeline}-policy"

  EventBridgeIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - !Ref EventBridgeIAMPolicy
      RoleName: iam-role-eventbridge
      Tags:
        - Key: Name
          Value: iam-role-eventbridge

  EventBridge:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub "changeEvent-rule-${CodePipeline}"
      Description: !Sub "for ${CodePipeline}. Created by ${AWS::StackName}"
      EventPattern:
        source:
          - aws.codecommit
        detail-type:
          - 'CodeCommit Repository State Change'
        resources:
          - !Sub arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${SourceRepositoryName}
        detail:
          event: ['referenceCreated', 'referenceUpdated']
          referenceType:
            - branch
          referenceName:
            - !Ref SourceBranch
      State: ENABLED
      Targets:
        - Arn: !Sub arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipeline}
          Id: CodePipeline
          RoleArn: !GetAtt EventBridgeIAMRole.Arn

コマンドでのデプロイ例

wget https://redmine.apps.kinocoffeeblack.net/attachments/download/251/template_s3_cf_202303.yaml
wget https://redmine.apps.kinocoffeeblack.net/attachments/download/250/template_pipeline.yaml


STACK_NAME_BASE=study
aws cloudformation deploy --stack-name ${STACK_NAME_BASE}-s3cf --template-file ./template_s3_cf_202303.yaml
aws cloudformation deploy --stack-name ${STACK_NAME_BASE}-pipeline --template-file ./template_pipeline.yaml --capabilities CAPABILITY_NAMED_IAM --parameter-overrides DeployBucketName=S3バケット名 SourceRepositoryName=CodeCommitリポジトリ名 SourceBranch=master
  • 「CodeCommitリポジトリ名」のSourceBranchで指定したブランチにpushすると、CodePipeLineが動きだしてS3バケットに自動でデプロイされる

gitのローカルリポジトリにリモートリポジトリ(CodeCommit)を設定してpushする方法メモ

"git init"等についての説明は省略。create-react-appで生成したソースは、初期状態から"git init"と最初のコミットがされた状態になっているはず。

■リモートリポジトリのURLを設定(この例の場合は"origin"として)

git remote add origin ssh://ホスト/v1/repos/リポジトリ名
  • ホストは %userprofile%/.ssh/config で設定したホスト(※)
  • リポジトリ名はCodeCommitのリポジトリ名"react-demo-szk" or "react-demo-go1"

※ .ssh/configファイルが下記の設定の場合は"git-kino"をホストに設定

Host git-kino
  HostName git-codecommit.us-east-1.amazonaws.com
  User (IAMのSSHキーID)
  IdentityFile ~/.ssh/git-kino_rsa

■確認

git remote -v

■push

git push origin master

※ ローカルのブランチ名が"main"の場合は"master"を"main"に読み替え