고급 Docker 이미지 최적화: 도구 및 기술 비교

Dive, SlimToolkit, 멀티 스테이지 빌드 및 기본 이미지 선택을 비교하여 Docker 이미지를 안전하게 축소하는 방법을 알아보세요.

고급 Docker 이미지 최적화: 도구 및 기술 비교

Docker 이미지 최적화는 빌드가 느리거나, 배포 시 레이어를 가져오는 데 시간이 오래 걸리거나, 취약점 스캔에서 애플리케이션이 사용하지 않는 패키지가 계속 발견될 때 중요합니다. 멀티 스테이지 빌드와 더 작은 기본 이미지가 도움이 되지만, 프로덕션 이미지는 각 레이어에 포함된 내용을 면밀히 살펴볼 필요가 있습니다.

이 가이드는 DockerSlim으로 알려진 SlimToolkit 및 Dive와 같은 분석 도구와 함께 Dockerfile 기술을 비교하여 런타임 동작을 손상시키지 않으면서 이미지를 축소할 수 있도록 합니다.

고급 최적화의 필요성

Docker 이미지는 신중하게 구성하지 않으면 불필요한 파일, 종속성 및 빌드 아티팩트로 비대해질 수 있습니다. 큰 이미지는 여러 문제를 야기합니다:

  • 느린 빌드 및 풀: 네트워크 전송 시간 증가 및 CI/CD 주기 지연.
  • 더 높은 스토리지 비용: 레지스트리 및 호스트에서 더 많은 디스크 공간 필요.
  • 증가된 공격 표면: 더 많은 소프트웨어 구성 요소는 더 많은 잠재적 취약점을 의미.
  • 느린 컨테이너 시작: 추출 및 처리해야 할 레이어 증가.

멀티 스테이지 빌드는 중요한 단계이지만, 주로 빌드 타임 종속성과 런타임 종속성을 분리합니다. 고급 최적화는 컨테이너가 런타임에 필요하지 않은 파일, 도구 및 패키지를 제거하는 데 중점을 둡니다.

Docker 이미지 레이어 이해

Docker 이미지는 레이어로 구성됩니다. Dockerfile의 각 명령어(예: RUN, COPY, ADD)는 새로운 읽기 전용 레이어를 만듭니다. 이러한 레이어는 캐시되어 후속 빌드를 가속화하지만 전체 이미지 크기에도 기여합니다. 레이어가 어떻게 쌓이고 각 레이어에 무엇이 포함되어 있는지 이해하는 것은 최적화의 기본입니다. 이후 레이어에서 파일을 삭제해도 이미지 크기가 줄어들지 않습니다. 단지 파일을 숨길 뿐이며, 원본 파일은 이전 레이어에 여전히 존재합니다. 이것이 멀티 스테이지 빌드가 효과적인 이유입니다. 새로운 FROM 문으로 새로 시작하여 최종 아티팩트만 복사할 수 있기 때문입니다.

기본 Dockerfile 최적화를 넘어서

전문 도구를 살펴보기 전에 몇 가지 Dockerfile 기술을 다시 살펴보고 개선해 보겠습니다:

1. 효율적인 기본 이미지

항상 애플리케이션 요구 사항을 충족하는 가장 작은 기본 이미지로 시작하십시오:

  • Alpine Linux: 매우 작음(약 5MB) 그러나 musl libc를 사용하여 일부 애플리케이션(예: C 확장이 있는 Python 패키지)과 호환성 문제를 일으킬 수 있습니다. Go 바이너리 또는 간단한 스크립트에 이상적입니다.
  • Distroless 이미지: Google에서 제공하며, 패키지 관리자, 셸 또는 기타 표준 OS 유틸리티 없이 애플리케이션과 런타임 종속성만 포함합니다. 매우 작고 보안성이 높습니다.
  • 슬림 변형: 많은 공식 이미지가 전체 버전보다 작은 -slim 또는 -alpine 태그를 제공합니다.
# 나쁨: 불필요한 도구가 포함된 큰 기본 이미지
FROM ubuntu:latest

# 좋음: 더 작고 목적에 맞는 기본 이미지
FROM python:3-slim

# 애플리케이션이 셸이나 패키지 관리자 없이 작동하는 경우 최소 런타임 이미지
# FROM gcr.io/distroless/python3-debian12

2. RUN 명령어 통합

RUN 명령어는 새 레이어를 만듭니다. &&로 명령어를 연결하면 레이어 수가 줄어들고 동일한 레이어 내에서 정리할 수 있습니다.

