Node.js+ Docker + github action CI/CD 파이프라인 구축

형준·2024년 5월 26일

EC2에 API 배포하는 이유

다양한 이유가 있겠지만 로컬에서 배포를 하기에는 무리가 있기 때문에 클라우드 서비스를 이용해서 API를 배포하겠습니다.

CI/CD 파이프라인을 구축하지 않고 배포하는 방법

  1. local에서 코드를 수정한 후 git push를 진행
  2. 내가 배포한 클라우드 서버에 putty등의 방법을 이용해 terminal로 원격 접속
  3. git pull을 한 후 노드 서버 띄우기

CI/CD 파이프라인을 구축하는 이유

직접 배포하는 과정을 코드를 수정할때마다 수행하기엔 번거롭고 서버를 재시작하는 과정에서 중단이 되므로 무중단 서비스를 제공할 수 없게 됩니다.

CI/CD란?

  • CI :코드의 변경 사항을 지속적으로 통합하고 빌드하며 테스트하는 것
  • CD : 소프트웨어를 지속적으로 배포하고 최종 사용자에게 제공하기 위해 필요한 단계들을 자동화하는 것

사용할 도구

  • Github Action
    • 깃허브에서 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화 할 수 있는 CI/CD 플랫폼입니다.
    • main 브랜치에 event(push, pull request 등 설정가능)가 일어나면 workflow를 통해 원하는 action들을 수행 가능(테스트, 빌드, 배포 등)
  • Docker
    • 컨테이너 기반의 가상화 플랫폼. 프로젝트를 패키지화해서 이미지를 만들고 해당 이미지를 가상 컨테이너에서 실행시킵니다.

로컬에서 도커 이미지 만들어서 테스트 해보기

  • 로컬에서 도커를 실행해보려면 도커를 설치해야합니다

Node 프로젝트에 Dockerfile과 .dockerignore파일 작성

//Dockerfile
FROM node:20.13.1

COPY package*.json ./

COPY . .

RUN npm install

CMD ["npm", "start"]

//.dockerignore
node_modules
  • 이미지 빌드하기
docker build -t umc-study .

  • 빌드하고 실행해보기
 docker run --rm -p 3001:3001 --name umc-study-container umc-study


  • 자꾸 이런게 떠서 root 디렉토리에 nodemon.json 추가해줬더니 안뜨는것 같습니다.
//nodemon.json
{
  "watch": ["srcs", "config"],
  "ext": "js,json",
  "ignore": ["node_modules", "dist"],
  "legacyWatch": true,
  "delay": 2500
}

github action을 통한 도커 이미지 빌드 자동화를 위한 스크립트 작성하기

  1. docker 이미지 빌드 후 docker hub에 push
  2. aws ec2에 도커 환경 구성하기
  3. docker hub에서 내가 빌드한 이미지 pull
  4. docker 이미지로 컨테이너 생성

Docker hub 회원가입 및 EC2 생성을 해줍니다.

EC2 원격접속해서 EC2에 도커 설치하기

sudo apt update
sudo apt install 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 update
sudo apt install docker-ce

.github/workflows 디렉토리에 ci.yml 파일을 만들어줍니다.

  • yml 파일 이름은 아무거나 상관없지만 .github/workflow는 이름을 다르게 하면 절대 안됩니다.
name: CI/CD

on:

  pull_request:
    types: [closed] # pull_request closed 됐을 경우

jobs:
  build:
    runs-on: ubuntu-20.04 # OS 환경
    if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev'
    # pull_request가 dev 브랜치에 merge 됐을 경우

    # node-version 과 같이 배열로 돼있으면, 해당 원소를 순회하면서 작업이 반복해서 실행된다.
    # 응용해서 runs-on에 여러 OS에서 돌릴 수도 있다.
    strategy:
      matrix:
        node-version: [20.x] 

    # uses 개념은 다른 사람이 작성한 내용을 실행하는 개념이다.
    # actions/checkout: GitHub의 마지막 커밋으로 Checkout 한다.
    # actions/setup-node: Node.js를 설치한다.
    # run 개념은 명령어를 실행한다. 셸 스크립트와 동일하다.
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      # npm ci는 npm install과 같은 기능을 수행한다.
      - run: npm ci
      # --if-present 옵션은 npm 스크립트가 존재할 때만 실행시키라는 의미이다.
      # 만약 build 스크립트가 없는 경우, 오류 없이 지나간다.
      - run: npm run build --if-present

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Docker build
        run: |
          docker build -t ${{ secrets.PROJECT_NAME }} .
          docker tag ${{ secrets.PROJECT_NAME }} ${{ secrets.DOCKER_HUB_REPO }}:${GITHUB_SHA::7}
          docker push ${{ secrets.DOCKER_HUB_REPO }}:${GITHUB_SHA::7}

      - name: Deploy
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.EC2_SERVER_HOST }}
          username: ubuntu
          key: ${{ secrets.PRIVATE_KEY }}
          envs: GITHUB_SHA
          script: |
            docker rmi $(docker images -q)
            docker pull ${{ secrets.DOCKER_HUB_REPO }}:${GITHUB_SHA::7}
            docker tag ${{ secrets.DOCKER_HUB_REPO }}:${GITHUB_SHA::7} ${{ secrets.PROJECT_NAME }}
            docker stop ${{ secrets.PROJECT_NAME }}
            docker rm ${{ secrets.PROJECT_NAME }}
            docker run -d --name ${{ secrets.PROJECT_NAME }} -p 3001:3001 ${{ secrets.PROJECT_NAME }}

secret.PROJECT_NAME처럼 환경변수를 사용하려면 github settings에 추가를 해줘야합니다.

secret.DOCER_HUB_REPO는 회원가입하신 도커 허브에서 레포를 하나 만들어주고 만들어진 레포 이름 적으면 됩니다.

secret.PRIVATE_KEY는 pem키에서 추출해서 넣으면 됩니다.

이제 작업중인 브랜치를 dev 브랜치에 pr을 생성해서 merge를하게 되면 작성한 script 파일 대로 작업을 수행하게 됩니다.

  • docker hub에 이미지 저장된 것을 확인하면 잘 저장되는 것을 확인할 수 있습니다.

이런식으로 성공하면 build가 완료했다고 나옵니다.

ec2에 접속해서 확인해보면 잘 동작중인것을 확인할 수 있습니다.

profile
백엔드 개발자가 되기 위한 경험을 기록하는 블로그입니다.

0개의 댓글