github actions로 Docker를 이용해 Next.js CI/CD 구현하기
github actions로 Docker를 이용해 Next.js CI/CD 구현하기
Next.js를 사용하여 프로젝트를 구성한 후, 배포를 할 단계가 찾아왔습니다.
Vercel을 이용하여 쉽게 배포할 수 있는 방법도 있겠지만, 이번 기회에 기존에 만들어 두었던 Oracle cloud를 활용하여 CI/CD에 도전해보게 되었습니다.
CI/CD?
우선 CI/CD에 대해서 간단하게 알아보자면, Redhat 에서는 다음과 같이 설명하고 있습니다.
CI/CD는 지속적 통합(Continuous Integration) 및 지속적 제공/배포(Continuous Delivery/Deployment)를 의미하며, 소프트웨어 개발 라이프사이클을 간소화하고 가속화하는 것을 목표로 합니다.
해당 설명에 의하면 다음과 같은 일련의 과정을 CI/CD라 할 수 있습니다.
지속적 통합 (Continuous Integration, CI): 여러 개발자가 동시에 개발하는 경우, 코드의 충돌이나 오류를 방지하기 위해 개발자가 코드를 중앙 저장소에 자주 통합하는 작업을 의미하며, 새 코드를 주기적으로 가져와 자동으로 빌드하고 테스트합니다. 만약 문제가 발견되면 팀에 알림을 보내고 문제를 해결할 수 있도록 합니다.지속적 배포 또는 지속적 제공 (Continuous Deployment/Delivery, CD): 지속적 배포는 새로운 코드 변경 사항을 자동으로 프로덕션 환경에 배포하는 것을 의미합니다.
여기서 저는 새로운 커밋이 레포지토리에 등록될 때마다 클라우드에 접근하여 코드를 반영하고, 빌드하여 배포하는 과정을 진행해보도록 하겠습니다.
Docker를 이용한 Next.js 빌드
Next.js를 배포하고자 할 때, 공식 문서에서 필요한 설정을 제공하고 있습니다.
해당 파일을 참고하여 .dockerignore와 Dockerfile을 작성해주었습니다.
참고로 Docker로 빌드할 때 이미지 용량을 줄이기 위해서는 기존 Next.js output 설정을 standalone으로 변경해주어야 합니다.
/** @type {import('next').NextConfig} */
module.exports = {
output: 'standalone',
}또한 현재 제가 운영중인 Oracle Cloud의 구조는 다음과 같습니다.

Nginx를 Docker에서 돌리고 있으며, 기존에 다른 프로젝트를 운영중이기 때문에 새롭게 배포할 Next.js 프로젝트도 해당 Nginx와 연결시켜주어야 했습니다.
따라서, docker-compose 파일을 작성하여 같은 network 설정을 통해 Nginx와 연결시켜주도록 하였습니다.
services:
noveloper:
container_name: noveloper
image: noveloper
ports:
- '4000:4000'
networks:
- nginx-network
networks:
nginx-network:
external: true이제, github actions 설정을 통해 커밋을 감지하고 새로운 코드로 빌드하는 워크플로우를 추가하면 됩니다.
Github actions 설정
github actions를 추가할 레포지토리의 actions 탭에서 새로운 워크플로우를 추가해봅시다.
name: deploy
on:
push:
branches: ['main'] # main 브랜치에 새로운 커밋이 푸시되면 실행합니다.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- name: execute remote ssh # 클라우드 인스턴스에 ssh로 접근합니다.
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_SSH_HOST }}
username: ${{ secrets.REMOTE_SSH_USERNAME }}
key: ${{ secrets.REMOTE_SSH_KEY }}
port: ${{ secrets.REMOTE_SSH_PORT }}
script: |
cd noveloper
git pull origin main
docker build -t noveloper .
docker compose down
docker compose up -d
docker rmi $(docker images -f "dangling=true" -q)main 브랜치에 새로운 커밋이 푸시되면 클라우드 인스턴스에 ssh로 접근하도록 구성하였고
정상적으로 ssh에 접속할 수 있도록 필요한 host,username,key,port를 환경변수로 등록해주었습니다.
접속한 후에는 script를 통하여, 다음과 같은 과정을 실행하도록 구성하였습니다.
cd noveloper: 프로젝트 폴더로 이동git pull origin main: 새로운 커밋 pulldocker build -t noveloper .: 프로젝트명의 docker 이미지 빌드docker compose up -d: 기존에 작성한 docker-compose.yml에 구성된 내용으로 docker 컨테이너 실행docker rmi $(docker images -f "dangling=true" -q): 오래된 이미지 삭제
결과
이제 새로운 커밋이 등록되면 다음과 같이 등록한 actions가 실행되게 됩니다.

현재 제 프로젝트에서는 평균 약 3분 정도 시간이 소요됩니다.
결론
미리 구성해둔 Nginx를 활용하여 Docker 컨테이너에 올린 Next.js를 쉽게 배포할 수 있었습니다.
또한, 매번 프로젝트를 배포할 때마다 vercel에 의존하였는데, 이렇게 클라우드를 활용하여 직접 배포를 진행해보니 새롭게 알게되는 것들이 많았습니다.
지금 구성한 과정 중에서 틀린 부분이 있을 수 있지만, 추후에도 계속해서 보완해나가도록 노력해보겠습니다.