본문 바로가기
일반IT/리눅스

🐳 도커(Docker)의 내부를 파헤치다: Overlay2 파일 시스템 구조 완벽 분석

by gasbugs 2025. 12. 4.
반응형

안녕하세요! 오늘은 도커 컨테이너가 실제로 데이터를 어떻게 저장하고 관리하는지, 그 '마법' 같은 구조를 직접 눈으로 확인해보는 시간을 가져보려 합니다.

 

많은 분들이 컨테이너를 사용하지만, 실제 파일이 어디에, 어떻게 존재하는지 궁금해하십니다. 도커는 OverlayFS(Overlay Filesystem)라는 기술을 사용해 여러 개의 레이어를 마치 하나의 파일 시스템인 것처럼 합쳐서 보여줍니다.

 

오늘은 복잡한 이론 대신, 직접 명령어를 치면서 호스트 OS 관점에서 컨테이너의 내부 구조를 샅샅이 살펴보겠습니다. 준비되셨나요? 🚀


1. 실험 대상 준비: 컨테이너 실행 🏃‍♂️

가장 먼저 분석할 컨테이너를 하나 실행해 봅시다. 가볍고 빠른 nginx:alpine 이미지를 사용하겠습니다.

# Nginx 컨테이너 실행 (백그라운드 모드)
docker run -d -p 80:80 --name nx nginx:alpine

이제 Nginx가 격리된 환경에서 돌고 있습니다. 하지만 리눅스 커널 입장에서 이것은 그저 하나의 프로세스일 뿐입니다.


2. Overlay의 비밀 지도: Mountinfo 확인 🗺️

이제 가장 중요한 단계입니다! 이 프로세스가 보고 있는 파일 시스템이 실제로 어떻게 조립되어 있는지 /proc 파일 시스템을 통해 확인해 봅시다.

# 해당 마운트 정보에서 overlayfs 설정값 조회
mount | grep rootfs

출력 예시:

overlay on /var/lib/docker/rootfs/overlayfs/fea3c44e1dee873838bee303f32d739164f9a34e6a38b3c99ccc3c6e88f7e702 type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/9/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/8/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/7/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/5/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/4/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/3/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/2/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/1/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/10/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/10/work,nouserxattr)

이 명령어를 치면 꽤 긴 문자열이 나오는데, 여기서 핵심 키워드 4가지만 찾으면 됩니다.

  • 🔒 LowerDir (이미지 레이어): 읽기 전용(Read-Only)입니다. 우리가 다운로드 받은 nginx:alpine 이미지를 구성하는 여러 겹의 레이어들이 여기에 해당합니다. 절대 수정되지 않습니다.
  • ✏️ UpperDir (컨테이너 레이어): 쓰기 가능(Read-Write) 영역입니다. 여러분이 컨테이너 안에서 파일을 만들거나 수정하면, 실제로는 오직 이곳에만 저장됩니다.
  • ⚙️ WorkDir: OverlayFS가 파일 병합 작업을 위해 내부적으로 사용하는 임시 공간입니다.
  • 👀 Merged (통합 뷰): overlay on에 바로 뒤에 보이는 /var/lib/docker/rootfs/overlayfs/로 시작하는 경로입니다. 위 LowerDir와 UpperDir가 합쳐져서 우리 눈에 보이는 최종 결과물입니다. 컨테이너가 보는 / (루트) 디렉토리가 바로 이것입니다.

3. 호스트에서 컨테이너 내부로 '순간 이동' 하기 🚪

컨테이너 내부에 접속(docker exec)하지 않고도, 호스트에서 컨테이너의 파일들을 볼 수 있을까요? 네, 가능합니다! 리눅스 커널은 /proc 디렉토리에 뒷문을 만들어 두었습니다.

# 방법 1: 컨테이너 ID 통해 Merged 디렉토리 확인
ls -al /var/lib/docker/rootfs/overlayfs/$(docker inspect -f '{{.Id}}' nx)

# 방법 2: PID를 이용해 컨테이너의 RootFS로 바로 이동 (추천!)
ls -al /proc/$(docker inspect -f '{{.State.Pid}}' nx)/root/

 

/proc/[PID]/root/ 경로는 해당 프로세스가 보고 있는 루트 디렉토리로 연결되는 심볼릭 링크와 같습니다. 이곳에 들어가면 docker exec로 들어갔을 때와 똑같은 파일들이 보입니다. 신기하죠? ✨


4. 데이터 쓰기 실험 및 검증 🧪

정말 호스트에서 보는 뷰와 컨테이너가 보는 뷰가 연결되어 있을까요? 테스트를 위해 호스트에서 파일을 하나 만들어보겠습니다.

# 호스트에서 컨테이너의 Root 경로에 파일 생성
echo test1234 > /proc/$(docker inspect -f '{{.State.Pid}}' nx)/root/test.txt

 

이제 컨테이너 내부에서 확인해 보면, test.txt 파일이 짠 하고 나타나 있을 겁니다. 이 실험이 시사하는 바는 큽니다. 컨테이너 파일 시스템은 별도의 닫힌 공간이 아니라, 호스트 파일 시스템의 특정 경로를 조합해서 보여주는 것이라는 점이죠.


5. 내 파일은 실제로 어디에 있을까? 💾

방금 만든 test.txt 파일은 호스트의 하드디스크 어딘가에 물리적으로 존재해야 합니다. 과연 어디에 저장되었을까요?

# test.txt 파일의 실제 물리적 위치 찾기
find /var/lib/docker/rootfs/ -name test.txt

검색 결과를 보면 /var/lib/docker/overlay2/[해시값]/diff/test.txt 같은 경로가 나올 겁니다.

이 경로가 바로 앞서 3번 단계에서 확인했던 UpperDir의 경로와 일치합니다! 즉, "이미지(LowerDir)는 건드리지 않고, 변경된 사항은 모두 UpperDir에 별도로 저장한다"는 OverlayFS의 작동 원리를 직접 확인한 것입니다.


🎯 결론 및 요약

오늘 실습을 통해 우리는 다음과 같은 사실을 알게 되었습니다.

  1. 컨테이너는 마법 상자가 아니라, 리눅스 프로세스다.
  2. 컨테이너의 파일 시스템은 읽기 전용 이미지(Lower) 위에 쓰기 가능 레이어(Upper)를 얹어서 합친(Merged) 것이다.
  3. 컨테이너를 삭제하면 UpperDir가 삭제되므로, 그 안에 쓴 데이터도 함께 날아간다. (그래서 볼륨이 필요하다!)

이 원리를 이해하면 도커의 이미지 빌드 속도, 컨테이너 시작 속도가 왜 빠른지, 그리고 스토리지를 어떻게 관리해야 하는지 훨씬 더 잘 이해할 수 있습니다.

오늘도 즐거운 컨테이너 항해 되세요! ⛵️


반응형