한번쯤 도커 이미지를 빌드해 보신 분들이라면, 이미지 사이즈가 적게는 수십 ~ 많게는 몇백 메가바이트에서 기가바이트 단위까지 넘나드는 것을 보셨을 것입니다.
물론 가상 머신에 OS와 어플리케이션을 올린 것보다는 가볍겠지만 단순한 어플리케이션 하나가 수백 메가를 차지하는 걸 보면 뭔가 억울한데요, Distroless 라는 구글에서 관리하는 베이스 이미지를 사용하면 일부 환경의 어플리케이션 이미지를 더욱 가볍게 제작할 수 있습니다.
이번 글에서는 Node.js의 Distroless
베이스 이미지를 사용해 간단한 이미지를 제작해보고, 기존 Node.js 베이스 이미지를 사용했을 때보다 얼마나 용량을 절약할 수 있는지 알아보도록 하겠습니다.
Distroless 이미지가 용량을 절약하는 원리는 운영체제, 버전 관리 툴(Ex. NPM), 쉘까지 모두 제거된 이미지를 사용함으로써 이미지에 순수한 어플리케이션과 의존성만을 사용하도록 제작한 것인데요, Node.js로 예를 들면 다음과 같습니다.
기존 Node 이미지 : 알파인 리눅스 등의 운영체제 및 쉘 + NPM + 어플리케이션 코드 + 의존성 파일(node_modules
)
Distroless Node 이미지 : 어플리케이션 코드 + 의존성 파일(node_modules
)
Distroless
이미지를 만드는 방법은 빌드용 이미지와 실행용 이미지를 각각 만드는 것인데요, 이를 보다 쉽게 만들어주는 도커의 멀티 스테이징 빌드 에 대해 간단히 짚고 넘어가겠습니다.
멀티 스테이징 빌드란 한 도커파일 안에서 둘 이상의 이미지 제작 프로세스를 구성할 수 있는 방법으로, 이를 이용해 먼저 빌드용 이미지를 빌드한 후 빌드용 이미지에서 생성한 결과물을 Distroless
이미지에 복사해와 실행 이미지를 구성합니다.
✅ 프로세스간 파일 복사를 위해, --from=(프로세스 번호 또는 별명) 을 사용합니다.
# 멀티 스테이징 빌드
# 0번 프로세스 (빌드용 이미지)
FROM node
WORKDIR /src
COPY ./package.json .
RUN npm install
# 1번 프로세스 (실행용 이미지)
FROM gcr.io/distroless/nodejs
# 0번 프로세스(0) 의 /src 폴더를 복사합니다.
COPY --from=0 /src /src
# distroless 이미지는 기본적으로 엔트리포인트로 node 커맨드가 설정되어 있습니다.
# 따라서, CMD node index.js 대신 CMD ["index.js"] 를 통해 커맨드를 실행합니다.
CMD ["index.js"]
다음은 멀티 스테이지 빌드를 통해 빌드 / 실행용 이미지를 제작하는 예제 도커파일입니다.
# 빌드용 이미지 제작 프로세스
# 0번 프로세스에 AS 키워드로 build-env 라는 별명을 설정합니다.
FROM node AS build-env
WORKDIR /src
COPY ./package.json .
RUN npm install
# 실행용 이미지 제작 프로세스
# distroless-nodejs 이미지를 사용합니다.
FROM gcr.io/distroless/nodejs
# build-env 프로세스에서 설치가 완료된 의존성 파일과 소스 코드를 복사해옵니다.
COPY --from=build-env /src /src
WORKDIR /src
EXPOSE 3000
CMD ["index.js"]
normal-nodejs는 node
베이스 이미지로 제작한 이미지이며, distroless-nodejs는 distroless
베이스 이미지와 멀티 스테이징 빌드를 활용해 제작한 실행용 이미지입니다.
보시는 것처럼 distroless
이미지를 사용하면 약 1/10 크기로 용량이 줄어든 것을 확인할 수 있는데요, 이뿐만 아니라 내부적으로 운영체제를 탑재하지 않음으로써 보안 측면에서 취약점이 생길 수 있는 부분 역시 줄일 수 있습니다.
하지만 단점 역시 존재하는데요, 무엇보다도 컨테이너 내에 패키지 관리자가 존재하지 않기 때문에 추가적인 소프트웨어를 절대로 설치할 수 없다는 단점이 있고, 현재 알려진 이슈로는 AWS에서는 모든 컨테이너에 쉘이 있다고 생각하기 때문에 distroless
이미지를 AWS에 배포하면 상태 체크를 통과하지 못한다는 문제가 존재한다고 합니다.