[AWS] NestJS 프로젝트를 Code Pipeline을 사용해서 Elastic Beanstalk으로 배포하는 법
Elastic Beanstalk을 사용하면 빌드한 JS 코드를 업로드해서 간단하게 배포할 수 있습니다.
하지만 매번 빌드해서 올리는 것은 비효율적이고 귀찮습니다. 매번 push할 때마다 알아서 빌드하고 올려준다면 어떨까요?
이런식으로 GitHub의 코드로 자동 배포하는 것은 여러가지 방법으로 가능합니다.
- GitHub Actions로도 여러 방법으로 할 수 있습니다.
- 푸쉬할 때 마다 GitHub Actions를 통해 빌드하고 그 파일을 업로드해서 배포를 할 수 있습니다.
- 푸쉬할 때 마다 Actions 상에서 소스코드를 그냥 S3에 업로드하고 빌드해주는 애(Code build)에게 빌드를 맡기고 배포까지 하는 방법이 있습니다.
- Code Pipeline을 통해 할 수 있습니다.
- 배포는 어떤 서비스로 어떤 방식으로 하냐에 따라 이것도 방법이 여러가지가 존재합니다.
이번에는 Code Pipeline와 Elastic Beanstalk을 사용해서 GitHub 저장소에 새로운 커밋을 push할 때마다 배포해주는 것 구현해보도록 하겠습니다.
준비물
- AWS 계정
- 컴파일 가능한 NestJS 앱이 있는 GitHub Repository
0. Region이 서울인지 확인합니다.
1. CodePipeline에 접속합니다.
2. Setting > Connections에 들어와서 Create connection을 누릅니다.
먼저 AWS Code pipeline이 제가 GitHub의 특정 저장소에 Commit할 때마다 Trigger될 수 있도록 GitHub connection을 만들어줘야 합니다.
3. GitHub Connection을 만들어줍니다.
원하는 connection 이름을 정합니다.
Install a new app을 눌러서 내 GitHub계정에 AWS Connection app을 설치합니다.
우리가 배포할 NestJS 저장소가 위치해 있는 개인 계정 혹은 Organization을 선택합니다.
배포하고 싶은 저장소를 선택합니다.
추가해준 것을 선택합니다.
Connect를 누릅니다.
이제 이 Connection을 통해서 내 Repository에 Commit이 Push될 때마다 파이프라이인을 실행할 수 있습니다.
4. Create pipeline을 누릅니다.
이제 왼쪽 메뉴의 Pipelines > Piplines를 클릭합니다.
주황색 Create pipeline 버튼을 누릅니다.
5. Pipeline의 이름과 사용할 Service Role을 정합니다.
저는 미리 생성해둔 Role이 없어서 자동 생성하도록하겠습니다.
Next를 누릅니다.
6. 배포할 GitHub 저장소를 설정합니다.
Source provider를 GitHub (Version 2)로 설정하면 Connection을 설정할 수 있습니다.
이때 connection 입력 창을 누르면 우리가 처음에 생성했던 Connection이 나와야 합니다. 안 나온다면 다시 우측에 Connect to GitHub을 누르고 다시 생성하고 돌아옵니다.
저장소를 선택합니다.
만약 한 Organization이나 여러 저장소를 선택한 경우 아래와 같이 여러 저장소가 추천으로 뜹니다.
우리가 배포되길 원하는 저장소 하나를 선택해줍니다.
계속적으로 배포가 될 브랜치를 설정합니다. 보통 main(master)이나 prod 브랜치가 될 것입니다.
저는 commit이 될 때마다 Pipeline이 실행되길 원해서 아래의 옵션을 체크했습니다.
그리고 Artifact는 모든 메타데이터를 원하지 않기 때문에 Default 그대로 뒀습니다.
Next를 누릅니다.
7. Code Build 단계는 Skip합니다.
저는 복잡한 빌드 작업이 필요없었기 때문에 Skip build stage 했습니다.
하지만 분명 필요하신 분이 있을 것 같아서 부연 설명을 해보겠습니다.
Jenkins를 쓴다면 이 build stage를 설정하셔서 빌드된 파일을 거기서 가져오셔도 됩니다.
만약 복잡하거나 무거운 Build 작업을 해야하거나 (ex. 두개의 프로젝트를 빌드해서 합친다) 이 단계에서 빌드 파일에 다른 파일을 불러와서 주입해야 한다면 따로 여기서 Code Build를 만드셔서 구성하셔도 됩니다.
Code Build는 Buildspec 파일을 만드셔서 GitHub Actions과 비슷한 느낌으로 구축할 수 있습니다.
Code Build를 Code Pipeline에서 설정하시면 빌드할 파일은 S3에서 다운 받고 빌드한 파일을 또 S3에 zip파일 형태로 업로드하게 됩니다.
Buildspec은 대충 이렇게 만들면 됩니다. (참고용으로 드립니다.)
node project의 경우
version: 0.2
phases:
install:
runtime-versions:
nodejs: 16
commands:
- echo Install yarn
- "npm install yarn -g"
pre_build:
commands:
- echo Delete .env
- rm -rf .env
build:
commands:
- echo Start build
- yarn ci && yarn build
post_build:
commands:
- echo Create Profile
- echo $Procfile > $CODEBUILD_SRC_DIR/Procfile
artifacts:
files:
- 'node_modules/**/*'
- 'dist/**/*'
- 'Procfile'
- 'package.json'
create-react-app의 경우
version: 0.2
phases:
install:
runtime-versions:
nodejs: 16
commands:
- "npm install yarn -g"
build:
commands:
- echo start build
- yarn install && yarn build
post_build:
commands:
- echo list output
- ls -al
artifacts:
files:
- '**/*'
base-directory: 'build'
Code Build의 실행 단계는 phase로 나누어져 있습니다.
저는 .env를 지우고 (있으면 안 되지만) 환경변수를 쓰도록 했고 yarn install 후 yarn build를 했습니다. 그리고 그러면 build한 파일이 dist폴더에 있기 때문에 artifacts를 dist내의 **/*파일들로 설정해서 모두 빌드 결과물로 S3 버킷에 zip로 저장될 수 있게 했습니다.
이것 말고도 언어 런타임을 특정 version으로 설정할 수도 있고 다른 곳에서 파일 받아올 수도 있고 정말 할 수 있는 것들이 많습니다.
(주의) Code Build를 설정할 때 VPC를 사용하시는 것을 체크하면 VPC의 정책이나 Security Group 때문에 S3로부터 Input Source를 다운받지 못할 가능성이 있습니다.
자세한 것은 여기 Tutorial을 보면서 학습해보세요. :)
https://docs.aws.amazon.com/codebuild/latest/userguide/getting-started.html
아무튼 저는 따로 Code Build Stage를 둘만큼 부담되는 빌드를 할 것이 아니기에 Code Build는 스킵했습니다.
8. 배포할 서비스를 선택합니다.
Code Pipeline은 제 저장소에 뭔가가 푸쉬될 때마다 저장소를 다운을 받아서 넘겨주게 됩니다. 그러면 넘겨 받은 파일을 어떻게 배포할 것이냐는 무수히 많은 선택지들이 있습니다.
저는 가장 무난하게 사용하기 쉬운 PaaS 서비스인 AWS Elastic Beanstalk으로 배포를 진행해보겠습니다.
생성은 간단하지만 로드밸런서 붙여서 오토스케일링도 걸어주고 알아서 다 해줍니다.
9. Elastic Beanstalk을 생성하고 선택합니다.
만약에 Elastic Beanstalk이 없다면 먼저 비어있는 Elastic Beanstalk을 생성을 합니다.
잠시 새로운 탭으로 Elastic Beanstalk 창을 엽니다.
여기서 Create a new environment를 클릭합니다.
Environment Tier를 설정해줍니다.
저는 NestJS를 쓸 것이기 때문에 Web service를 선택했습니다.
이름을 정해줍시다. 도메인도 어느정도 제한적이지만 원하는 대로 붙일 수 있습니다.
플랫폼의 종류와 버전을 정합니다. 저는 nodejs 16버전으로 설정했습니다.
그리고 마지막으로 Application의 소스코드를 업로드해서 배포할 수 있는데 우리는 어차피 Code Pipeline이 주는 것을 받아서 쓸 것이기 때문에 그냥 Sample application으로 설정합니다.
이제 생성하고 기다립니다!
이게 시간이 좀 걸립니다. 생성이 완료될 때까지 기다려줍니다.
생성이 되시면 해당 Elastic Beanstalk의 Configuration에 들어가면 AutoScaling, health 체크, 환경변수 등 여러가지 설정을 해줄 수 있습니다.
먼저 환경 변수부터 설정해줍시다.
Software Category에 있는 Edit을 누르고 제일 아래로 스크롤을 내리면 환경 변수를 설정하는 곳이 나옵니다.
여기에서 내 NestJS에 필요한 환경변수를 설정하고 Apply를 눌러줍시다.
저는 일단 PORT를 3333으로 설정했습니다.
그렇기 때문에 health check나 외부에서 온 request도 80이 아닌 3333번 포트로 설정해줘야 합니다.
내 외부에서 온 트래픽을 Health 체크도 해주며 실질적인 Nest app에게 전달해주는 것은 로드밸런서입니다.
이걸 내 프로젝트에 맞게 설정하기 위해 다시 configuration 창으로 가서 Load Balancer의 Edit을 눌러줍니다.
그리고 Processes를 보면 기본적으로 80으로 요청을 보내도록 되어 있을 겁니다. 저는 80이 아니라 방금 환경 변수로 3333 포트에 서버를 열도록 했기 때문에 3333으로 수정했습니다.
추가적으로 만약 도메인을 가지고 있으면 Listener에 HTTPS를 추가해서 인증서를 붙여서 사용할 수도 있습니다.
말고도 Configuration을 둘러보면서 세부적인 옵션을 조정합니다. 조정이 끝났다면 다시 Code pipeline을 설정하고 있던 창으로 넘어갑니다.
10. 다시 pipline에 돌아와서 Elastic Beanstalk과 environment를 설정합니다.
다시 Code pipeline 생성을 하고 있던 창으로 돌아와서 방금 생성한 Elastic Beanstalk으로 Application과 Environment name을 설정해줍니다.
Next를 눌러줍니다.
11. 최종적으로 검토하고 Create pipeline을 클릭합니다.
12. Elastic Beanstalk을 위한 Procfile을 만들어줍니다.
마지막 관문이 남았습니다. 바로 Elasic Beanstalk이 프로젝트를 잘 빌드하고 실행하게 하는 것입니다.
NestJS의 기본 빌드 디렉터리인 dist를 보면 특이하게 빌드 파일의 진입점이 main.js입니다. 이것을 node가 실행하도록해야 합니다.
먼저 package.json파일에 deploy 스크립트를 추가합니다.
{
"name": "nest-project",
"version": "0.0.1",
// ...
"scripts": {
// ...생략
// 아래의 deploy 스크립트를 추가합니다.
"deploy": "npm ci && npm run build && npm run start:prod",
// ...생략
},
"dependencies": {
"@nestjs/common": "^8.0.0",
// ... 생략
이제부터는 npm run deploy 명령어만 실행하면 모든 dependency를 install 후 빌드를 하고 dist/main.js를 node로 실행해줍니다.
저희가 Procfile을 생성하지 않으면 아래와 같은 기본 명령어가 들어갑니다.
web: npm start
그렇기 때문에 우리 프로젝트의 root 디렉터리에 Profile을 생성해서 우리의 Profile 명령어 쓰도록 바꿔봅시다.
Profile을 생성하고 아래의 내용을 넣습니다.
web: npm run deploy
그리고 이 모든 변경 사항을 Push를 한다면 성공할 것입니다!
만약에 Code Build나 별도의 빌드를 걸치 후 실행 파일만 주어진 상태였다면 저 처럼 저렇게 빌드 후 배포하는 스크립트를 사용하지 않고 Procfiles을 만들어서 빌드된 파일을 알맞게 실행하게만 설정하면 됩니다.
끝
끝입니닷!!
다들 쾌적한 환경에서 즐코하세욥ㅎㅎ
썸네일 출처: Cloud server icons created by flatart_icons - Flaticon
댓글
이 글 공유하기
다른 글
-
[AWS] S3를 통해 정적인 Asset 호스팅하기
[AWS] S3를 통해 정적인 Asset 호스팅하기
2022.08.22 -
[AWS] VPC에 Subnet, NAT Gateway, Internet Gateway를 구성해보자
[AWS] VPC에 Subnet, NAT Gateway, Internet Gateway를 구성해보자
2022.08.07 -
수평적 확장(Scale-Out)과 수직적 확장(Scale-Up)
수평적 확장(Scale-Out)과 수직적 확장(Scale-Up)
2022.07.18 -
[AWS] Certificate Manager에서 발급 받은 인증서 로드밸런서에 붙이기
[AWS] Certificate Manager에서 발급 받은 인증서 로드밸런서에 붙이기
2022.07.09