Docker Internals Deep Dive: docker run을 실행할 때 실제로 일어나는 일 (2025 Edition)
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, I’ll keep the source link unchanged and translate the rest into Korean while preserving all formatting and technical terms.
현대 컨테이너 플랫폼 개요
현대 컨테이너 플랫폼은 예측 가능하고 모듈식인 동작에 의존합니다. Docker의 아키텍처는 표준 인터페이스 — REST, gRPC, OCI Runtime, 그리고 Linux‑kernel 프리미티브를 중심으로 구축된 계층형 실행 파이프라인입니다. 이 흐름을 이해하면 디버깅, 확장, 또는 오케스트레이션 시스템과의 통합 시 모호함을 없앨 수 있습니다.
1. Core Architecture
CLI → dockerd (API + Orchestration) → containerd (Runtime mgmt)
→ containerd‑shim (Process supervisor) → runc (OCI runtime)
→ Linux Kernel (Namespaces, cgroups, fs, net)
Docker CLI
- 사용자에게 제공되는 명령 인터페이스
- 플래그를 JSON으로 변환
/var/run/docker.sock을 통해 dockerd와 통신
dockerd
- REST API 서버
- 컨테이너 수명 주기 오케스트레이션
- 네트워크 및 볼륨 관리
- 이미지와 런타임 작업을 containerd에 위임
containerd
- 고수준 런타임 관리자
- 스냅샷, 이미지, 컨텐츠 스토어 관리
- 레이어를 풀/압축 해제하고 OCI 런타임 사양을 생성
- 각 컨테이너마다
containerd‑shim을 실행
Image Storage Detail
- 각 레이어는 SHA‑256 해시를 이용해 콘텐츠 주소화
- 동일한 레이어는 중복 저장되지 않음(중복 제거)
- OverlayFS는 하드링크를 사용하므로 레이어가 컨테이너 간에 공유됨
containerd‑shim
- 컨테이너 워크로드의 부모 프로세스
- dockerd/
containerd가 재시작되더라도 컨테이너를 살아 있게 유지 - I/O 스트림(로그, attach) 관리
- 종료 코드를
containerd에 반환
runc
- OCI 런타임 사양을 구현
- 네임스페이스 생성, cgroup 제한 적용, 루트 파일시스템 마운트, 엔트리포인트 실행
- 컨테이너 생성 직후 즉시 종료(shim이 계속 살아 있음)
Linux Kernel
- 프로세스 격리(네임스페이스) 강제
- 리소스 제어(cgroup) 관리
- 계층형 파일시스템(OverlayFS) 제공
- 네트워킹(veth 페어, 브리지, iptables/NAT) 처리
✈️ The Airport Analogy – A Mental Model
| Docker Component | Airport Role | Real‑World Impact |
|---|---|---|
| Docker CLI | Passenger Terminal | docker run 명령 입력, 상태 확인 |
| dockerd | Airport Operations Center | 모든 비행, 게이트, 스케줄 관리 |
| containerd | Ground Control | 짐(이미지) 적재, 활주로 할당 |
| containerd‑shim | Gate Agents | 운영 센터가 재시작돼도 비행기가 준비된 상태 유지 |
| runc | Pilot | 실제로 비행기를 조종(컨테이너 실행) |
| Kernel | Air Traffic Control | 공역(리소스) 관리, 충돌 방지 |
| Container | The Actual Flight | 격리된 공역에서 실행되는 애플리케이션 |
문제 해결 시 구성 요소 간 관계를 기억하기 위해 이 모델을 활용하세요.
2. 실행 흐름: docker run -d -p 8080:80 nginx
| Step | Description |
|---|---|
| 1. CLI → dockerd | CLI가 명령을 파싱하고 JSON 페이로드를 생성한 뒤 Unix 소켓을 통해 전송합니다. |
| 2. dockerd Validation | 구성을 검증하고 로컬 이미지를 확인하며 컨테이너 생성을 조정합니다. |
| 3. Image Pull (if needed) | containerd가 레지스트리 인증, 매니페스트 해석, 레이어 다운로드 및 검증을 처리하고 레이어를 콘텐츠 스토어에 저장합니다. |
| 4. Filesystem Assembly | containerd가 스냅샷을 준비하고 OverlayFS 상/하위 레이아웃을 생성하며 메타데이터와 런타임 구성을 포함한 OCI 번들을 만듭니다. |
| 5. Networking Setup | dockerd가 네트워크 네임스페이스를 구성합니다:• veth 페어를 생성합니다 (호스트 쪽은 docker0에 연결)• 컨테이너 IP를 할당합니다 (예: 172.17.0.2)• 포트 매핑을 위해 iptables DNAT 규칙을 추가합니다 • 외부 트래픽을 위한 MASQUERADE 규칙을 추가합니다 |
| 6. containerd → containerd‑shim | containerd가 shim을 생성하고 OCI 사양을 전달하며 라이프사이클 감독을 위임합니다. |
| 7. shim → runc | runc가 네임스페이스를 생성하고 rootfs를 마운트하며 cgroup 제한을 적용하고 컨테이너 엔트리포인트를 실행한 뒤 종료합니다 (shim은 남아 있습니다). |
| 8. Container Running | 컨테이너가 격리된 Linux 프로세스로 실행됩니다: • Shim이 라이프사이클을 유지합니다 • dockerd가 로그를 스트리밍하고 상태를 보고합니다• 커널이 격리를 적용합니다 |

