CI & CD

AWS CodePipeline을 이용하여 정적 웹 사이트를 S3에 배포

CloudLee 2024. 3. 25. 18:50

AWS CodePipeline을 이용하여 정적 웹 사이트를 S3에 배포

 

CodePipeline + S3

 

  • CodePipeline이란?

소프트웨어 릴리스에 필요한 단계를 모델링, 시각화 및 자동화하는 데 사용할 수 있는 지속적 전달하는 서비스로, 릴리스 프로세스의 여러 단계를 신속하게 모델링하고 구성할 뿐 아니라 소프트웨어 변경 사항을 지속적으로 릴리스하는 데 필요한 단계를 자동화합니다.

 

  • S3란?

최고의 확장성, 데이터 가용성, 보안 및 성능을 제공하는 객체 스토리지 서비스로, 데이터 레이크, 웹사이트, 모바일 애플리케이션, 백업 및 복원, 아카이브, 엔터프라이즈 애플리케이션, IoT 디바이스, 빅 데이터 분석 등 다양한 사용 사례에서 원하는 양의 데이터를 저장할 뿐 아니라 보호합니다.

 


#  TL;DR 

 

CloudFormation 템플릿을 활용하여 CodePipeline과 S3 서비스 구축하여 정적 웹 사이트를 배포합니다.

웹사이트 호스트 설정을 한 S3 Bucket을 Management console 상에서 미리 생성한 후에 진행합니다.

GitHub 리포지토리와 CodePipeline과 연동한 후에 git push, merge 를 계기로 vue.js 소스코드를 빌드하여 S3 bucket에 배포합니다.

buildspec.yml을 이용하여 CodeBuild를 정의하며. Cloudformation템플릿으로 CodePipeline.yml을 작성하여 CodePipeline을 정의합니다.

서비스 구축은 아래와 같은 순서로 진행합니다.

 

  • CodePipeline 구축 순서
  1. Codebuild에서 수행할 작업을 정의하는 buildspec.yml 작성
  2. Cloudformation템플릿(CodePipeline.yml)의 파라미터를 정의한 Parameters.json 작성
  3. CodePipeline을 구성하기 위한 Cloudformation템플릿(CodePipeline.yml) 작성
  4. AWS CLI로 CloudFormation 스택 생성
  5. CodePipeline 실행 테스트
  6. AWS CLI로 CloudFormation 스택 삭제

# 아키텍처 다이어그램

 

  • GitHub Repository의 소스 코드를 git clone, 빌드하여 S3 Bucket에 배포하는 다이어그램입니다.
  • CodeBuild와 CodePipeline에서 S3 bucket에 엑세스하기 위하여 권한을 부여하는 IAM role이 필요합니다.

# 개요

 

CI/CD 파이프라인을 Codepipeline으로 구현하여 GitHub 리포지토리에 있는 소스 코드를 빌드하여 자동으로 S3 bucket으로 배포하는 서비스를 구축합니다.

 

서비스  역할
AWS CloudFormation 스택 생성
AWS IAM 액세스 권한 추가
AWS S3 콘텐츠 배치, 아티팩트
CodeBuild 코드 빌드 
CodeDeploy 코드 배포
CodePipeline CI/CD 파이프라인 구축
GitHub 리포지토리

 

 


# Codebuild에서 실행하는 작업을 명시하는 buildspec.yml 작성

 

version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 14
  pre_build:
    commands:
      - echo cache clear
      - npm cache clear --force
      - echo npm install
      - npm install 
  build:
    commands:
      - echo code build
      - npm run build
