[배포 준비] next js docker로 실행해보기
docker file 구성
FROM node:18-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /usr/src/app
COPY package.json yarn.lock ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
RUN rm -rf ./.next/cache
FROM base AS builder
WORKDIR /usr/src/app
ENV NODE_ENV=production
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY . .
RUN \
if [ -f yarn.lock ]; then yarn run build; \
else echo "Lockfile not found." && exit 1; \
fi
RUN yarn cache clean
FROM base AS runner
WORKDIR /usr/src/app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /usr/src/app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
COPY --from=builder --chown=nextjs:nodejs /usr/src/app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /usr/src/app/.next/static ./.next/static
USER nextjs
EXPOSE 80
ENV PORT 80
CMD ["node", "server.js"]
Dockerfile은 4가지 스테이지로 구성되어있다.
base image, dependency 설치, 빌드, 런타임
멀티 스테이지 빌드방식
이렇게 스테이지별로 나눠놓는 방식을 멀티 스테이지 빌드 방식이라고 한다.
필요한 결과물들만 COPY해서 가져오는 방식이기 때문에
도커의 이미지 용량을 최소화 할 수 있다.
Base image
이미지를 위한 기초와 구성을 제공한다.
alpine은 NodeJS를 포함하고 있는 작지만 파워풀한 이미지다
alpine Linux는 대부분의 베이스 이미지들보다 5MB정도 작다고 한다 (https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine)
Dependency Installation
alpine이 너무 작기 때문에 우리가 사용해야할 NodeJS 패키지들이 필요한 몇가지 라이브러리들을 제공한다.
alpine은 glibc와 그 친구들 대신 musl libc라는걸 쓰는데 이건 조금 이슈가 될 수 있다고 한다.
alpine을 쓰는데있어서 좀 논란이 될 수 있는 공통된 이슈중 하나는 process.dlopen이라는 라이브러리를 쓰는 것인데
그걸 해결하기 위해 필요한 것이 libc6-compat를 추가하는 것이라고 한다.
RUN apk add --no-cache libc6-compat
워킹 디렉토리를 설정후 yarn을 설치한다.
그리고 나의 경우 cache를 삭제해 주었다.
Build
deps 스테이지에서 설치한 node_modules를 가져오고
build를 수행한다.
Runtime
환경변수를 production으로 설정해 nextjs에게 알리고
group과 user를 설정해주어 보안성을 강화해준다.
public folder로 모든 정적 에셋을 복사해준다
이것은 nextjs config에 output모드일때만 작동될 것이다.
마지막으로 실제 node server.js와 함께 실행해 주면 된다.