본문 바로가기
빌드노트 검색

빌드노트

docker commit한 이미지에 볼륨 파일이 없는 이유

컨테이너에서 읽었던 파일이 docker commit 이미지에 없다면 Mounts와 파일 경로를 대조한다. 같은 경로의 일반 파일·볼륨 파일을 실제로 commit해 비교하고, 이미지와 마운트 데이터를 따로 보존해야 하는 이유를 설명한다.

컨테이너 안에서 읽었던 파일이 docker commit으로 만든 이미지에는 없을 수 있다. 그 파일이 볼륨에 있었다면 commit 실패부터 의심할 일이 아니다. commit은 마운트된 볼륨의 데이터를 이미지에 포함하지 않는다. 같은 컨테이너에서 보였더라도 일반 경로에 쓴 파일과 볼륨에 쓴 파일은 보존 대상이 다르다. Docker commit 공식 설명 (새 탭에서 열림)

Docker의 writable layer는 컨테이너마다 생기는 쓰기 가능한 파일 계층이다. 마운트 밖의 일반 파일 변경은 여기에 기록된다. 볼륨은 이 계층 밖에 데이터를 저장하지만, 컨테이너 안에서는 평범한 디렉터리처럼 보인다. ls나 cat으로 파일을 봤다는 사실만으로 이미지에 들어갈 파일이라고 판단할 수 없는 이유다. Docker 저장 구조 (새 탭에서 열림)

먼저 원래 컨테이너의 Mounts를 본다

사라진 파일의 경로를 알고 있다면 그 경로가 볼륨 안인지부터 확인한다. 다음은 PowerShell에서 원래 컨테이너의 마운트 종류·볼륨 이름·컨테이너 안의 연결 경로를 조회하는 명령이다. $c에는 자신의 컨테이너 이름이나 ID를 넣는다.

$c = '확인할-컨테이너-이름'
docker inspect --type container --format '{{range .Mounts}}{{println .Type .Name .Destination}}{{end}}' $c

별도로 만든 실습 컨테이너의 출력은 아래와 같았다. 긴 볼륨 이름만 lab-data로 축약했으며, volume과 /data는 실제 출력 그대로다.

volume lab-data /data

첫 값은 마운트 종류(Type), 두 번째는 볼륨 이름(Name), 마지막은 컨테이너 안의 연결 경로(Destination)다. 판단할 때는 파일 경로가 연결 경로 아래에 있는지 본다. 이 경우 /data/note.txt에 쓴 내용은 볼륨에 저장되므로 commit 이미지에 포함되지 않는다. 마운트가 겹치면 파일에 가장 구체적으로 적용되는 경로를 확인한다. Mounts 출력 해석 (새 탭에서 열림)

조회가 실패하면 컨테이너 이름과 Docker 연결부터 확인한다. 정상 조회의 출력이 비어 있거나 파일이 마운트 밖에 있다면, 이 결과만으로 누락 원인을 볼륨이라고 결론 내리지 않는다. Type이 bind 등 다른 종류인 경우도 아래 named volume 실험과 구분한다.

같은 컨테이너의 두 파일을 commit해 봤다

2026년 10월 23일 Docker Desktop 4.92.0, Docker Engine 29.8.0의 Linux/amd64 환경에서 합성 텍스트로 비교했다. Alpine 3.22.7 기반의 새 전용 이미지를 만들고, 네트워크를 none으로 지정한 컨테이너에 새 named volume 하나만 연결했다. 이미지에는 VOLUME 선언이 없었고, 두 파일은 실습에서 새로 만들었다.

/layer/note.txt에는 layer-file, 볼륨 경로인 /data/note.txt에는 volume-file을 썼다. commit 전에는 두 파일 모두 쓴 내용 그대로 읽혔다. 이 컨테이너를 commit한 이미지에서 볼륨을 연결하지 않은 새 컨테이너를 만들어 같은 두 경로를 조회했다. 실제 Mounts는 []였고, 파일 조회 출력은 다음과 같았다.

layer-file
missing-from-image

/layer/note.txt는 남았지만 /data/note.txt는 없었다. missing-from-image는 파일이 없을 때 실험용 셸이 출력한 표시이며 Docker 오류 메시지가 아니다. 같은 컨테이너에서 읽었다는 사실이 같은 저장 계층에 있었다는 뜻은 아니었다.

경로 이름 때문인지도 대조했다. 다른 새 컨테이너에서 볼륨 없이 같은 /data/note.txt에 unmounted-file을 쓴 뒤 commit했더니, 그 이미지의 새 컨테이너에서는 파일을 읽을 수 있었다. 두 조건의 차이는 /data라는 이름이 아니라 그 경로가 볼륨에 연결돼 있었는가였다.

원본 볼륨을 읽기 전용으로 다시 연결한 실습 컨테이너에서는 volume-file을 읽었다. 이미지에서 빠졌다는 관찰과 원본 볼륨에서 지워졌다는 판단은 다르다.

새 이미지에서 비교할 때도 마운트를 확인한다

이미 commit한 이미지를 조사한다면 먼저 자동으로 볼륨을 만드는 설정이 있는지 본다. $image에는 로컬에 있는 자신의 commit 이미지 태그를 넣는다.

$image = '자신의-이미지-이름:태그'
docker image inspect --format '{{json .Config.Volumes}}' $image

실습 결과는 null이었다. 이미지에 VOLUME 선언이 있으면 실행 명령에 --mount가 없어도 볼륨이 생길 수 있다. 따라서 실행 명령만 보고 “마운트 없이 확인했다”고 판단하지 않는다. Dockerfile VOLUME 설명 (새 탭에서 열림)

이 설정 조회는 파일 존재 여부를 검사하는 명령은 아니다. 파일을 읽어 비교할 때는 검사용 컨테이너의 실제 Mounts도 확인해야 한다. 같은 볼륨을 다시 연결했다면 이미지 밖의 데이터를 읽을 수 있고, 다른 볼륨이 연결됐다면 이미지의 파일을 가릴 수도 있다. 이번 실험은 자동 볼륨 선언이 없고 실제 마운트도 없는 조건에서 비교했다. 읽기 권한 오류나 검사 도구가 없는 오류는 파일 누락과 구별한다.

이미지와 볼륨을 따로 보존한다

필요한 파일이 볼륨 안에 있었다면 commit을 반복해도 그 데이터가 이미지로 따라오지 않는다. 원래 Mounts의 볼륨 이름과 연결 경로를 남기고, 이미지 보존과 별도로 볼륨 데이터의 백업·이관을 준비해야 한다. Docker 문서도 볼륨의 백업과 복원을 별도 절차로 설명한다. 볼륨 백업·복원 (새 탭에서 열림)

commit은 기본적으로 대상 컨테이너의 프로세스를 잠시 멈춰 이미지 생성 중 데이터 손상 가능성을 줄인다. 이 동작이 볼륨을 이미지에 포함시키지는 않는다. 이번 실험은 쓰기를 끝낸 텍스트 파일만 비교했으며 DB 백업이나 실행 중인 데이터의 정합성은 검증하지 않았다. DB를 보존하려면 해당 DB의 백업·복구 방식과 정합성 조건을 따로 확인해야 한다.

← 전체 글 보기