[Infra] Github-Actions + S3 + EC2 + CodeDeploy + pm2로 Next.js CICD 구축하기

Hoon·2023년 9월 19일
1

Infra

목록 보기
7/10
post-thumbnail

이전에 EC2 인스턴스pm2Next.js 배포하는법을 정리한적이 있었는데, 이번에는 Github-Actions, S3, CodeDeploy 를 이용해서 해당 pm2 로 배포한 NextJS 프로젝트의 CI/CD 를 구축해보려한다.

플로우는 아래와 같다.

    1. 타겟 브랜치에 push 혹은 merge 시에 Github-Actions 의해 Next.jsbuild압축하여 S3 에 업로드함
    1. CodeDeploy 가 미리 작성해둔 appspec.yml 파일의 설정에 맞춰 S3 에 있는 빌드파일을 EC2 로 가져옴
    1. 미리 작성해둔 deploy.sh 스크립트를 실행하여 pm2ecosystem.config.js 설정을 실행하여 프로젝트의 변경사항을 감지하고 배포함

S3 생성

AWS S3 에 들어가 빌드된 프로젝트를 올릴 버킷 을 생성해 준다.


IAM 역할 생성

다음으로는 AWS IAM 에 들어가 EC2 인스턴스 에 할당해줄 아래의 정책을 추가역할 을 생성해준다.

생성 후 EC2 -> 보안 -> IAM 역할수정에 들어가 앞에서 생성한 IAM 역할을 지정해준다.

추가로 Code Deploy 에 할당해줄 역할 도 생성해준다.


Code Deploy 생성

AWS Code Deploy 에 들어가 아래와 같이 애플리케이션 을 생성해준다.

이어서 배포 그룹 도 생성해준다. 서비스 역할 은 앞에서 생성한 Code Deploy 역할 을 선택해준다.

황경에는 타겟 EC2 인스턴스 를 선택해주고, Load Balancer 는 비활성화 해주도록한다.


Github 에 시크릿 키 등록

이제 Github-Actions 에서 AWS 에 접근해야하는데 이 때 Access KeySecret Access Key가 있어야 접근할 수 있으므로 다음과 같이 IAM 사용자 를 생성해준다.

이제 key 들을 발급받아 아래와 같이 repository secret key 에 등록해준다.
(여기서 AWS_REGION은 ap-northease-2, 아시아태평양 - 서울 이다.)


Code Deploy Agent 설치

아래의 명령어를 통해 EC2Codedeploy agent 를 설치해준다.

$ sudo apt update
$ sudo apt install ruby-full
$ sudo apt install wget

$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

$ chmod +x ./install
$ sudo ./install auto

아래의 명령어로 잘 설치되었고, 동작하는지 확인할 수 있다

$ sudo service codedeploy-agent status


Github-Actions

이제 Github-Actions 에 대한 스크립트를 .github/workflows/main.yml 에 작성한다.

# .github/workflows/main.yml
name: main

on: 
  push:
    branches:
      - main 
      
jobs: 
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Git Checkout # Git Checkout
        uses: actions/checkout@v3

      - name: Check Node v # 노드 버전 확인.
        run: node -v

      - name: Install Dependencies # 의존성 설치
        run: yarn install --frozen-lockfile

      - name: Build # 빌드
        run: yarn build
        
      - name: zip create # S3에 업로드할 zip 파일 생성
        run: zip -qq -r ./hoon-build.zip .
        shell: bash
        # -qq: quit 모드로 실행 (에러나 경고메세지만 출력하도록 함)
        # -r: 지정된 디렉토리를 재귀적으로 압축 (하위 디렉토리와 파일들 모두 압축)

      - name: Configure AWS credentials # AWS 인증 확인
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Upload to S3 # zip 파일을 S3에 업로드
        run: |
          aws s3 cp --region ap-northeast-2 ./hoon-build.zip s3://{{AWS S3 bucket명}}/hoon-build.zip

      - name: Code Deploy # S3에 올라간 zip 파일을 CodeDeploy로 가져옴
        run: aws deploy create-deployment
          --application-name {{CodeDeploy 어플리케이션 이름}}
          --deployment-config-name CodeDeployDefault.AllAtOnce # CodeDeploy에서 설정한 배포 설정
          --deployment-group-name {{CodeDeploy 배포 그룹 이름}}
          --s3-location bucket={{AWS S3 bucket명}},bundleType=zip # Code Deploy가 S3에서 프로젝트를 찾을 수 있도록 경로 지정. (bucket=버킷 이름/test-build.zip)

