🐳 Docker 이미지 다이어트의 시작: docker history로 족보 파헤치기

분명 가벼운 앱 하나 띄웠을 뿐인데, 이미지 용량을 확인해 보면 1GB가 훌쩍 넘어있을 때가 있습니다. "아니, 내가 뭘 넣었다고?" 싶어 당황스럽죠. 이럴 때 필요한 게 바로 이미지의 '족보'를 까보는 일입니다.

docker-layer-diet

"너 도대체 뭘 먹고 이렇게 커졌니?"

Docker 이미지는 겹겹이 쌓인 양파 껍질(레이어)과 같습니다. docker history는 이 껍질을 하나씩 벗겨서 범인을 찾아내는 엑스레이 같은 명령어입니다.

기본적인 사용법은 아주 간단합니다.

# 기본 사용법
docker history [옵션] <이미지 이름:태그>

# 예시: 내 앱의 히스토리 확인
docker history my-app:latest

명령어를 실행하면 이미지의 최신 레이어부터 베이스 이미지까지 역순으로 쫙 나타납니다.

IMAGE          CREATED          CREATED BY                                      SIZE
a6215f271958   5 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]               0B
<missing>      7 weeks ago      /bin/sh -c #(nop) ADD file:f28242cf608f6...     7.81MB

여기서 SIZE 항목을 유심히 보세요. 0B여야 할 곳에 수백 MB가 찍혀 있다면? 그 녀석이 다이어트 대상입니다. 경험으로 보다보면 '이상한 냄새가 나는 곳"이 분명히 있습니다.

**💡 유용한 팁: --no-trunc**

기본 출력은 명령어가 길면 중간에 잘립니다. 이때 --no-trunc 옵션을 붙이면 잘림 없이 전체 명령어를 확인할 수 있어 정확한 분석에 필수적입니다.

docker history --no-trunc my-app:latest


실전 사례: "범인은 chown이었다"

실제로 제가 겪었던 실화 하나 들려드릴게요. 150MB짜리 프로젝트 파일을 빌드했는데 이미지가 300MB가 넘게 나오는 기이한 현상이 있었습니다. 범인은 바로 아주 평범해 보이는 Dockerfile 두 줄이었죠.

[비효율적인 방법: 레이어 2개 생성]

# 1. 파일을 일단 복사 (기본적으로 root 소유로 복사됨)
COPY . .

# 2. 보안을 위해 소유권 변경 (별도 명령어로 실행)
RUN chown -R appuser:appgroup /app

이걸 빌드한 뒤 docker history로 확인해 보니 이런 결과가 나왔습니다.

IMAGE          CREATED BY                                        SIZE
<layer_id_2>   /bin/sh -c chown -R appuser:appgroup /app         150MB  <-- (문제의 지점!)
<layer_id_1>   /bin/sh -c #(nop) COPY dir:abc in /app            150MB

여기서 Docker 레이어의 무서운 점이 드러납니다. 1단계에서 150MB 파일을 복사하면 레이어 하나가 생깁니다. 그런데 2단계에서 chown을 실행하면, Docker는 "어? 파일 정보(소유권)가 바뀌었네? 그럼 바뀐 상태로 레이어 하나 더 만들어야지!"라며 기존 150MB를 그대로 복사해서 새로운 레이어를 쌓아버립니다.

결국, 내용물은 똑같은데 소유권만 다른 파일이 2중으로 저장되어 용량이 2배가 된 거죠.


해결은 한 줄 다이어트!

해결책은 간단합니다. 복사할 때 애초에 소유권을 지정해서 레이어를 하나로 합치면 끝입니다.

[효율적인 방법: 레이어 1개 생성]

# 복사와 동시에 소유권까지 지정!
COPY --chown=appuser:appgroup . .

Dockerfile을 이렇게 수정하고 다시 docker history를 찍어보면 결과가 드라마틱합니다.

IMAGE          CREATED BY                                               SIZE
<layer_id_1>   /bin/sh -c #(nop) COPY --chown=appuser... dir:abc       150MB

보이시나요? 단 하나의 레이어만 생성되었고, 이미지 용량은 다시 날씬하게 150MB로 돌아왔습니다. 명령어 두 줄을 한 줄로 합쳤을 뿐인데 용량이 절반이 된 거죠.


결론: 빌드 후엔 무조건 '히스토리' 체크!

Docker 이미지는 명령어 한 줄당 레이어 한 층이라는 사실을 잊지 마세요.

코드를 짜고 나서 테스트를 하듯, 빌드 후에는 습관적으로 docker history --no-trunc를 실행해 보세요. "이 apt-get은 왜 이렇게 무거워?", "이 레이어는 왜 굳이 나눴지?"라는 의문이 꼬리에 꼬리를 물다 보면, 어느새 아주 가볍고 효율적인 시스템을 구축하고 계실 겁니다.

불필요한 레이어는 시스템의 적이니까요!


도움이 되셨나요? 도움이 되셨으면 좋아요! 부탁드립니다.

관련글도 읽어보세요.

관련글

Docker 공유 메모리 (shm_size와 ipc) 완벽 이해하기

Docker: 네트워크 공유 없이 호스트 포트로 컨테이너 간 통신하기

도커 볼륨(Volume) 복사, ‘왜’ 그렇게 해야 할까?