Dockerfile 내에 FROM
명령어를 사용해 빌드 시 단계별로 시작 할 수 있습니다. 이전 단계에 복사하여 최종 이미지를 원하는 시점에 빌드를 가능하게 하는 기법을 Multi-stage 입니다.
현재 진행 중인 프로젝트에서는 NestJS와 React를 사용하여 서버와 클라이언트를 분리해서 개발하고 있습니다.
서버(백엔드
)에서 작업한 결과물을 클라이언트(프론트엔드
)에 연결하여 서로 통신이 잘 되는지 확인할 필요가 있습니다.
이때 서버, 데이터베이스, 클라이언트가 모두 실행된 상태여야 합니다. 그러나 각 사용자마다 운영체제와 컴퓨팅 환경이 다르기 때문에 정상적으로 실행할 수 있다는 것을 보장하기 쉽지 않습니다.
Docker 가상 컨테이너를 활용하면 이러한 문제 환경을 해결할 수 있습니다. 운영체제, 사양, 버전 등 서로 다른 환경에서도 Docker 이미지로 실행을 보장할 수 있습니다.
DockerHub에는 수많은 이미지를 사용하고 있으며, 각 제조사에서 필요한 이미지를 DockerHub에 제공합니다.
현재 프로젝트에서는 Dockerfile을 사용하여 Docker 이미지화를 하고 있습니다. Docker 이미지화를 할 때 Dev 환경과 Prod 환경을 구분해야 합니다.
Prod 환경에 배포할 때는 불필요한 라이브러리 제거와 이미지 용량을 최소화해야 합니다. 또한 Dev 환경에서는 프론트엔드 개발자와 백엔드 개발자 간에 Docker 이미지를 공유하여 개발 환경에 맞게 Docker 이미지를 사용해야 합니다.
두 환경의 차이에 맞추어 Docker 이미지가 빌드되어야 합니다. 이 문제를 해결하기 위해 Multi-stage 를 사용하여 서로 다른 빌드 환경을 구분할 수 있습니다.
개발 환경(Dev), 빌드 환경(Build), 프로덕션 환경(Prod)으로 단계를 구분했습니다.
Dev 단계에서는 모든 의존성 라이브러리를 설치합니다.
FROM node:18-alpine AS dev
RUN apk add --no-cache libc6-compat && \\
apk update && \\
apk add --update curl && \\
rm -rf /var/cache/apk/*
USER root
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && \\
adduser --system --uid 1001 nestjs
COPY --chown=nestjs:nodejs . .
RUN npm ci && npm cache clean --force
HEALTHCHECK CMD curl --fail <http://localhost:3333/health> || exit 1
USER nestjs
Build 단계에서는 Build와 dev를 제외한 의존성을 설치합니다. 로그 폴더가 없을 시 폴더를 생성합니다.
FROM node:18-alpine AS build
ENV NODE_ENV prod
RUN apk add --no-cache libc6-compat && \\
apk update && \\
apk add --update curl && \\
rm -rf /var/cache/apk/*
USER root
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && \\
adduser --system --uid 1001 nestjs
COPY --chown=node:node --from=dev /app/node_modules /app/node_modules
COPY --chown=nestjs:nodejs . .
RUN if [ ! -d "/app/log" ]; then mkdir -p /app/log; fi && \\
npm run build && \\
npm ci --omit=dev && \\
npm cache clean --force
USER nestjs
Prod 단계에서는 소스 코드를 컴파일하고, 최소한으로 이미지를 생성합니다.
FROM node:18-alpine AS prod
ENV NODE_ENV prod
# Set install apk
RUN apk add --no-cache libc6-compat && \\
apk update && \\
apk add --no-cache --update curl && \\
rm -rf /var/cache/apk/*
## Set the timezone in Seoul
RUN apk --no-cache add tzdata && \\
cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \\
echo "Asia/Seoul" > /etc/timezone
USER root
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && \\
adduser --system --uid 1001 nestjs
COPY --chown=nestjs:nodejs --from=build /app/dist /app/dist
COPY --chown=nestjs:nodejs --from=build /app/node_modules /app/node_modules
COPY --chown=nestjs:nodejs --from=build /app/log /app/log
USER nestjs
HEALTHCHECK CMD curl --fail <http://localhost:3031/health> || exit 1
CMD [ "node", "dist/main.js" ]
이렇게 Multi-stage를 사용함으로써 개발 환경, 빌드 환경, 프로덕션 환경을 분리하여 각 환경에 맞는 최적화된 Docker 이미지를 생성할 수 있게 되었습니다.