4 - Dockerfile 최적화와 캐싱 메커니즘

Yoony·2024년 2월 6일
0
post-thumbnail

Dockerfile

Dockerfile은 애플리케이션을 패키징하기 위한 간단한 스크립트입니다. 스크립트는 익스트럭션으로 구성되어 있고, 대문자로 작성돼 있으나 소문자를 사용해도 무관합니다.

instruction

  1. FROM: 모든 이미지는 다른 이미지로부터 출발한다. 빌드할 이미지의 시작점을 지정한다.
  2. ENV: 환경 변수 값을 지정한다. 값을 지정하기 위해 [key]=[value] 형식을 따른다.
  3. WORKDIR: 컨테이너의 이미지 파일 시스템에 디렉터리를 만들고, 해당 디렉터리를 작업 디렉터리로 지정한다. 컨테이너 또는 호스트에 이미 존재할 필요가 없고 새로 만든다.
  4. COPY: 로컬 파일 시스템의 파일 혹은 디렉터리를 컨테이너 이미지로 복사한다. [원본 경로][복사 경로] 형식으로 지정한다.
  5. ENTRYPOINT: 이미지로 컨테이너를 띄울 때 항상 실행되어야 하는 커맨드를 지정한다. Docker image를 마치 하나의 실행 파일처럼 사용할 때 유용합니다. 컨테이너가 뜰 때 ENTRYPOINT로 지정한 커맨드가 실행되고, 이 커맨드로 실행한 프로세스가 죽을 때 컨테이너도 따라서 종료되기 때문입니다.
  6. CMD: 도커가 이미지로부터 컨테이너를 실행했을 때 실행할 디폴트 명령을 지정한다. 또는 ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용합니다.
  7. RUN: CMD와는 실행 시점이 다릅니다. CMD는 컨테이너 실행 시, RUN은 이미지를 빌드하는 과정에서 필요한 커맨드를 실행하기 위해서 사용됩니다. 쉘(shell)을 통해 거의 못하는 작업이 없듯, RUN 명령어로 할 수 있는 일도 무궁무진하지만 보통 이미지 안의 소프트웨어를 설치하기 위해서 많이 사용됩니다.

Docker 이미지 레이어 캐싱 & 최적화

이미지 레이어란?

instruction으로 도커 이미지를 빌드한다는 것을 이해했습니다. 도커 이미지는 이미지 레이어가 모인 논리적 대상입니다. 즉, 도커 이미지를 구성하는 물리적으로 저장된 파일은 도커 엔진의 캐시에 저장된 이미지 레이어입니다. 이미지 레이어는 어떻게 생성될까요? Dockerfile의 instruction은 각각 하나의 이미지 레이어와 1:1로 연결됩니다. 즉, instruction이 실행될 때 이미지 레이어가 생성됩니다. 이미지 레이어는 디스크 용량과 관련됩니다. 어떻게 이미지 레이어가 차지하는 디스크 용량을 줄이고 관리할 수 있을까요?

1. 이미지 레이어는 여러 이미지가 공유할 수 있습니다.

  • 예를들어 diamol/node라는 이미지는 Node.js 런타임과 최소한의 운영체제를 포함합니다. 이때 other-node-app 이미지의 Dockerfile에서 FROM diamol/node를 지정합니다. other-node-app은 최소한의 운영체제 레이어와 Node.js 런타임을 포함합니다. 뿐만 아니라 diamol/node 이미지를 기반 이미지로 하므로 기반 이미지의 모든 레이어를 포함합니다.
  • 이때 이미지 레이어를 여러 이미지가 공유한다면, 공유되는 레이어는 수정할 수 없습니다. 도커는 이미지 레이어를 read-only로 만들어 두어 이런 문제를 방지합니다. 이미지를 빌드하면서 레이어가 만들어지면 다른 이미지에서 재사용될 수 있습니다. 그러나 레이어를 수정할 수는 없습니다.

2. 이미지 레이어는 캐싱할 수 있습니다.

  • 캐싱 메커니즘을 통해서 Dockerfile 스크립트를 최적화할 수 있습니다. 최적화란 도커 이미지 용량을 줄이고 빌드 시간을 단축하는 것입니다. instruction의 결과가 이전 빌드와 같다면, 이전에 캐시된 레이어를 사용할 수 있습니다. 이런 방법으로 똑같은 instruction을 다시 실행하는 낭비를 줄일 수 있습니다.

  • 도커는 캐시에 일치하는 레이어가 있는지 확인하기 위해 해시값을 사용합니다. 도커 이미지를 pull 받게 되면 마치 여러개로 분리된 조각을 내려받는 것처럼 보입니다. 이렇게 분리된 데이터를 레이어(Layer)라고 하고, hash로 구분합니다. 레이어가 업데이트 된다면 hash도 변경됩니다.

$ docker pull nginx:latest

Using default tag: latest
latest: Pulling from library/nginx
c499e6d256d6: Already exists
74cda408e262: Pull complete
ffadbd415ab7: Pull complete
Digest: sha256:282530fcb7cd19f3848c7b611043f82ae4be3781cb00105a1d593d7e6286b596
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
  • 여기서, Dockerfile에 정의된 모든 instruction이 레이어가 되는 것은 아닙니다. RUN, ADD, COPY 이 3가지 단계만이 레이어로 저장되고 그 외에 메타 정보를 다루는 CMD, LABEL, ENV, EXPOSE 등은 임시 레이어로 생성되지만 저장되지 않아 이미지 사이즈에 영향을 주지 않습니다.
  • 기존 이미지 레이어에 해시값이 일치하는 것이 없다면 캐시 미스가 발생하고 해당 instruction이 실행됩니다. 여기서 주목할 점은 한번 instruction이 실행되면 그 다음에 오는 instruction은 수정된 것이 없더라도 항상 실행됩니다. 이러한 연유로 잘 수정하지 않는 instruction이 앞으로 오고, 자주 수정되는 instruction이 뒤에 오도록 배치해야 합니다. 이렇게 해야 캐시에 저장된 이미지 레이어를 되도록 재사용할 수 있습니다. 이미지를 공유하는 과정에서 시간, 디스크 용량, 네트워크 대역폭 모두 절약할 수 있는 방법입니다.

ref: https://jonnung.dev/docker/2020/04/08/optimizing-docker-images/

profile
Software Quality Engineer

0개의 댓글