Carryduo | CodeBuilder & CodePipeline(nestJS 프로젝트 빌드 후 배포하기)

유현준·2022년 11월 8일
1

추신

1. 개요: 프로젝트 초반 배포 시나리오와 그 문제점

1) 프로젝트 초반 배포 시나리오

  • 프로젝트 초기에, AWS codeDeploy와 AWS codePipeline을 활용하여 CD를 구축했다. 즉, github과 AWS EC2를 연결하여 github의 특정 branch에 변경 사항이 생길 때, AWS에서 이를 포착하여 AWS에서 대여한 EC2에 자동으로 반영하도록 한 것이다.
  • 프로젝트 초기 단계를 기준으로 소스코드가 EC2에 배포되는 시나리오는 다음과 같다.

    1) aws codePipieline에 등록한 branch에 pull request
    2) branch에 변경된 소스코드 내용들이 codePipeline을 통해 출력 아티팩트로 지정된 AWS S3 bucket에 저장
    (pipeline 생성 시, 출력 아티팩트를 기본값으로 저장해둔 경우, SourceArtifact라는 이름으로 s3 버킷 내 폴더 생성)
    3) CodeDeploy에서 S3 Bucket의 소스코드를 AWS EC2로 배포
    4) AWS EC2에서 배포받은 소스코드를 빌드(typescript -> javascript)
    5) afterinstall hook을 통해 배포 환경에서 서버 자동 재실행

2) 문제점

  • 프로젝트는 nestJS 프레임워크를 기반으로 작성되었다. 즉, typescript를 기반으로 작성된 프로젝트이기 때문에, 실행을 위해서는 컴파일(빌드)를 사전에 해주어야만 한다. 구체적으로, typescript를 javascript로 컴파일하는 작업이 런타임 사전에 필요한 것이다.
  • 프로젝트 초반 배포 시나리오에는 이 빌드 작업이 런타임 환경에서 실행되었다.
  • 프로젝트 규모가 매우 작았을 때에는 런타임을 실행하는 데 문제가 없었지만, 프로젝트 규모가 점진적으로 커지면서, 빌드 과정에서 CPU 사용률이 100%에 근사하게 되고, 이에 따라 서버가 터지는 문제가 발생했다.

    런타임 목적으로 사용하고 있는 EC2가 t3 micro로 좋은 성능이 아닌 것도 문제 원인이라 할 수 있지만, 애당초, 런타임 환경에서 런타임이 아니라 컴파일부터 하려고 한 것 자체가 원인이라고 판단했다. 요컨대, 런타임 환경에는 런타임에 필요한 요소들만 배포되어야 한다.

  • 이에, 나는 EC2에 배포하기 이전에, 소스코드를 빌드하는 작업을 추가하였다.
  • 요컨대, 배포 시나리오를 다음과 같이 수정하도록 의사결정한 것이다.

    1) aws codePipieline에 등록한 branch에 pull request
    2) branch에 변경된 소스코드 내용들이 codePipeline을 통해 출력 아티팩트로 지정된 AWS S3 bucket에 저장
    (pipeline 생성 시, 출력 아티팩트를 기본값으로 저장해둔 경우, SourceArtifact라는 이름으로 s3 버킷 내 폴더 생성)
    3) 소스코드를 빌드(typescript -> javascript)
    4) 빌드한 소스코드를 AWS EC2에 배포
    5) afterinstall hook을 통해 배포 환경에서 서버 자동 재실행

  • 아래는 3) 소스코드를 빌드 를 어떻게 진행했는지에 대한 내용이다.

2. CodeBuilder 생성 및 CodePipeline에 추가

  • 위에 서술한 내용을 보면 어렴풋이 유추할 수 있겠지만, 기존 CodePipeline의 스테이지는 Source와 Deploy 두 단계만 있었다.
  • 런타임 환경에 배포하기 전에 소스코드 빌드를 위해 필자는 AWS CodeBuilder를 기존 CodePipeline의 스테이지에 추가해주는 방식을 이용했다.
  • Codebuilder를 생성하고 이를 CodePipeline에 추가하는 과정은 다음과 같다.

1) CodeBuilder 생성

  • codebuilder 생성 과정은 다음과 같다.

1. 프로젝트 이름 작성

2. codebuilder에서 컴파일을 실행할 소스코드를 제공할 경로를 지정

  • 필자의 프로젝트에서는 이미 codePipeline에서 source가 아마존 S3에 아티팩트로 저장되어 있었다.
  • 그래서 bucket은 해당 codepipeline의 버킷, 객체 폴더 또한 source가 저장된 객체 폴더를 지정해주었다.

