[Memetory] Docker 이미지 크기 줄이기

이준우·2024년 3월 30일
0

개요

우리 서비스는 생성형 AI를 활용하여 사용자가 입력한 각 이미지에 표정과 대사를 입힌 영상을 만든 후, 영상들을 하나의 영상으로 만들어주는 서비스입니다.

그 중, 영상을 생성해주는 역할을 맡은 AI 서버를 배포할 때 생긴 문제점을 해결하는 과정을 담았습니다.

Dockerfile 작성하기

로컬의 개발환경을 그대로 서버로 가져가기 위해서 Dockerfile 을 작성했습니다.

  • 초기 Dockerfile
    FROM python:3.10
    
    ENV PYTHONUNBUFFERED 1
    WORKDIR /app
    COPY . ./
    
    VOLUME ./image:./image
    
    RUN pip install --upgrade pip
    
    RUN apt-get update
    RUN apt-get -y install ffmpeg
    
    RUN pip install -r ./requirements.txt
    
    CMD ["python3", "app.py"]

앱 작동에 필요한 python 패키지와 영상 처리에 필요한 ffmpg를 다운로드 하는 과정을 담아서 Dockerfile을 작성했습니다. 이후 만들어진 Docker 이미지의 용량을 보니 14 GB로 상당히 큰 이미지가 완성되었습니다.

14 GB 정도로 큰 이미지는 업로드할 때도 오래 걸리기 때문에, AWS EC2의 비용이 크게 발생할 수 밖에 없고 build 할 때 더 많은 시간을 소요하기 때문에 이미지의 크기를 줄여야만 하는 상황이 발생했습니다.

1차 해결방안

  1. RUN apt-get update && apt-get -y install ffmpeg
    • apt-get 의 업데이트와 ffmpeg의 다운로드를 RUN 2개로 나누는 것이 아닌 하나로 붙여서 실행
    • Docker는 이미지를 빌드할 때, 명령에 대한 레이어로 실행되는데 레이어가 늘어나면 늘어날 수록 용량이 증가하게 된다. 따라서 RUN 명령에 대한 레이어를 하나로 합침으로써, 용량을 줄이기 위해 노력했습니다.
  2. RUN pip --no-cache-dir install -r ./requirements.txt
    • --no cache-dir 명령어를 통해서 필요없는 캐시 데이터를 저장하지 않게했다.

위 두가지 해결방안을 적용해서 Docker 이미지를 빌드했지만, 이미지의 크기에는 큰 영향을 미치지 않고 여전히 14 GB에 가까운 크기의 이미지가 빌드되었습니다…

2차 해결방안

인터넷을 통해서 Docker 이미지를 줄이는 방법을 많이 찾아보았고, 그중 가장 보편적인 방법은 Docker image를 빌드할 때 Multi-stage 를 적용하는 것이였습니다.

Multi-stage란 여러 개의 BaseImage를 사용하여 Docker build를 수행하는 역할이다.
BaseImage란 Docker build에 사용하는 기본 이미지로써, Dockerfile에서 FROM에 설정된 이미지에 해당된다.
FROM 키워드를 기준으로 작업공간이 분리되는데, 이 분리된 작업 공간을 stage라고 한다. 즉 2개 이상의 stage로 나뉜 것을 Multi-stage라고 한다.

FROM python:3.10 AS builder

ENV PYTHONUNBUFFERED 1
ARG CACHEBUST=1
WORKDIR /app
COPY requirements.* ./

RUN apt-get update && apt-get -y install ffmpeg

RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r ./requirements.txt

COPY . ./

FROM python:3.10-slim AS deployer

COPY --from=builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY --from=builder /app /app

RUN apt-get update && apt-get -y install ffmpeg

WORKDIR /app

CMD ["python3", "app.py"]

파이썬의 패키지를 설치하는 stage와 ffmpeg 응용프로그램을 설치하는 2개의 stage로 나눠서 작성했습니다.

각 stage는 FROM을 기준으로 나뉘며 AS를 통해서 별칭을 지정할 수 있습니다.

각 스테이지에 있는 데이터는 COPY--from 옵션을 통해서 스테이지간 파일을 교환할 수 있다.

  • COPY --from=builder /app /appbuilder 의 /app 디렉토리를 deployer 의 /app 디렉토리로 복사하는 역할을 합니다.

즉 builder부분에서 파이썬의 패키지를 다운로드 한 후, 다운로드된 파일들을 deployer 스테이지에 복사하여서 이미지를 생성하였습니다!

결과

14GB 에서 8GB 까지 데이터를 대폭 줄이게 되었다!

덕분에 EC2 서버의 볼륨을 크게 늘리지 않고, 해당 이미지를 사용하여 컨테이너를 돌릴 수 있게 되었다.

추가 문제

로컬에서는 실행되지만 서버에서는 실행되지 않는 문제가 발생했다.

추측

requirment.txt에 CPU에 종속적인 라이브러리가 존재한다고 추측

boto3~=1.34.60
requests~=2.31.0
gfpgan~=1.3.8
keras~=2.13.1
Flask~=3.0.0
numpy==1.24.3
opencv-python==4.8.0.74
onnx==1.15.0
insightface==0.7.3
psutil==5.9.5
tk==0.1.0
customtkinter==5.2.0
tkinterdnd2==0.3.0
onnxruntime==1.15.0
tensorflow==2.13.0
opennsfw2==0.10.2
protobuf==4.23.4
tqdm==4.65.0
python-dotenv~=1.0.1
  • 서버에서 docker build 중 basicar 부분에서 오류가 발생한다는 것을 확인했다.
  • linux에는 GPU가 존재하지 않는다는 글을 본 후, gpu를 활용하는 onnxruntime에서 발생하는 문제 같다고 생각했다.
    • 아니였어 → pip 에서 제거했음에도 불구하고 basicar를 다운로드
  • gfpgan~=1.3.8
    • 종속성에 basicar 가 존재하는 것을 확인

      gfpgan

해결

  • 페이지 스왑 AI인 roop 명령어를 컨테이너에 돌려본 결과 그냥 kiiled 되는 문제점을 발견
  • 리눅스의 용량, 메모리가 부족할 수 있다는 chatGPT의 결과를 봄
  • cpu의 코어수가 부족해서 생긴 문제같다는 결론을 내림
    • 즉, 컴퓨터의 성능 문제
  • 따라서 t3.medium으로 스케일업을 했더니 해결되었다.
    • cpu 코어수 2개, t2보다 업그레이드 된 cpu
profile
잘 살고 싶은 사람

0개의 댓글