# 나쁨: 여러 레이어를 만들고 빌드 아티팩트를 남김
RUN apt-get update
RUN apt-get install -y --no-install-recommends some-package
RUN rm -rf /var/lib/apt/lists/*

# 좋음: 단일 레이어, 동일한 레이어 내에서 정리
RUN apt-get update \
    && apt-get install -y --no-install-recommends some-package \
    && rm -rf /var/lib/apt/lists/*
  • : 패키지를 설치하는 동일한 RUN 명령어 내에서 항상 rm -rf /var/lib/apt/lists/*(Debian/Ubuntu의 경우) 또는 다른 패키지 관리자에 대한 유사한 정리를 포함하십시오. 이렇게 하면 빌드 캐시가 최종 이미지에 남지 않습니다.

3. .dockerignore 효과적으로 활용

.dockerignore 파일은 .gitignore와 유사하게 작동하여 불필요한 파일(예: .git 디렉토리, node_modules, README.md, 테스트 파일, 로컬 구성)이 빌드 컨텍스트에 복사되는 것을 방지합니다. 이는 컨텍스트 크기를 크게 줄여 빌드 속도를 높이고 원치 않는 파일이 실수로 포함되는 것을 방지합니다.

.git
.vscode/
node_modules/
Dockerfile
README.md
*.log

심층 분석: 분석 및 축소 도구

Dockerfile 조정 외에도 전문 도구는 통찰력과 자동화된 축소 기능을 제공할 수 있습니다.

1. Dive: 이미지 효율성 시각화

Dive는 Docker 이미지를 레이어별로 탐색하기 위한 오픈 소스 도구입니다. 각 레이어의 내용을 보여주고, 변경된 파일을 식별하며, 낭비되는 공간을 추정합니다. 이미지가 큰지 이해하고 크기에 가장 많이 기여하는 특정 레이어나 파일을 찾는 데 매우 유용합니다.

설치

# macOS에서
brew install dive

# Linux에서, Dive 릴리스 페이지에서 현재 패키지를 설치하십시오.
# Debian/Ubuntu의 경우, 해당 .deb를 다운로드하여 설치하십시오:
sudo apt install ./dive_*_linux_amd64.deb

사용 예시

기존 이미지를 분석하려면:

dive my-image:latest

Dive는 대화형 터미널 UI를 시작합니다. 왼쪽에는 레이어 목록, 크기 및 크기 변경 사항이 표시됩니다. 오른쪽에는 선택한 레이어의 파일 시스템이 표시되며 추가, 제거 또는 수정된 파일이 강조 표시됩니다. 또한 "효율성 점수" 및 "낭비된 공간" 메트릭을 제공합니다.

  • : 한 레이어에 나타나지만 이후 레이어에서 삭제되는 큰 파일이나 디렉토리를 찾으십시오. 이는 멀티 스테이지 빌드 최적화 또는 동일한 RUN 명령어 내에서 정리할 수 있는 잠재적 영역을 나타냅니다.

2. SlimToolkit: 자동화된 이미지 축소

SlimToolkit(이전 게시물 및 패키지에서 여전히 DockerSlim이라고도 함)은 Docker 이미지를 자동으로 축소할 수 있습니다. 정적 검사와 동적 런타임 분석을 결합한 다음 프로브 실행 중에 관찰된 파일을 포함하는 더 작은 이미지를 빌드합니다.

작동 방식

  1. 분석: Slim은 원래 컨테이너를 실행하고 프로브 중에 런타임 동작을 모니터링합니다.
  2. 프로필 생성: 애플리케이션의 런타임 요구 사항에 대한 프로필을 빌드합니다.
  3. 최적화: 이 프로필을 기반으로 필요한 것으로 식별된 파일만 포함하는 더 작은 이미지를 만듭니다.

설치

# macOS에서
brew install docker-slim

# Linux에서, SlimToolkit 프로젝트에서 현재 릴리스를 설치하십시오.
# 플랫폼에 맞는 패키지 이름은 공식 릴리스 페이지를 확인하십시오.

기본 사용 예시

간단한 Python Flask 애플리케이션 app.py가 있다고 가정해 보겠습니다:

# app.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, Slim Docker!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

그리고 이에 대한 Dockerfile:

# Dockerfile
FROM python:3-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]

먼저 일반 이미지를 빌드하십시오:

docker build -t flask-demo:full .

그런 다음 SlimToolkit을 실행하십시오. 정확한 명령어 이름은 도구 설치 방법에 따라 다르므로 slim --help 또는 docker-slim --help를 확인하십시오:

slim build --target flask-demo:full --http-probe=false

웹 애플리케이션의 경우 가능하면 프로브를 활성화하고 중요한 엔드포인트를 실행하는지 확인하십시오. 프로브가 /만 적중하면 Slim은 백그라운드 작업, 관리자 경로, 이미지 프로세서 또는 거의 사용되지 않는 플러그인에 필요한 파일을 제거할 수 있습니다.

올바른 기술 선택

이미지가 왜 큰지 이해해야 할 때는 Dive를 사용하십시오. 빌드 도구가 런타임 이미지로 누출될 때는 멀티 스테이지 빌드를 사용하십시오. 런타임 가정을 제어할 때는 distroless 또는 슬림 기본 이미지를 사용하십시오. 최적화된 이미지를 철저히 테스트할 수 있을 때는 SlimToolkit을 사용하십시오.

실용적인 워크플로는 다음과 같습니다:

  1. 일반적으로 이미지를 빌드합니다.
  2. dive your-image:tag를 실행하고 큰 파일, 패키지 캐시 및 이전 레이어에 여전히 존재하는 삭제된 파일을 찾습니다.
  3. 컴파일 및 패키지 설치 정리를 이전 Dockerfile 단계 또는 별도의 빌드 스테이지로 이동합니다.
  4. 이미지에 대해 테스트 스위트를 다시 빌드하고 실행합니다.
  5. 시작, 상태 확인, 예약된 작업 및 덜 일반적인 경로에 대한 강력한 스모크 테스트가 있는 경우에만 SlimToolkit을 시도합니다.

핵심 요점

Dockerfile 수정부터 시작하십시오. CI에서 검토하고 반복하기 쉽기 때문입니다. 이미지 크기가 이해가 되지 않을 때 Dive를 도입하십시오. 프로브 및 테스트가 잘 되는 워크로드에 SlimToolkit을 사용하고 최적화된 이미지를 다른 릴리스와 동일한 검증이 필요한 새로운 아티팩트로 취급하십시오.