artifacts:  
  files:
    - "**/*"
  base-directory: dist

 

 

  • nodejs : 14 -> nodejs버전을 지정합니다.
  • base-directory : dist ->  아티팩트의 base(root)를 빌드한 소스가 저장되는 dist 디렉토리로 지정하며 files:  **/*  로 dist 디렉토리의 모든 파일을 아티팩터로 저장합니다. codedeploy에서 아티팩터에 저장된 빌드된 소스를 s3 bucket에 배포하기 위하여 필요합니다.

# GitHub와 CodePipeline을 연동

우선 AWS Management console에서 Create connection을 통해 GitHub와 CodePipeline을 연동하도록 설정합니다.

connection 생성한 후엔 ConnectionArn의 값을 메모하여 다음 cloudformation parameter 파일에 추가하도록 합니다.

  • AWS management console을 통해 GitHub와 CodePipeline 연동하는 방법 

https://docs.aws.amazon.com/dtconsole/latest/userguide/connections-create-github.html

# Cloudformation작성에 필요한 파라미터 파일 codepipeline.json 작성

 

[
    {
      "ParameterKey": "Env",
      "ParameterValue": "dev"
    },
    {
      "ParameterKey": "Branch",
      "ParameterValue": "${git의 branch명}"
    },
    {
        "ParameterKey": "Repository",
        "ParameterValue": "${git의 리포지토리명}"
    },
    {
      "ParameterKey": "AppBucketName",
      "ParameterValue": "${정적웹사이트의 S3 bucket명}"
    },
    {
      "ParameterKey": "GitConnectionArn",
      "ParameterValue": "${ConnectionArn의 값}"
    }
  ]

 

  • Codepipeline과 연동할 git의 branch명, 리포지토리명, CodeConnetction Arn을 파라미터로 지정합니다.
  • 미리 생성한 S3 bucket명을 파라미터로 지정합니다.

 


#CodePipeline을 구성하기 위한 Cloudformation 파일 (codepipeline.yml) 작성

 

AWSTemplateFormatVersion: "2010-09-09"
Description: CodePipeline S3 stack.

# ------------------------------------------------------------
# Parameter
# ------------------------------------------------------------

Parameters:
  Env:
    Type: String
    Default: "dev"
  Branch:
    Type: String
    Default: ""
  Repository:
    Type: String
    Default: ""
  AppBucketName:
    Type: String
    Default: ""
  GitConnectionArn
    Type: String
    Default: ""
    
Resources:
  # ------------------------------------------------------------
  # Artifact용 S3 Bucket
  # ------------------------------------------------------------

  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${Env}-artifact
      VersioningConfiguration:
        Status: Enabled

  # ------------------------------------------------------------
  # CodeBuild
  # ------------------------------------------------------------

  CodeBuild:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub ${Env}-codebuild
      Source:
        BuildSpec: buildspec.yml
        Type: CODEPIPELINE
      Artifacts:
        Name: !Sub ${Env}-codepipeline
        Packaging: NONE
        Type: CODEPIPELINE
      Cache:
        Type: NO_CACHE
        
      # 환경설정
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:5.0
        ImagePullCredentialsType: CODEBUILD
        PrivilegedMode: false
        Type: LINUX_CONTAINER
      ServiceRole: !GetAtt CodebuildServiceRole.Arn
      TimeoutInMinutes: 60
      QueuedTimeoutInMinutes: 480
      BadgeEnabled: false

      # 로그 설정
      LogsConfig:
        CloudWatchLogs:
          Status: ENABLED
        S3Logs:
          Status: DISABLED

  # ------------------------------------------------------------
  # CodePipeline
  # ------------------------------------------------------------

  CodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub ${Env}-pipeline
      RoleArn: !GetAtt CodepipelineServiceRole.Arn
      ArtifactStore:
        Location: !Ref ArtifactBucket
        Type: S3
      Stages:
        - Name: Source
          Actions:
            - Name: Source
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: CodeStarSourceConnection
                Version: "1"
              Configuration:
                # 브랜치 지정
                BranchName: !Ref Branch
                # github 연동
                ConnectionArn: 
                 - !Ref GitConnectionArn
                # 리포지토리 지정
                FullRepositoryId: !Ref Repository
                OutputArtifactFormat: CODE_ZIP
              OutputArtifacts:
                - Name: SourceArtifact
              Namespace: SourceVariables
              RunOrder: 1
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: "1"
              Configuration:
                EnvironmentVariables: !Sub |
                  [
                    {"name":"STAGE","value":"dev","type":"PLAINTEXT"}
                  ]
                ProjectName: !Ref CodeBuild
              InputArtifacts:
                - Name: SourceArtifact
              OutputArtifacts:
                - Name: BuildArtifact
              Namespace: BuildVariables
              RunOrder: 1
        - Name: Deploy
          Actions:
            - Name: Deploy
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Provider: S3
                Version: "1"
              Configuration:
                BucketName: !Ref AppBucketName
                Extract: true
              InputArtifacts:
                - Name: BuildArtifact
              Namespace: DeployVariables
              RunOrder: 1
              
  # ------------------------------------------------------------
  # IAM
  # ------------------------------------------------------------

  #### CodeBuild Role 생성
  CodebuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      RoleName: !Sub ${Env}-codebuild-service-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: !Sub ${Env}-build-policy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Resource:
                  - !GetAtt LogGroup.Arn
                Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
              - Resource:
                  - arn:aws:s3:::codepipeline-ap-northeast-2-*
                  - !Sub arn:aws:s3:::${ArtifactBucket}/
                  - !Sub arn:aws:s3:::${ArtifactBucket}/*
                Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:GetObjectVersion
                  - s3:GetBucketAcl
                  - s3:GetBucketLocation
                  - s3:List*
              - Resource:
                  - !Ref ReportGroup
                Effect: Allow
                Action:
                  - codebuild:CreateReportGroup
                  - codebuild:CreateReport
                  - codebuild:UpdateReport
                  - codebuild:BatchPutTestCases
                  - codebuild:BatchPutCodeCoverages

  ### CodePipeline Role 생성
  CodepipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      RoleName: !Sub ${Env}-codepipeline-service-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codepipeline.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: !Sub ${Env}-codepipeline-base-policy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Resource:
                  - "*"
                Effect: Allow
                Action: 
                  - codedeploy:CreateDeployment
                  - codedeploy:GetApplicationRevision
                  - codedeploy:GetDeployment
                  - codedeploy:GetDeploymentConfig
                  - codedeploy:RegisterApplicationRevision
              - Resource:
                  - "*"
                Effect: Allow
                Action:
                  - codestar-connections:UseConnection  
              - Resource:
                  - "*"
                Effect: Allow 
                Action: 
                  - s3:*
              - Resource:
                  - "*"
                Effect: Allow 
                Action:
                  - codebuild:BatchGetBuilds
                  - codebuild:StartBuild
              - Resource: "*"
                Effect: Allow
                Action:
                  - servicecatalog:ListProvisioningArtifacts
                  - servicecatalog:CreateProvisioningArtifacts
                  - servicecatalog:DescribeProvisioningArtifacts
                  - servicecatalog:DeleteProvisioningArtifacts
                  - servicecatalog:UpdateProduct

  # ------------------------------------------------------------
  # log-group && report-group 생성
  # ------------------------------------------------------------

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/codebuild/${Env}-codebuild

  ReportGroup:
    Type: AWS::CodeBuild::ReportGroup
    Properties:
      Name: !Sub ${Env}-report-group
      Type: TEST
      ExportConfig:
        ExportConfigType: NO_EXPORT

 

  •  CodePipeline 아티팩트용 S3 Bucket을 생성합니다.
  •  Codepipleline과 CodeBuild에는 필요한 IAM role을 생성합니다.
  •  CodeBuild를 통해 소스 코드 빌드 시 에러 로그를 확인할 수 있도록 로그 그룹을 생성합니다.

 


# AWS CLI로 CloudFormation 스택 생성

 

# 스택생성
$ ENV=dev
$ aws cloudformation create-stack \
  --stack-name "$ENV-stack" \ 
  --template-body file://codepipeline.yml \
  --parameters file://codepipeline.json \
  --capabilities CAPABILITY_NAMED_IAM

 

  • CloudFormation 스택 생성을 위한 AWS CLI는 위 내용과 같이 command를 실행합니다.
  • --stack-name에는 생성되는 스택명, --template-body에는 cloudformation template명 , --parameters에는 파라미터의 json을 지정합니다.
  • --capabilities의 경우 IAM role생성 시 필수로 적용해야 하는 옵션입니다.

 


# CodePipeline 실행 테스트

 

Codepipeline 실행 성공 여부는 Management console의 Codepipeline의  Pipelines에서 확인합니다.

 

 

  •  Git 리포지토리에 있는 소드 코드가 문제없이 성공적으로 업데이트된 화면입니다.

 

 

  •  CodeBuild를 실행된 화면입니다.

 

 

  •  빌드된 소스 코드가 S3 bucket에  성공적으로 배포된 화면입니다.

 


# AWS CLI로 CloudFormation 스택 삭제

 

# 스택삭제
$ ENV=dev
$ aws cloudformation delete-stack --stack-name "$ENV-stack"

 

  • CloudFormation 스택 삭제를 위한 AWS CLI는 상기 command로 삭제합니다.

# 요약

 

  • CodePipeline을 활용하면 CI/CD 파이프라인을 쉽게 구축하는 것이 가능합니다.
  • CodePipeline을 사용하면 소스 코드가 업데이트될 때마다 자동으로 빌드하고 배포시킬 수 있게 됩니다.
  • CloudFormation을 활용하면 빠르게 AWS Service를 구축할 수 있어 유용합니다.

 

#  참고 공식문서

 

  • S3 Bucket 생성

https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/create-bucket-overview.html

 

버킷 생성 - Amazon Simple Storage Service

객체 잠금을 사용하는 버킷을 생성하려면 s3:CreateBucket, s3:PutBucketVersioning 및 s3:PutBucketObjectLockConfiguration 권한이 있어야 합니다.

docs.aws.amazon.com

 

  • GitHub 연동 콘솔활용

https://docs.aws.amazon.com/ko_kr/codepipeline/latest/userguide/connections-github.html

 

GitHub 연결 - AWS CodePipeline

AWS CLI 또는 AWS CloudFormation을 통해 생성된 연결은 기본적으로 PENDING 상태입니다. CLI 또는 AWS CloudFormation을 사용하여 연결을 생성한 후 콘솔을 통해 연결을 편집하여 상태를 AVAILABLE로 설정합니다.

docs.aws.amazon.com

 

  • CodePipeline CodestarConnetion 참고

https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html

 

CodeStarSourceConnection for Bitbucket Cloud, GitHub, GitHub Enterprise Server, GitLab.com, and GitLab self-managed actions - AW

This feature is not available in the Asia Pacific (Hong Kong), Asia Pacific (Hyderabad), Asia Pacific (Jakarta), Asia Pacific (Melbourne), Asia Pacific (Osaka), Africa (Cape Town), Middle East (Bahrain), Middle East (UAE), Europe (Spain), Europe (Zurich),

docs.aws.amazon.com

 

반응형