- 내려받은 이미지는 명시적으로 삭제하지 않는 한 자동으로 삭제되지 않는다.
- 예약 작업을 만들어 사용하지 않는 이미지 레이어를 삭제하는 방법도 좋지만, 이미지를 잘 최적화하면 이 문제가 크게 줄어든다.
- 꼭 필요한 파일만 이미지에 포함시켜야 한다.
- 실제 Dockerfile 스크립트를 작성해 보면 사용되지 않을 이미지 파일이나 문서 파일까지 한꺼번에 디렉터리 채로 이미지에 포함시키는 경우가 많다.
예제 17.1 불필요한 파일을 제거해 최적화를 시도한 Dockerfile 스크립트
# Dockerfile v1 - 전체 디렉터리 구조를 이미지에 복사함
FROM diamol/base
CMD echo app- && ls app && echo docs- && ls docs
COPY . .
# Dockerfile v2 - 불필요한 파일을 별도로 삭제함
FROM diamol/base
CMD echo app- && ls app && echo docs- && ls docs
COPY . .
RUN rm -rf docs
- 이미지는 이미지 레이어가 쌓여 만들어진다.
- docs 디렉터리는 COPY 인스트럭션으로 만든 레이어에 그대로 남아 있다.
- 삭제 레이어에 가려 보이지 않을 뿐 전체 이미지 크기는 전혀 줄어들지 않는다.
실습 앞에 나온 두 Dockerfile 스크립트로 이미지를 빌드해 크기를 비교해 보자.
001) ➜ cd ch17/exercises/build-context
002)
003) ➜ docker image build -t diamol/ch17-build-context:v1 .
004) [+] Building 3.1s (8/8) FINISHED
005) => exporting to image 0.0s
006) => => naming to docker.io/diamol/ch17-build-context:v1 0.0s
007)
008) ➜ docker image build -t diamol/ch17-build-context:v2 -f ./Dockerfile.v2 .
009) [+] Building 1.2s (8/8) FINISHED
010) => exporting to image 0.0s
011) => => naming to docker.io/diamol/ch17-build-context:v2 0.0s
012)
013) ➜ docker image ls
014) REPOSITORY TAG IMAGE ID CREATED SIZE
015) diamol/ch17-build-context v2 206c5fa79f99 43 seconds ago 8.99MB
016) diamol/ch17-build-context v1 2e1ca97fac74 About a minute ago 8.99MB
-
015~016: 파일을 삭제한 v2 이미지의 크기가 v1 이미지와 같다. 이미지는 이미지 레이어가 합쳐져 만들어지는데, 파일이 삭제된 것이 아니라 그다음 레이어가 해당 파일을 가린 것이다.
-
다음 레이어에서 불필요한 파일을 제거해 봐야 소용이 없으며, 각 레이어마다 따로 최적화해야 한다.
실습 캐시에 저장된 레이어로 컨테이너를 실행할 수 있다. 전체 이미지로 실행한 컨테이너와 비교해 보자.
001) ➜ docker container run diamol/ch17-build-context:v2
002) app-
003) init.txt
004) docs-
005) ls: docs: No such file or directory
006)
007) ➜ docker history diamol/ch17-build-context:v2
008) IMAGE CREATED CREATED BY SIZE COMMENT
009) 206c5fa79f99 8 minutes ago RUN /bin/sh -c rm -rf docs # buildkit 0B buildkit.dockerfile.v0
010) <missing> 8 minutes ago COPY . . # buildkit 2.1MB buildkit.dockerfile.v0
011) <missing> 8 minutes ago CMD ["/bin/sh" "-c" "echo app- && ls app && … 0B buildkit.dockerfile.v0
012) <missing> 2 years ago /bin/sh -c apk add --no-cache curl 1.59MB
013) <missing> 3 years ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
014) <missing> 3 years ago /bin/sh -c #(nop) ADD file:da3ddeca2212f561c… 5.3MB
015)
015) docker container run <이전_레이어_식별자>
- 005: 컨테이너를 실행하면 파일 목록을 출력한다. Dockerfile 스크립트에서 docs 디렉터리의 파일을 삭제했으니 최종 이미지의 파일 시스템에서는 이 디렉터리에 아무 파일도 없다.
- 010: 이 레이어는 COPY 인스트럭션으로 생성됐다. docs 디렉터리의 모든 파일은 이 레이어에 들어 있다.
- 015: 교재에는 레이어 이미지 고유값이 있는데 나는 없다?
예제 17-2 필요한 파일만 복사하도록 최적화된 Dockerfile 스크립트
FROM diamol/base
CMD echo app- && ls app && echo docs- && ls docs
COPY ./app ./app
- 이 스크립트로 이미지를 빌드해 보면 이미지 크기가 줄어들었음을 알 수 있다.
- 하지만 아직 최적화의 여지가 남아 있다.
- 도커의 빌드 과정은 엔진에 빌드 컨텍스트(빌드를 실행한 디렉터리)를 압축하고 Dockerfile 스크립트를 함께 보내면서 시작된다.
- 이러한 빌드 과정 덕분에 로컬 컴퓨터에서 원격 엔진에 이미지 빌드 명령을 내릴 수 있는 것이다.
- 이 빌드 컨텍스트에는 불필요한 파일이 포함된 경우가 많다.
- .dockerignore 파일에 불필요한 디렉터리나 파일 목록(와일드카드도 사용할 수 있다)을 기재하면 빌드 컨텍스트에서 이들 파일을 제외할 수 있다.
실습 .dockerignore 파일을 작성해 빌드 컨텍스트의 크기를 출인 다음 최적화된 이미지를 다시 빌드해 보자.
# 최적화된 이미지를 빌드한다고 하지만 컨텍스트에 아직 불필요한 파일이 있다
➜ docker image build -t diamol/ch17-build-context:v3 -f ./Dockerfile.v3 .
[+] Building 2.9s (8/8) FINISHED
=> exporting to image 0.0s
=> => naming to docker.io/diamol/ch17-build-context:v3
# 미리 작성해 둔 ignore 파일의 이름을 바꿔 유효하게 한다
➜ mv rename.dockerignore .dockerignore
➜ cat .dockerignore
docs/
Dockerfile*%
# 다시 한 번 똑같이 이미지를 빌드한다
➜ docker image build -t diamol/ch17-build-context:v3 -f ./Dockerfile.v3 .
[+] Building 1.0s (7/7) FINISHED
=> exporting to image 0.0s
=> => naming to docker.io/diamol/ch17-build-context:v3 0.0s
- 첫 번째 빌드에서는 엔진에 전달된 빌드 컨텍스트의 용량이 2MB였다.
- 두 번째 빌드에서는 현재 디렉터리에 빌드 컨텍스트에서 제외할 파일 목록이 정의된 .dockerignore 파일이 있는 상태에서 빌드가 실행됐다.
- 이때의 빌드 컨텍스트 용량은 4KB에 불과했다.