DevOps/AWS

[CodeDeploy] NestJS 애플리케이션 AWS에 배포하기 07

kyoulho 2023. 3. 31. 16:41

인프라 구성도

이전 시간까지 GithubActions을 통해 코드를 빌드하였습니다. 이제 CodeDeploy로 오토스케일링 그룹에 배포하는 설정을 진행하겠습니다.

 

Dockerfile

NestJS 애플리케이션을 도커 이미지로 만들기 위한 도커파일입니다. 프로젝트 루트에 생성합니다.

FROM node:18

WORKDIR /app

COPY package*.json ./

RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["npm" ,"run","start:prod"]

 

nginx.conf

프록시로 사용될 nginx 설정 파일입니다. 프로젝트 루트에 /nginx 디렉토리에 생성합니다.

user nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" "$request_uri" "$uri"'
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile on;
    keepalive_timeout 65;

    upstream docker-nest {
        server localhost:3000;
    }

    server {
        listen 80;
        server_name <사용하는 도메인을 넣어주세요>;

        location ~ /.well-known/acme-challenge {
                allow all;
                root /usr/share/nginx/html;
                try_files $uri =404;
        }

        location / {
            proxy_pass http://docker-nest;
        }
    }
}

80번 포트로 들어오는 요청을 localhost:3000으로 라우팅 해줍니다.

 

docker-compose.yml

nginx와 NestJS 컨테이너를 띄우기 위한 파일입니다. 프로젝트 루트에 생성합니다.

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: proxy
    network_mode: "host"
    restart: "always"
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf

  dm2023-nest:
    build: .
    container_name: dm2023-nest
    restart: always
    ports:
      - '3000:3000'

위에서 생성한 nginx 설정 파일을 연결해 줍니다.

 

before-install.sh

CodeDeploy에서 배포를 진행하기 전에 실행하게 될 스크립트파일입니다. 프로젝트 루트에 /scripts 디렉토리에 생성합니다.

#!/bin/sh

sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

sudo apt-get install -y docker-ce
sudo usermod -aG docker "${USER}"

sudo curl -L "https://github.com/docker/compose/releases/download/v2.17.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

도커와 도커컴포즈를 설치해 줍니다. 유저그룹에 추가해 주는 건 나중에 인스턴스에 직접 접속할 때 귀찮을까 봐입니다...

 

after-install.sh

CodeDeploy에서 배포를 진행한 후에 실행하게 될 스크립트파일입니다. 프로젝트 루트에 /scripts 디렉토리에 생성합니다.

#!/bin/sh

cd /home/ubuntu/dm2023-nest || exit

sudo docker-compose up -d

EC2 인스턴스 내에 프로젝트 폴더로 이동하여 컨테이너들을 띄웁니다.

 

appspec.yml

CodeDeploy에서 사용되는 배포에 대한 설정 파일입니다.

version: 0.0
os: linux
files:
  - source: /
    # S3에서 가져온 파일을 저장할 위치
    destination: /home/ubuntu/dm2023-nest
    # 덮어쓰기 옵션
    overwrite: yes

# files에서 가져온 파일들에게 권한을 어떻게 적용해야하는지 지정하는 곳입니다.
permissions:
  - object: /
    pattern: '**'
    owner: ubuntu
    group: ubuntu

hooks:
  BeforeInstall:
    - location: scripts/before-install.sh
      timeout: 600
      runas: ubuntu
  AfterInstall:
    - location: scripts/after-install.sh
      timeout: 600
      runas: ubuntu

Install 전후로 이전에 생성한 스크립트를 실행합니다.

 

모두 완료되었다면 relase 브랜치에 merge 혹은 push를 해봅시다.

새로운 오토스케일링 그룹이 생성되고 시작템플릿을 이용하여 EC2 인스턴스가 생성됩니다.

이후에 배포가 진행되며 새로운 생성된 인스턴스에 상태 검사가 완료되면 이전에 있던 오토스케일링 그룹을 사라지게 됩니다.

이로써 길고 길었던 무중단 배포 과정이 마무리됩니다.