appspec.yml

appspec.yml 파일은 code-deploy 가 실행할 스크립트이다. S3 로 부터 프로젝트를 EC2 인스턴스 의 지정한 경로로 가져와 지정한 shell script 를 실행한다.

version: 0.0
os: linux # Ubuntu니까 linux로 설정.

files:
  - source: /
    destination: /home/ubuntu/deploy # EC2 인스턴스 안에 프로젝트를 저장할 경로.
    overwrite: yes
permissions: # EC2 인스턴스에 프로젝트를 저장하기 위한 권한 설정.
  - object: /home/ubuntu/deploy # EC2 인스턴스 안에 프로젝트를 저장할 경로.
    owner: ubuntu
    group: ubuntu
    mode: 755
hooks:
  AfterInstall: # 배포 완료 후 실행할 동작 설정.
    - location: ./deploy.sh # deploy.sh를 실행.
      timeout: 60 # 제한 시간 1000초 으로 설정. 1000초가 넘어가면 실패함.
      runas: ubuntu # ubuntu 권한으로 실행.

ecosystem.config.js

pm2 로 프로젝트를 실행할거기 때문에 pm2 의 설정을 작성할 ecosystem.config.js 를 아래와 같이 작성해준다.

module.exports = {
  apps: [
    {
      name: "hoon-server", // 앱의 이름
      script: "./node_modules/next/dist/bin/next", // Next.js 스크립트 경로
      args: "start", // Next.js 앱을 시작할 때 사용할 인수
      exec_mode: "cluster", // 실행 모드: cluster 또는 fork 중 선택
      instances: "2", // 클러스터 모드에서 실행할 인스턴스 수 (CPU 코어 수만큼)
      autorestart: true, // 프로세스 자동 재시작 활성화
      watch: true, // 파일 변경 감지 활성화 (개발 중에만 활용)
      max_memory_restart: "1G", // 1GB 이상 메모리 사용 시 재시작
      env: {
        NODE_ENV: "production", // Node.js 환경 설정
      },
    },
  ],
};

또한, 해당 설정을 실행하기 위해 package.jsonscript 를 추가해준다.

{
  ...
  "script": {
    ...
  	 "deploy": "pm2 start ecosystem.config.js --env production",
    ...
  }
}

deploy.sh

이제 마지막으로 appspec.yml 파일에 의해 실행될 deploy.sh 이다. 해당 경로로 이동해 위에서 작성한 ecosystem.config.js 를 실행하는 scriptyarn deploy 를 실행해준다.

REPOSITORY=/home/ubuntu/deploy

cd $REPOSITORY

yarn deploy

Try

이제 로컬에서 git 타겟 브랜치push 혹은 merge 시에 아래와 같은 화면을 확인할 수 있다.

아래와 같이 안녕하세요~! 를 추가한 부분이 자동으로 잘 반영된것을 볼 수 있다.

Trouble Shooting

이전에 해당 작업을 했을때 따로 정리를 안해둬서 오랜만에 AWS 관련 내용을 정리하면서 해볼려니까 이슈가 조금 있었다...

code-deploy 에 대한 에러로그는 아래의 명령어로 확인할 수 있다.

$ cat /var/log/aws/codedeploy-agent/codedeploy-agent.log

처음에 역할을 잘 못 지정해서 이슈가있었는데 aws 에 역할 변경 후 EC2 인스턴스 에서도 아래의 명령어를통해 reset 시켜주었다.

# AWS 자격증명 파일 삭제
$ sudo rm -rf /root/.aws/credentials

# codedeploy-agent 재시작
$ sudo service codedeploy-agent restart

아무래도 프리티어 버전EC2 인스턴스 를 사용하니까 디스크 공간 이 모잘라서 계속 에러가 났었다. 아래의 명령어를 통해 디스크 공간 을 확인하고 부족하면 EC2 의 EBS 공간 을 늘려주자.

# 디스크공간 확인
$ df -h

deploy.sh 스크립트를 실행하는 과정에서 pm2 command 를 찾지 못해 pm2 의 경로를 찾아 /usr/bin/pm2 /usr/local/bin/pm2심볼릭 링크 를 지정해주었다.

which pm2
sudo ln -s {which pm2} /usr/bin/pm2
sudo ln -s {which pm2} /usr/local/bin/pm2

profile
4년차 개발자 Hoon입니다

0개의 댓글