Network & Server Factory

개인 공부 기록

DevOps/Docker

[Docker] 이미지와 레이어 정리

1nfra 2026. 9. 28. 15:32
이미지는 컨테이너를 만드는 읽기 전용 틀이고, 여러 레이어를 겹쳐 만든 파일시스템입니다. 이 글에서는 레이어가 어떻게 쌓이고 공유되는지, 컨테이너가 파일을 바꿀 때 무슨 일이 일어나는지, 이미지 이름의 태그와 digest가 어떻게 다른지 정리합니다.

컨테이너부터 Kubernetes까지 시리즈 2편입니다. 이전 글은 [Docker] 컨테이너 개념 정리이고, 전체 순서는 시리즈 목차에 있습니다.

1. 이미지와 컨테이너

이미지는 앱을 실행하는 데 필요한 파일과 실행 설정(어떤 명령으로 시작할지, 어떤 환경 변수를 쓸지)을 담은 읽기 전용 묶음입니다. 컨테이너는 이 이미지로 만든 실행 중인 인스턴스입니다. 붕어빵 틀 하나로 붕어빵을 여러 개 굽듯이, 이미지 하나로 컨테이너를 여러 개 띄울 수 있습니다.

 

항목 이미지 컨테이너
상태 읽기 전용, 바뀌지 않음 실행 중이거나 멈춘 인스턴스
구성 레이어 여러 개 + 실행 설정 이미지 + 쓰기 계층 하나
만드는 방법 docker build, docker pull docker run, docker create
목록 확인 docker image ls docker ps -a

2. 레이어 구조

이미지는 파일 변경 내역을 한 장씩 겹친 레이어로 이루어집니다. 투명 필름을 여러 장 겹쳐 보면 위에서 한 장의 그림으로 보이는 것처럼, 레이어를 위에서 합쳐 본 모습이 컨테이너의 파일시스템이 됩니다. Dockerfile의 RUN, COPY 같은 명령이 각각 레이어 하나를 만듭니다.

두 컨테이너는 이미지 레이어를 함께 읽고, 바뀐 내용은 각자의 쓰기 계층에만 남깁니다

 

컨테이너가 이미지의 파일을 고치면 그 파일을 쓰기 계층으로 복사한 뒤 고칩니다(Copy-on-Write). 그래서 같은 이미지로 컨테이너를 100개 띄워도 이미지 레이어는 디스크에 한 벌만 있고, 컨테이너마다 바뀐 부분만 따로 저장됩니다. 대신 쓰기 계층은 컨테이너를 지우면 같이 사라집니다.

 

레이어는 이미지끼리도 공유합니다. 같은 베이스 이미지로 만든 이미지 두 개를 받을 때 이미 있는 레이어는 다시 받지 않고 건너뜁니다. 반대로 한번 만든 레이어는 바뀌지 않으므로, 앞 레이어에서 추가한 큰 파일을 뒤 레이어에서 지워도 이미지 크기는 줄지 않습니다. 이 점은 3편의 Dockerfile 작성에서 중요합니다.

3. 이미지 이름, 태그, digest

이미지 이름은 어느 레지스트리의 어느 저장소에 있는 어떤 버전인지를 한 줄로 나타냅니다. 우리가 흔히 쓰는 nginx는 앞뒤가 생략된 짧은 이름입니다.

생략한 부분은 Docker Hub(docker.io), 공식 이미지 네임스페이스(library), latest 태그로 채워집니다

 

구분 예 특징
Tag nginx:alpine, demo-api:v1.3.0 사람이 붙인 이름
같은 태그를 다른 이미지로 옮길 수 있음
Digest nginx@sha256:4c0a… 이미지 내용으로 계산한 값
내용이 같으면 항상 같고, 바뀌지 않음
latest nginx:latest 특별한 의미가 없는 기본 태그
무엇이 최신인지 보장하지 않음

 

