최근 개발자 커뮤니티에서 도커(Docker) 이미지 크기와 빌드 속도에 대한 논의가 뜨겁다. 이번 주 깃허브 트렌드에서 도커 최적화 기법에 대한 글이 급증하며, 많은 개발자들이 "이미지가 1GB가 넘고, 작은 변경에도 빌드 시간이 몇 분씩 걸린다"고 불만을 토로하고 있다. 이 문제는 도커파일(Dockerfile)을 작성할 때 기본 이미지 선택, 빌드 컨텍스트, 캐싱을 고려하지 않으면 흔히 발생한다. 하지만 몇 가지 간단한 변경으로 이미지 크기를 60~80% 줄이고, 빌드 시간을 몇 초로 단축할 수 있다.

기본 이미지 선택의 중요성

도커파일은 항상 FROM 지시어로 시작하여 기본 이미지를 선택한다. 이 기본 이미지는 애플리케이션의 기초가 되며, 추가 코드 없이도 최소 이미지 크기를 결정짓는다. 예를 들어, 공식 python:3.11 이미지는 전체 Debian 기반 이미지로, 대부분의 애플리케이션에서 사용하지 않는 컴파일러, 유틸리티, 패키지로 가득 차 있다.

각 이미지를 빌드한 후 크기를 비교해보면, 도커파일의 한 줄을 변경하는 것만으로도 수백 메가바이트의 차이를 확인할 수 있다. 기본 이미지 선택의 규칙은 python:3.1x-slim을 시작으로, 의존성이 호환되고 추가 크기 감소가 필요할 경우에만 alpine 이미지를 사용하는 것이다.

캐싱을 활용한 효율적인 빌드

도커는 이미지를 레이어(layer)별로 빌드하며, 각 지시어가 실행될 때마다 캐싱을 통해 이전 레이어를 재사용한다. 하지만 레이어가 변경되면 이후 모든 레이어가 무효화되어 처음부터 다시 빌드해야 한다. 이는 의존성 설치 시 큰 영향을 미친다. 예를 들어, 스크립트의 한 줄을 변경하면 Docker는 COPY . . 레이어를 무효화하고 모든 의존성을 처음부터 다시 설치하게 된다.

해결책은 변경이 적은 항목을 먼저 복사하는 것이다. 이렇게 하면 app.py를 변경해도 Docker는 캐시된 pip 레이어를 재사용하고 최종 COPY . ..만 다시 실행한다. 따라서 COPY와 RUN 지시어는 변경 빈도에 따라 정렬해야 하며, 항상 의존성을 코드보다 먼저 배치해야 한다.

다단계 빌드를 통한 이미지 경량화

빌드 시에만 필요한 도구들—예를 들어, 컴파일러, 테스트 실행기, 빌드 의존성—이 최종 이미지에 포함되어 불필요한 부하를 주는 경우가 많다. 다단계 빌드는 이를 해결하는 방법이다. 한 단계에서 모든 것을 빌드하거나 설치한 후, 최종 이미지에는 필요한 출력만 복사하는 방식이다.

예를 들어, Python 프로젝트에서 의존성을 설치하고 최종 이미지를 경량화하는 방법은 다음과 같다. 다단계 빌드를 사용하면 gcc와 build-essential 도구는 최종 이미지에서 사라지고, 컴파일된 패키지만 복사된다. 이 패턴은 Go나 Node.js 프로젝트에서도 효과적이며, 수백 메가바이트에 달하는 컴파일러나 노드 모듈을 최종 이미지에서 완전히 제외할 수 있다.

불필요한 파일 제거하기

apt-get으로 시스템 패키지를 설치할 때, 패키지 관리자는 패키지 목록과 캐시 파일을 다운로드한다. 이 파일들은 런타임에 필요하지 않지만, 별도의 RUN 지시어로 삭제하면 여전히 중간 레이어에 존재하여 최종 이미지 크기에 기여한다. 따라서 실제로 삭제하려면 설치와 같은 RUN 지시어 내에서 정리해야 한다.

규칙은 apt-get install 후에 && rm -rf /var/lib/apt/lists/*를 같은 RUN 명령어로 이어서 사용하는 것이다. 이러한 습관을 들이면 이미지 크기를 줄이는 데 큰 도움이 된다.

.dockerignore 파일의 필요성

docker build를 실행할 때, Docker는 빌드 디렉토리의 모든 파일을 Docker 데몬으로 전송한다. 이 과정에서 .git 히스토리, 가상 환경, 로컬 데이터 파일 등 불필요한 파일이 포함될 수 있다. .dockerignore 파일을 사용하면 빌드 컨텍스트에서 제외할 파일과 폴더를 지정할 수 있다.

예를 들어, 다음은 전형적인 Python 데이터 프로젝트를 위한 .dockerignore 파일의 예시이다. 이 파일을 사용하면 빌드 시작 전 Docker 데몬으로 전송되는 데이터가 대폭 줄어들며, 특히 대규모 데이터 프로젝트에서는 가장 큰 이점이 될 수 있다.

보안 측면에서도 주의가 필요하다. 프로젝트 폴더에 API 키나 데이터베이스 자격 증명이 포함된 .env 파일이 있다면, .dockerignore를 잊어버리면 이러한 비밀이 이미지에 포함될 수 있다. 따라서 .env 및 자격 증명 파일은 항상 .dockerignore에 추가해야 하며, 민감한 데이터는 Docker secrets를 사용하는 것이 좋다.

이러한 기법들은 고급 도커 지식이 필요하지 않으며, 일관되게 적용하면 이미지 크기를 줄이고 빌드를 빠르게 하며 배포를 깔끔하게 할 수 있다.

Bala Priya C는 인도 출신의 개발자이자 기술 작가이다. 그녀는 수학, 프로그래밍, 데이터 과학 및 콘텐츠 제작의 교차점에서 작업하는 것을 좋아한다. 그녀의 관심 분야는 DevOps, 데이터 과학 및 자연어 처리이다. 독서, 글쓰기, 코딩, 커피를 즐기며, 현재는 개발자 커뮤니티와 지식을 공유하는 튜토리얼과 가이드 작성을 하고 있다.