3. build 환경 설정

  • 소스코드 컴파일의 기준이 되는 환경을 설정하는 것이다.
  • 런타임 환경에서 node.js 버전을 16 버전 이상으로 사용하는 경우, 런타임 이미지를 6.0 이상으로 하는 것을 권장한다.
    (런타임 이미지를 4.0 버전으로 설정하고 buildspec에서 node 버전을 16으로 하였더니, 빌드 과정에서 node 버전에 대한 에러를 목격했다.)

4. build 시 사용할 명령 지정

  • 일반적으로 프로젝트 소스코드 루트경로에 buildspec.yml 파일을 생성하여, codebuilder가 해당 파일을 바라보게 하는 방식으로 명령을 지정한다.
  • buildspec.yml은 다음과 같이 작성할 수 있다.
version: 버전 작성

아래는 빌드가 실행될 환경 및 명령어를 작성해준다.
phases:
  install:
    runtime-versions:
      nodejs: 16
    commands:
      - npm install
  pre_build: // 빌드 사전 명령어
    commands:
      - echo Nothing to do in the pre_build phase...
  build: // 빌드 명령어
    commands:
      - echo Build started on `date`
      - npm run build (pacakage.json에 이미 작성된 빌드에 대한 명령어이다.)
  post_build: // 밀드 이름 명령어
    commands:
      - echo Build completed on `date`

아래는 빌드 출력물에 대한 설정이다.
artifacts:
  files:
    - '**/*'
  name: build-$(date +%Y-%m-%d)

5. 아티팩트 설정

  • 아티팩트 설정은 다음과 같이 하였다.
  • 지금와서 돌이켜보건데, codebuilder에서 아티팩트를 지정하지 않더라도, codePipeline 단에서 출력 아티팩트의 처리 여부를 설정해줘도 무방한 듯 싶다.

6. 로그 여부 설정

  • 빌드 실행 과정에 대한 로그를 어떤 루트를 통해 볼 지를 설정하는 것이다.

2) codePipeline에 생성한 codeBuilder를 스테이지로 추가

  • 순서는 다음과 같다.

1. 스테이지 및 작업 그룹 추가

  • 위 이미지처럼 build 스테이지 추가를 한다.
  • 이후, 생성한 build 스테이지에서 작업 그룹 추가를 선택한다.

2. build 스테이지 작업 내용 작성

  • 작업 공급자는 AWS CodeBuild를 선택한다.
  • 입력 아티팩트는 Source 스테이지에서 제공하는 아티팩트로 설정한다.
    | Source 스테이지를 확인하면, 별도의 아티팩트 이름을 설정하지 않았다면, ` SourceArtifact로 이름이 설정되어 있을 것이다.(파이프라인 생성 시 기본값으로 생성되는 아티팩트명이다)
    | 이는 S3의 해당 CodePipeline 버킷을 통해서도 확인할 수 있다.
  • 프로젝트 이름은 AWS CodeBuilder에서 생성해준 프로젝트를 선택한다.
  • 출력 아티팩트 이름은 사용자의 편의대로 지정하면 된다. 아티팩트는 build 출력 결과물이다.

3. deploy 스테이지 작업 내용 편집

  • 기존 codePipeline에서는 deploy에 주입되는 소스는 source 스테이지의 아티팩트였다. 이를 build의 아티팩트로 변경해주는 작업이 필요하다.
  • 위 사진에서 입력 아티팩트를 build 스테이지에서 source 아티팩트를 입력 아티팩트로 설정해준 것처럼, build 아티팩트를 입력 아티팩트로 설정해준다.

3. 결과

  • 위와 같은 작업 이후에 pipeline의 구성이 다음과 같이 변경된 것을 확인할 수 있다.

  • pipeline 결과물 또한 다음과 같이 변경되었다.
  1. 기존
    => 프로젝트 규모가 커짐에 따라, deploy에서 반영해야 할 변경사항이 많아짐에 따라, 런타임환경에서 build에 대한 부담이 커져, build가 종종 실패하곤 했다.
  2. codeBuilder
    => 런타임환경에서 시행하던 build를 런타임환경 배포 전에 실행하고, build된 결과물을 런타임환경에 배포하게 되었다.

4. 소감

  • nestJS를 사용하면서 처음 컴파일에 대한 개념을 경험했다.
  • 그래서 배포 시나리오에서 컴파일을 고려해야한다는 것을 전혀 몰라 정말 큰코 다쳤었는데, 덕분에 이렇게 AWS CodePipeline을 좀 더 알아가게 된 것 같다.
profile
차가운에스프레소의 개발블로그입니다. (22.03. ~ 22.12.)

0개의 댓글