태그는 책갈피처럼 옮겨 꽂을 수 있어서, 같은 nginx:alpine이라도 오늘 받은 것과 한 달 뒤 받은 것이 다를 수 있습니다. 운영 환경에서는 버전이 들어간 태그를 쓰고, 완전히 같은 이미지를 보장해야 하면 digest로 지정합니다. 사설 레지스트리에 올리는 방법은 [Azure] Azure Container Registry 사용법 정리에서 다뤘습니다.

4. 직접 해 보기

이미지를 받아 레이어와 digest를 확인합니다.

docker pull nginx:alpine
docker image ls nginx
docker image history nginx:alpine
docker image inspect nginx:alpine --format '{{.RepoDigests}}'

docker image history는 위에서부터 최근 레이어 순으로, 각 레이어를 만든 명령과 크기를 보여 줍니다. 크기가 0B인 줄은 파일은 바꾸지 않고 CMD나 ENV 같은 설정만 기록한 것입니다. 마지막 명령은 nginx@sha256: 로 시작하는 digest를 출력합니다.

 

Docker Engine 29부터는 새로 설치하면 containerd 이미지 저장소가 기본값입니다. 이 저장소는 압축된 레이어와 압축을 푼 레이어를 함께 보관하기 때문에, docker image ls에 보이는 크기와 실제 디스크 사용량이 이전 버전과 다르게 나올 수 있습니다. 이전 버전에서 업그레이드한 경우는 설정을 바꾸기 전까지 기존 저장소(overlay2)를 그대로 씁니다.

 

이번에는 컨테이너의 쓰기 계층을 확인합니다.

docker run -d --name web nginx:alpine
docker exec web sh -c 'echo hello > /usr/share/nginx/html/test.txt'
docker diff web

docker diff는 이미지와 비교해 쓰기 계층에서 바뀐 경로를 보여 줍니다. A는 추가, C는 변경, D는 삭제이고, 방금 만든 test.txt가 A로 나옵니다. docker rm -f web으로 지운 뒤 같은 이미지로 새 컨테이너를 띄우면 test.txt는 없습니다. 이 쓰기 계층을 새 이미지로 굳히는 명령이 docker commit이고, 방법은 [Docker] docker commit으로 이미지 만들고 삭제에 정리했습니다. 다만 무엇을 바꿨는지 기록이 남지 않아서 이미지는 Dockerfile로 만드는 것이 기본입니다.

5. 운영 시 주의점

항목 조치
latest 태그 언제 받느냐에 따라 다른 이미지가 될 수 있음
버전 태그를 쓰고, 필요하면 digest로 고정
큰 파일 삭제 뒤 레이어에서 지워도 앞 레이어에 남아 크기가 줄지 않음
설치와 정리를 같은 RUN에서 처리
비밀 정보 이미지에 넣은 비밀번호는 레이어에 남아 누구나 꺼낼 수 있음
빌드 secret이나 실행 시 주입 사용
디스크 사용량 containerd 저장소는 압축본과 푼 레이어를 함께 저장해 이전보다 디스크를 더 씀
docker image prune으로 쓰지 않는 이미지 정리
CPU 아키텍처 Apple Silicon(arm64)과 서버(amd64)는 다른 이미지가 필요
공식 이미지는 대부분 둘 다 제공하고, 직접 만든 이미지는 --platform 확인

6. 정리

  • 이미지는 읽기 전용 레이어를 겹친 틀이고, 컨테이너는 그 위에 쓰기 계층 하나를 더한 실행 인스턴스입니다.
  • 레이어는 이미지와 컨테이너끼리 공유되고, 한번 만든 레이어는 바뀌지 않아 뒤에서 지워도 크기가 줄지 않습니다.
  • 태그는 옮길 수 있는 이름이고 digest는 내용 자체를 가리키므로, 운영에서는 버전 태그나 digest를 씁니다.

다음 글 3편에서는 Dockerfile로 이미지를 직접 만들고, 멀티 스테이지 빌드로 크기를 줄이는 방법을 다룹니다.

참고

728x90
서울
--:--:--
-전체 글
-카테고리
오늘 방문