🐳

Docker 컨테이너의 내부 구조

Linux 네임스페이스부터 macOS 지원, GPU까지 — 10년간의 기술적 진화

Docker가 해결한 근본 문제는 단순하다. 같은 머신에서 서로 다른 라이브러리 버전을 요구하는 앱을 동시에 실행하는 것.

VM으로 해결할 수 있지만 커널·파일시스템·캐시가 전부 중복돼서 무겁다. Docker는 Linux 네임스페이스를 써서 VM 없이 격리를 달성했다.

네임스페이스 — 핵심 메커니즘

네임스페이스는 프로세스마다 파일시스템, 네트워크, PID 등 시스템 리소스의 "뷰"를 분리하는 커널 기능이다. 두 프로세스가 같은 /etc/passwd를 요청해도 실제로는 다른 파일을 본다.

2001년 마운트 네임스페이스부터 시작해서 2007년 네트워크 네임스페이스까지, 총 7가지 유형이 점진적으로 추가되었다. Docker의 기여는 이 저수준 기능들을 개발자가 쓸 수 있는 형태로 포장한 것이다.

이미지 — 레이어드 파일시스템

docker build는 Dockerfile의 각 명령을 실행하고, 그 결과로 생긴 파일시스템 차이를 레이어로 쌓는다. 콘텐츠 주소 지정(content-addressable) 스토리지에 저장되므로 같은 레이어는 중복 저장하지 않는다.

overlayfs, btrfs, ZFS 같은 copy-on-write 파일시스템 위에서 동작한다.

컨테이너 실행 — containerd가 하는 일

docker run 호출 시 containerd가 네임스페이스를 동적으로 설정한다:

cgroups — CPU·메모리 등 리소스 제한
네트워크 네임스페이스 — 컨테이너 내부 포트를 호스트 포트로 재매핑
스토리지 볼륨 — 호스트 파일시스템의 영구 저장소 연결
PID 네임스페이스 — 프로세스 트리 격리
사용자 네임스페이스 — 컨테이너 내 UID를 호스트의 다른 UID로 매핑

네임스페이스 구성에 약간의 오버헤드가 있지만 VM 스폰보다 훨씬 가볍다. 대부분 1초 미만이면 컨테이너가 뜬다.

macOS 지원 — 역발상 아키텍처

Docker 이미지는 Linux 커널에서만 동작한다. macOS/Windows 개발자를 위해 Docker는 하이퍼바이저를 앱 안에 내장하는 방식을 택했다.

HyperKit — Intel CPU의 하드웨어 가상화 확장을 이용해 일반 사용자 프로세스에서 Linux 커널을 실행하는 라이브러리 VMM이다. 유니커널 연구에서 영감을 받았다.

LinuxKit — Docker 실행에 필요한 최소 컴포넌트만 포함한 커스텀 Linux 배포판. 모든 컴포넌트가 컨테이너 내부에서 실행되고, 부팅 시 루트 네임스페이스에는 아무것도 돌아가지 않는다.

HyperKit + LinuxKit 조합으로 네이티브 macOS 프로세스와 거의 같은 속도로 Linux 프로세스를 부팅한다.

네트워킹 — SLIRP 해결책

내장 Linux에서 macOS로의 네트워킹이 예상외로 어려웠다. 기업 방화벽이 컨테이너 트래픽을 악성으로 탐지하는 바람에 베타에서 수천 건의 버그 리포트가 쏟아졌다.

해결책이 재밌다. 1990년대 Palm Pilot을 인터넷에 연결하는 데 쓰인 SLIRP를 재활용했다. OCaml로 작성된 사용자 공간 TCP/IP 스택(vpnkit)이 Linux 네트워킹 요청을 macOS 네이티브 소켓 콜로 변환한다.

VPN 정책 관점에서 나가는 트래픽이 Docker 앱에서 발생한 것으로 인식되니 방화벽 문제가 사라졌다. vpnkit 배포 후 기업 사용자의 버그 리포트가 99% 이상 감소했다.

GPU 지원 — CDI

AI 워크로드가 부상하면서 GPU 의존성 관리가 새 과제다. GPU 워크로드는 정확히 일치하는 커널 드라이버와 사용자 공간 라이브러리가 필요한데, 컨테이너들이 단일 커널을 공유하니 Docker가 원래 해결하려던 것과 같은 충돌이 발생한다.

2023년부터 CDI(Container Device Interface)를 지원한다. 컨테이너 시작 시 GPU 장치 파일과 전용 동적 라이브러리를 바인드 마운트하는 방식이다. 같은 GPU 벤더 내에서는 이식성이 보장되지만, Nvidia GPU용 앱이 Apple M시리즈에서 돌아가는 건 아직 먼 이야기다.

동작 흐름

1

Dockerfile 작성 → docker build로 레이어드 파일시스템 이미지 생성

2

docker run 호출 → containerd가 네임스페이스(mount, network, PID, user)를 동적 설정

3

cgroups로 CPU·메모리 리소스 제한, 볼륨 마운트로 영구 스토리지 연결

4

macOS/Windows: HyperKit(라이브러리 VMM) + LinuxKit(최소 Linux)이 앱 내부에서 Linux 커널 실행

5

vpnkit(SLIRP)이 Linux 네트워킹을 호스트 OS 소켓 콜로 변환 → 방화벽 문제 해결

6

컨테이너 종료 시 Linux 커널이 일반 프로세스처럼 가비지 컬렉션

장점

  • VM 대비 극도로 가볍다 — 대부분 1초 미만 기동
  • 레이어드 이미지로 효율적 중복 제거와 빌드 캐싱
  • OCI 표준으로 벤더 락인 없이 다양한 런타임에서 실행 가능
  • macOS/Windows에서도 Linux 컨테이너가 "그냥 동작"

단점

  • GPU 워크로드에서 벤더 간 이식성이 부족하다
  • macOS/Windows에서는 내부적으로 VM이 돌아가므로 순수 Linux 대비 오버헤드 존재
  • AI 시대에 이미지 크기가 기하급수적으로 커지는 중 — torch 하나로 수 GB
  • 네임스페이스 격리는 VM 수준의 보안 격리가 아니다

사용 사례

개발 환경 통일 — "내 컴퓨터에서는 되는데" 문제 해결 CI/CD 파이프라인 — 빌드·테스트·배포를 동일 이미지로 마이크로서비스 — 서비스별 독립 배포와 스케일링 AI/ML 워크로드 — GPU 의존성 포함 환경 패키징