3. 구성 요소 책임
| Component | Role | Delegates To |
|---|---|---|
| CLI | 사용자 인터페이스, 요청 생성 | dockerd |
| dockerd | API, 오케스트레이션, 네트워킹 | containerd |
| containerd | 이미지 관리, 스냅샷, 라이프사이클 | runc |
| containerd‑shim | 컨테이너 프로세스 감독 | Kernel (via namespaces created by runc) |
| runc | 컨테이너 환경 생성 | Kernel |
| Kernel | 격리 + 자원 제어 | Hardware |
Related Architecture (Kubernetes)
dockerd → kubelet → CRI → containerd
하위 단계(containerd → shim → runc → kernel)는 변경되지 않습니다.
4. Key Clarifications
- 컨테이너는 프로세스이며, 가상 머신이 아닙니다.
runc는 상주하지 않으며, 쉼이 컨테이너의 수명 주기를 관리합니다.- Docker의 레이어드 파일시스템은 copy‑on‑write이며, 효율적인 저장을 가능하게 합니다.
- Kubernetes는
dockerd를 제거하고containerd와 직접 통신하여 더 간단한 CRI 파이프라인을 구현합니다. - Live‑restore는 쉼이 컨테이너를
dockerd와 분리하기 때문에 작동합니다.
Source:
5. 디버깅 가이드 (Ops‑Ready Edition)
컨테이너 장애를 진단하기 위한 구조화된 계층적 순서. SRE, DevOps, 런타임 엔지니어링 팀을 위해 설계되었습니다.
컨테이너가 즉시 종료됨
접근법: 가장 높은 계층(애플리케이션)부터 가장 낮은 계층(커널)까지 순차적으로 확인합니다.
1. 애플리케이션 계층
심각도: 낮음 – 대부분의 실패는 여기서 시작됩니다.
docker logs <container>
크래시, 누락된 바이너리, 잘못된 엔트리포인트 등을 로그에서 확인합니다.
2. Shim / 런타임 계층
- shim이 살아 있는지 확인:
ps -ef | grep containerd-shim runc종료 상태 확인:docker inspect --format='{{.State.ExitCode}}' <container>
3. Containerd 계층
- containerd 로그 확인:
journalctl -u containerd에서 스냅샷 또는 OCI‑spec 오류를 찾습니다.
4. Dockerd 계층
- Docker 데몬 로그 확인:
journalctl -u docker에서 API‑레벨 거부나 네트워크 설정 실패를 찾습니다.
5. 커널 계층
- 네임스페이스 생성 확인:
lsns또는ip netns list - cgroup 제한 확인:
cat /sys/fs/cgroup/.../memory.max
이 계층별 체크리스트를 활용해 실패가 발생하는 정확한 단계를 파악한 뒤, 적절한 수정을 적용하세요.
Docker 런타임 문제 디버깅
대상: 런타임 예외, 크래시 루프, 누락된 설정, 엔트리포인트 실패 등.
런타임 계층 (containerd / OCI)
심각도: 중간 – 문제는 컨테이너 생성에 영향을 주며, 애플리케이션 로직에는 직접적인 영향을 주지 않습니다.
journalctl -u containerd
감지 항목:
- 잘못된 OCI 스펙
- 스냅샷 / 언팩 오류
- 권한 문제
- 이미지 메타데이터 실패
커널 계층
심각도: 높음 – 커널 오류는 노드의 전체 컨테이너에 영향을 미칩니다.
dmesg | tail -20
드러나는 내용:
- 네임스페이스 생성 실패
- cgroup 적용 오류
- LSM 차단(AppArmor / SELinux)
- OverlayFS 마운트 문제
컨테이너 시작 지연
레지스트리, 스토리지, 런타임 중 어느 부분에서 지연이 발생하는지 파악합니다.
이미지 풀 / 언팩 지연
journalctl -u containerd --since "2 minutes ago" | grep -Ei "pull|unpack"
느린 원격 풀, 레이어 언팩 지연, 압축 해제 문제 등을 찾습니다.
호스트 스토리지 병목
iostat -dx 1 /var/lib/containerd
감지 항목:
- 높은 I/O 대기시간
- OverlayFS 백엔드 포화
- 느린 디스크 또는 과부하된 볼륨
레지스트리 / 네트워크 지연
time docker pull alpine:latest
측정 내용:
- 왕복 지연 시간
- 다운로드 처리량
- 레지스트리 인증 또는 프록시 지연
네트워크 문제
호스트 → 브리지 → 컨테이너 연결을 추적합니다.
NAT / 포트 포워드 규칙 확인
sudo iptables -t nat -L DOCKER -n -v
브리지 및 veth 토폴로지
ip addr show docker0
brctl show
컨테이너 네임스페이스 네트워킹
docker exec <container> ip addr show
흔히 나타나는 오류 패턴
| 오류 메시지 | 가능 원인 |
|---|---|
no such file or directory | 엔트리포인트 누락 또는 잘못된 작업 디렉터리 |
permission denied | 사용자 네임스페이스 제한, 볼륨 권한 문제 |
address already in use | 호스트 포트 충돌 |
exec format error | 아키텍처 불일치(예: amd64 vs arm64) |
layer does not exist | 이미지 저장소 손상, 부분적인 풀 |
failed to setup network namespace | 커널에 필요한 기능이 부족 |
복구 조치
이미지 풀 실패
- 레지스트리 인증 토큰을 확인합니다.
- 프록시 / SSL 구성을 검증합니다.
- 레지스트리 엔드포인트에 대한 연결을 테스트합니다.
OCI 사양 / 런타임 오류
- Docker, containerd, runc 버전이 호환되는지 확인합니다.
- 사용자 정의 seccomp 또는 AppArmor 프로파일을 검증합니다.
- 손상된 스냅샷을 재생성합니다.
커널 네임스페이스 / Cgroup 실패
- 커널 버전이 필요한 기능을 지원하는지 확인합니다.
- cgroup v1 vs. v2 모드를 검증합니다.
- 네임스페이스에 영향을 주는
sysctl오버라이드를 검사합니다.

