blog-imgDucklog

Next.js + Docker + Github Action + GCP를 활용한 CI/CD 자동화

Next.js + Docker + Github Action + GCP를 활용한 CI/CD 자동화

next.js 프로젝트를 배포하려면 기존에는 vercel을 이용해서 쉽게 배포할 수 있었지만, 개인이 아닌 단체로 사용하는 경우 요금이 엄청나기 때문에 만약, 사내에서 next 프로젝트를 배포하게 되면 돈이 낭비될 것이라고 생각했다.

그래서 vercel이 아니라 다른 방법으로 CI/CD를 구축하는 방법을 찾던 중, 이전부터 도커와 github action을 이용해서 배포해보고 싶다는 생각이 들어서 해봤다.

만약 next가 아닌 순수 react 프로젝트라면 Nginx를 이용해야했지만, next는 serverless이기 때문에 별도로 nginx를 사용하지 않아도 된다.

개인 사내 서버에 배포하기보단 테스트 겸 사이드 프로젝트에 사용하기 위해서는 외부(집)에서도 접근이 용이 해야하기 때문에, 개인 GCP (Google Cloud Platform)을 이용했다.

우선 docker을 사용하기 위해선, dockerfile을 만들어줘야한다.

FROM node:18 AS builder

# Set working directory
WORKDIR /app

# Copy package.json and yarn.lock for utilising Docker cache
COPY package.json yarn.lock ./

# Install dependencies
RUN yarn install --frozen-lockfile

# Copy the rest of your app's source code
COPY . .

# Build app
RUN yarn build

# ---- Run Stage ----
FROM node:18 AS runner

# Set working directory
WORKDIR /app

# Copy over the artifacts from the build stage
# COPY --from=builder /app ./
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
# Start app
CMD ["sh", "-c", "yarn start -p $PORT"]


node 18버전을 사용했고, 유동적으로 포트를 받기 위해서 위에처럼 변수로 받아서 실행할 수 있게 해줬다.

자세히 보면, COPY --from=builder /app/.next/standalone ./라는 명렁어가 있는데,

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
};

module.exports = nextConfig;

next.config 설정에서 standalone를 해줬기 때문이다. 해당 설정을 해주면 도커 파일이 작아져 배포하는 시간 줄어든다.

# .dockerignore

node_modules
.next
dockerfile
.dockerignore
.git
.gitignore
README.md

그리고 dockerignore를 이용해서 도커파일에 포함하지 않을 파일들을 입력해준다.


name: CI/CD workflow

on:
push:
branches: [main]

jobs:
build-and-deploy:
runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v2

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Google Container Registry
        uses: docker/login-action@v1
        with:
          registry: gcr.io
          username: _json_key
          password: ${{ secrets.GCR_JSON_KEY }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          tags: gcr.io/${{ secrets.GCR_ID }}/petmunity-fe:latest

      - name: Setup Google Cloud SDK
        uses: google-github-actions/setup-gcloud@v0.3.0
        with:
          project_id: ${{ secrets.GCR_ID }} # 여기에 Google Cloud 프로젝트 ID를 입력하세요.
          service_account_key: ${{ secrets.GCR_JSON_KEY }}
          export_default_credentials: true

      - name: Deploy to Google Cloud Run
        run: |
          gcloud run deploy petmunity-fe --image gcr.io/${{ secrets.GCR_ID }}/petmunity-fe:latest --region asia-northeast1 --platform managed --allow-unauthenticated


다음으로 github action을 사용하기위한 yml이다.

main 브랜치로 푸시되거나 머지되면 배포가 되야하기 때문에

push: branches: [main]를 입력해줬다.

Google Cloud를 이용했기 때문에 Google Cloud SDK를 추가해주는 부분도 입력해주었다.

해당 코드를 이용해서 main 브랜치로 올리게 되면 자동 배포가 가능하게 된다.

기존에는 vercel을 이용해서 배포만 했어서 너무 편했지만, 해당 실습을 하면서 도커와 github action이 어떤 식으로 작동하는 지 알게 되는 좋은 경험이었다.