Docker Layer Caching

이정훈·2024년 8월 8일

Docker

목록 보기
14/34

Docker는 이미지를 빌드할 때 새로 만들어진 레이어를 캐싱합니다.
이렇게 캐싱된 레이어는 다음에 다른 이미지를 빌드 할 때 사용됩니다.
Docker는 캐싱을 이용해서 빌드 시간과 대역폭 사용량을 최소화합니다.
Docker가 알아서 캐싱을 해주지만 이 메커니즘을 이해해야 우리는 Docker가 캐싱을 더 잘 사용하게 만들 수 있습니다.

How the build cache Works?

Docker에서 캐싱을 하는 방법은 간단합니다.
Dockerfile에서 각 명령어마다 캐싱을 합니다.
예를 들어 아래와 같은 Dockerfile이 있다고 가정합시다.

# syntax=docker/dockerfile:1
FROM ubuntu:latest

RUN apt-get update && apt-get install -y build-essentials
COPY main.c Makefile /src/
WORKDIR /src/
RUN make build

위 Dockerfile을 이용해서 빌드를 한다면 아래 사진과 같은 레이어들이 생성됩니다.

그리고 각 레이어들은 모두 캐싱이 됩니다.
다음 빌드를 할 때 변경사항이 없다면 위 사진의 레이어들을 그대로 가져다 씁니다.
그러나 변경사항이 생기면 어떻게 될까요?
예를 들어 main.c 파일에 변경사항이 생겼다고 가정해봅시다.
그럼 해당 변경사항이 있는 명령어부터 아래 모든 레이어들은 캐싱된 레이어를 사용하지 않고 새로운 레이어를 만듭니다.
아래 사진과 같습니다.

Example of Efficient Caching

캐싱 메커니즘을 알았으니 비효율적인 Dockerfile과 효율적인 Dockerfile을 비교해봅시다.
먼저 비효율적인 Dockerfile입니다.

# syntax=docker/dockerfile:1
FROM node
WORKDIR /app
COPY . .          # Copy over all files in the current directory
RUN npm install   # Install dependencies
RUN npm build     # Run build

이 Dockerfile은 COPY명령어를 통해 모든 파일을 복사한 뒤 RUN 명령어를 통해 모든 패키지 설치 후 빌드를 합니다.
만약 소스 코드에 변경이 생기면 COPY밑에 모든 작업을 다시 해야 합니다.
여기서 소스 코드만 변경했다면 패키지는 변경이 없다는 것인데 불필요하게 새로운 레이어를 만들지않고 기존 레이어를 사용하게 끔 해야 합니다.

다음은 위 비효율적인 Dockerfile을 고쳐 효율적으로 바꾼 것입니다.

# syntax=docker/dockerfile:1
FROM node
WORKDIR /app
COPY package.json .    # Copy package management files
RUN npm install                  # Install dependencies
COPY . .                         # Copy over project files
RUN npm build                    # Run build

위 Dockerfile은 의존성을 먼저 설치하고 소스 코드를 복사합니다.
그렇기 때문에 다음에 소스코드 변경이 생겨도 의존성 설치는 이미 존재하는 레이어를 사용합니다.
이는 이미지 빌드를 효율적으로 만들어 줍니다.

Keep layers small

위 방법 외에도 Dockerfile에서 최적화하는 방법을 알아보겠습니다.
1. Don't include unnecessary files
불필요한 파일들은 빌드에 포함시키지 않아야 합니다.
아래는 모든 파일들을 /src에 넣고 있어서 불필요한 파일들이 들어가게 됩니다.

COPY . /src

그래서 아래와 같이 필요한 파일만 /src에 넣으면 좋습니다.

COPY ./src ./Makefile /src

이 방법외에도 .dockerignore을 이용해서 불필요한 파일들이 컨테이너에 들어가지 않게 할 수 있스니다.

  1. Use your package manage wisely
    npm이나 pip같은 패키지 매니저를 이용해 필요한 패키지만 설치하게 만드는 것이 좋습니다.

  2. Use the dedicated Run cache
    RUN 명령어에는 --mount type=cache 옵션이 있습니다.
    이 옵션은 RUN 명령어의 결과를 특정 디렉터리에 캐싱해서 사용하기 때문에 RUN 명령어의 최적화에 도움을 줍니다.
    참고로 컨테이너 내의 특정 디렉터리에 저장하는 것입니다.

RUN \
    --mount=type=cache,target=/var/cache/apt \
    apt-get update && apt-get install -y git
  1. Minimize the number of layers
    가능한 레이어의 수를 적게 유지하는 것이 좋습니다.

  2. Use an appropriate base image
    적절한 베이스 이미지를 사용하는 것이 중요합니다.

  3. Use multi-stage builds
    Dockerfile에서 명령어들을 특정 스테이지로 묶어서 스테이지를 순서대로 실행하는 방법입니다.
    예시는 아래와 같습니다.

FROM alpine as git
RUN apk add git

# stage 2
FROM git as fetch
WORKDIR /repo
RUN git clone https://github.com/your/repository.git .

# stage 3
FROM nginx as site
COPY --from=fetch /repo/docs/ /usr/share/nginx/html
  1. Combine commands together wherever possible
    커맨드를 합칠 수 있다면 합치는 것이 좋습니다.
    레이어가 줄어듭니다.
    예를 들어 아래와 같이 따로 작성한 커맨드는
RUN echo "the first command"
RUN echo "the second command"

아래와 같이 합쳐서 레이어를 줄일 수 있습니다.

RUN echo "the first command" && echo "the second command"
profile
기록으로 흔적을 남깁니다.

0개의 댓글