6. 요약
docker run 호출은 체계적이고 모듈화된 실행 경로를 따라 이동합니다. 각 구성 요소는 작고 명확히 정의된 책임을 받아 다음 단계로 깔끔하게 넘겨 주어 예측 가능한 제어 흐름을 형성합니다:
- Dockerd는 의도를 파싱하고 이를 런타임 명령으로 변환합니다.
- Containerd는 안정적인 gRPC API를 통해 컨테이너 수명 주기를 조정합니다.
- containerd‑shim은 데몬 재시작 시에도 컨테이너의 프로세스 관리를 격리합니다.
- runc는 OCI Runtime Spec을 리눅스 기본 요소로 구현합니다.
- 커널은 네임스페이스, cgroup, 파일시스템 드라이버를 통해 최종 강제 적용 계층을 제공합니다.
이러한 경계는 오픈 표준(REST → gRPC → OCI Spec → syscalls)으로 관리되어 호환성, 신뢰성 및 레이어 간 깊은 가시성을 보장합니다. 격리, 자원 관리, 성능 효율성은 모두 네이티브 리눅스 구조에서 직접 파생되며, 숨겨진 하이퍼바이저나 추가 추상화가 없습니다.
운영 참고 사항
프로세스 소유권이 containerd‑shim에 위임되기 때문에 dockerd와 containerd를 재시작해도 실행 중인 컨테이너가 중단되지 않습니다. 이 설계는 안전한 데몬 업그레이드, 노드 유지보수 및 워크로드를 중단하지 않는 고가용성 작업 흐름을 지원합니다.
빠른 참고
- 핵심 아키텍처 – 실행 흐름 → 구성 요소 책임
- 핵심 정리 – 디버깅 가이드 (운영 준비 버전)
- 디버깅 트리 – 컨테이너 즉시 종료 → 시작 지연 → 네트워크 문제 → 일반 오류 패턴 → 복구 조치
- 요약 – 모듈식 스택에 대한 고수준 정리