지난번 docker image 경량화 시도를 이어서 기록한다.
1) 가벼운 base 이미지 변경과 2)poetry group을 활용한 불필요한 패키지 설치 제외 방법으로 이미지 사이즈를 꽤 줄일 수 있었다.
그러나 작성한 dockerfile을 기반으로 이미지를 빌드하는 시간은 여전히 길었고, 때문에 dockerfile 작성 테스트 자체가 시간과 비용이 많이 소모되었다.
도커 이미지 빌드 시간 단축
을 위해 시도했던 방법 중 가장 효과적이고 만족스러웠던 multi-stage build 기반 dockerfile 작성법을 소개하고자 한다.
docker image 사이즈를 줄이려는 노력은, 그 크기 자체도 문제였지만, dockerfile을 이용한 이미지 빌드 시간이 매우 오래걸리는 부분이 가장 큰 이슈였다.
FROM python:'원하는 버전'-slim
# install basic utils
RUN apt update && apt install --no-install-recommends - y \
apt-utils \
curl \
...
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# install poetry and set up
COPY pyproject.toml poetry.lock ./
RUN pip install poetry=='원하는 버전' && \
poetry config virtualenvs.create false && \
poetry install --only main --no-interaction --no-root
# 기타 app 실행 설정들(file copy, workdir , entrypoint 설정)
지난번 dockerfile 경량화를 진행한 후 dockerfile은 대략 위 형태를 가진다.
그러나 위 처럼 docker image 사이즈를 경량화하더라도,
이미지를 빌드할 때마다 환경 설치하는 시간이 생각보다 더 오래 걸렸다.
한번 빌드 실행 후 재빌드시, 대부분의 RUN 단계가 캐시를 사용하긴 했지만
RUN poetry install --only main --no-interaction --no-root
단계가 꼭 시간을 잡아먹었다. (왜 poetry install 은 캐시를 사용하지 않았을까? toml/lock 파일의 변경 사항은 없었다. 확인 필요)
위 문제를 해결해준 것이 바로 Multi-Stage builds 다.
FROM python:'원하는 버전' as builder
WORKDIR
COPY poetry.lock pyproject.toml ./
# install basic utils + poetry
RUN apt update -y && \
apt upgrade -y && \
apt install apt-utils build-essential -y && \
pip install poetry=='원하는 버전' && \
poetry config virtualenvs.create false && \
poetry install --only main --no-interaction --no-root
FROM python:'원하는 버전'-slim as application
COPY --from=builder /usr/local/lib/'원하는 버전'/site-packages /usr/loacl/lib/'원하는버전'/site-packages
# 기타 app 실행 설정들(file copy, workdir , entrypoint 설정)
컨테이너의 환경과 관련된 builder stage와 app 동작에 관련된 application stage, 2단계의 빌드로 구성된다.
변경 사항이 잘 발생하지 않는 환경 세팅 단계와 변경이 비교적 잘 일어나는 app 파일 및 동작 관련 단계를 구분한 것이다. 이 분리를 통해 앞서 얘기한 '재빌드마다 poetry install 과정에서 시간 소요'되는 이슈를 바로 해결할 수 있었다.
빌드 시간 축소: 레이어 캐싱 효과는 매우 강력했다.
python 환경 관련하여 변경사항이 없었기 때문에, 위 dockerfile을 가지고 재빌드할 경우 한번 빌드한 builder 이미지는 재사용하고, 변경된 부분만 다시 빌드하기 때문에 빌드 시간을 엄청나게 줄일 수 있었다.
이미지 사이즈 축소: 필요한 파일만 포함하여 최종 이미지 생성!
builder stage에서 환경을 셋업한 후, 관련 빌드 파일을 모두 다음 스테이지로 넘기는 것이 아니다.
COPY --from=builder /usr/local/lib/'원하는 버전'/site-packages /usr/loacl/lib/'원하는버전'/site-packages
application 실행에 필요한 패키지 폴더만 최종 이미지에 포함시켜 불필요한 의존성이나 임시 파일들이 이미지에 추가되는 것을 방지할 수 있다. 빌드 시간 축소를 목적으로 적용했으나, 최종 이미지 사이즈 또한 절반 이상 줄었다.
application 마다 다르겠지만, python-package 외에도 builder 에서 가져와야할 것들이 있을 수 있다. 이 부분은 종속성/변동성에 따라 builder stage 혹은 최종 stage에 적용해주어야한다.
나의 경우, application 실행에 필요한 패키지가 apt install 이 필요했다. 때문에 python/site-packages에 포함되어 있지 않아 application stage의 site-package COPY에서 이를 가져오지 않아 이슈가 있었다.
application builder 에 직접 추가하여 해결했다.
RUN apt update -y && \
apt install "패키지명" -y
추가) builder 단계에서 위 사항 추가하고, 설치 위치를 찾아 application 단계에서 COPY만 해오는 것이 더 좋았을 듯!