Docker + Nextjs 14.0.4 빌드 배포 이미지 사이즈 최적화와 개발 환경 적용기

2024. 1. 4. 16:45docker

새롭게 프로젝트 시작하기 전에 가볍게 Nextjs 14.0.4 환경에서 빌드한 파일을 용량 최적화와 함께 Docker로 한번 배포해보자

 

사실 vercel 에서 제공하는 Dockerfile 과 docker-compose 를 거의 복사 붙여넣기에 가까운 글이니 

https://github.com/vercel/next.js/tree/canary/examples/with-docker-compose

 

직접가서 뜯어보시며 보는것도 나쁘지 않다고 생각함

 

시작은 craete-next-app 아무것도 안건들꺼다

 

프로젝트 최상단 경로에 Dockerfile 생성

FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN npm ci

FROM base AS dev

WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .



# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1

RUN npm run build

# If using npm comment out above and use below instead
# RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs


CMD ["node", "server.js"]

짧게 설명하면 node 18 alpine 환경에

 

npm을 사용했고

 

개발환경 dev

 

프로젝트 빌드에 builder

 

빌드 프로젝트 실행에 runner 를 사용했다.

 

다음은 compose

services:
  frontend-prod:
    container_name: frontend-prod
    build: .
    restart: always #change if you don't want your container restarting
    environment:
      - NODE_ENV=production
    ports:
      - 3000:3000
  frontend-dev:
    container_name: frontend-dev
    build:
      context: . #if your Dockerfile is not at the same level change the path here (./frontend)
      target: dev
    restart: always
    command: npm run dev
    environment:
      - NODE_ENV=development
    volumes:
      - .:/app
      - /app/node_modules
      - /app/.next
    ports:
      - 3000:3000

근데 어쩌다보니 적용하긴 했지만 개발환경까지 굳이 도커위에 올려줘야하나 싶긴 했다.

 

( 개발환경이랑 배포환경 두개 동시에 켤 일이 있나 싶어서 ports 는 같게 해줬는데 불편하면 package.json 가서 포트 변경 하자 )

 

대충 요약해서 설명하면 frontend-dev 는 파일 통째로 싹 복사해서 docker에 올려버리는거

frontend-prod 는 nextjs 로 빌드한 폴더만 가지고 최적화 시켜서 올려버리는거

 

뭐 프로젝트 커지면 Dockerfile 이랑 Docker-compose 도 다 따로 만드는 것 같은데 ( vercel 에서 제공하는 예시코드 보면 그렇게 되어있더라 ) 그건 프로젝트 커지면 그때 바꿔도 늦지 않을듯..?

 

올려놓고 보면 용량차이가 꽤 심하다.

 

파일두개 만들었으면 실행시켜보자

docker compose -f docker-compose.prod.yml up frontend-prod

docker compose -f docker-compose.prod.yml up frontend-dev

 

 

용량 차이보소..
컨테이너

다 만들어졌으면 localhost:3000 에 프로젝트가 뜬다.

 

그런데 배포버전이야 빌드해서 한번 올려놓으면 되지만

 

저 환경에서 개발을 하려면 react 의 hot reload 기능이 있어야 하지 않겠음?

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "standalone",
  webpackDevMiddleware: (config) => {
    config.watchOptions = {
      poll: 1000,
      aggregateTimeout: 300,
    };
    return config;
  },
};

module.exports = nextConfig;

이렇게 해주면 잘됨.

 

output standalone 은 최적화랑 관련있는데 배포할때 필요없는 코드 지워줌

 

참고

https://jameschambers.co.uk/nextjs-hot-reload-docker-development

https://dev.gmarket.com/72

https://tech.inflab.com/20230918-rallit-standalone/

https://github.com/vercel/next.js/tree/canary/examples/with-docker-compose

'docker' 카테고리의 다른 글

Docker 기본 개념  (1) 2024.01.04