Docker Internals Deep Dive: docker run을 실행할 때 실제로 일어나는 일 (2025 Edition)

발행: (2025년 12월 16일 오후 12:10 GMT+9)
15 min read
원문: Dev.to

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 ComponentAirport RoleReal‑World Impact
Docker CLIPassenger Terminaldocker run 명령 입력, 상태 확인
dockerdAirport Operations Center모든 비행, 게이트, 스케줄 관리
containerdGround Control짐(이미지) 적재, 활주로 할당
containerd‑shimGate Agents운영 센터가 재시작돼도 비행기가 준비된 상태 유지
runcPilot실제로 비행기를 조종(컨테이너 실행)
KernelAir Traffic Control공역(리소스) 관리, 충돌 방지
ContainerThe Actual Flight격리된 공역에서 실행되는 애플리케이션

문제 해결 시 구성 요소 간 관계를 기억하기 위해 이 모델을 활용하세요.

2. 실행 흐름: docker run -d -p 8080:80 nginx

StepDescription
1. CLI → dockerdCLI가 명령을 파싱하고 JSON 페이로드를 생성한 뒤 Unix 소켓을 통해 전송합니다.
2. dockerd Validation구성을 검증하고 로컬 이미지를 확인하며 컨테이너 생성을 조정합니다.
3. Image Pull (if needed)containerd가 레지스트리 인증, 매니페스트 해석, 레이어 다운로드 및 검증을 처리하고 레이어를 콘텐츠 스토어에 저장합니다.
4. Filesystem Assemblycontainerd가 스냅샷을 준비하고 OverlayFS 상/하위 레이아웃을 생성하며 메타데이터와 런타임 구성을 포함한 OCI 번들을 만듭니다.
5. Networking Setupdockerd가 네트워크 네임스페이스를 구성합니다:
• veth 페어를 생성합니다 (호스트 쪽은 docker0에 연결)
• 컨테이너 IP를 할당합니다 (예: 172.17.0.2)
• 포트 매핑을 위해 iptables DNAT 규칙을 추가합니다
• 외부 트래픽을 위한 MASQUERADE 규칙을 추가합니다
6. containerd → containerd‑shimcontainerd가 shim을 생성하고 OCI 사양을 전달하며 라이프사이클 감독을 위임합니다.
7. shim → runcrunc가 네임스페이스를 생성하고 rootfs를 마운트하며 cgroup 제한을 적용하고 컨테이너 엔트리포인트를 실행한 뒤 종료합니다 (shim은 남아 있습니다).
8. Container Running컨테이너가 격리된 Linux 프로세스로 실행됩니다:
• Shim이 라이프사이클을 유지합니다
dockerd가 로그를 스트리밍하고 상태를 보고합니다
• 커널이 격리를 적용합니다

Docker workflow

3. 구성 요소 책임

ComponentRoleDelegates To
CLI사용자 인터페이스, 요청 생성dockerd
dockerdAPI, 오케스트레이션, 네트워킹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 오버라이드를 검사합니다.

Debugging tree

6. 요약

docker run 호출은 체계적이고 모듈화된 실행 경로를 따라 이동합니다. 각 구성 요소는 작고 명확히 정의된 책임을 받아 다음 단계로 깔끔하게 넘겨 주어 예측 가능한 제어 흐름을 형성합니다:

  • Dockerd는 의도를 파싱하고 이를 런타임 명령으로 변환합니다.
  • Containerd는 안정적인 gRPC API를 통해 컨테이너 수명 주기를 조정합니다.
  • containerd‑shim은 데몬 재시작 시에도 컨테이너의 프로세스 관리를 격리합니다.
  • runc는 OCI Runtime Spec을 리눅스 기본 요소로 구현합니다.
  • 커널은 네임스페이스, cgroup, 파일시스템 드라이버를 통해 최종 강제 적용 계층을 제공합니다.

이러한 경계는 오픈 표준(REST → gRPC → OCI Spec → syscalls)으로 관리되어 호환성, 신뢰성 및 레이어 간 깊은 가시성을 보장합니다. 격리, 자원 관리, 성능 효율성은 모두 네이티브 리눅스 구조에서 직접 파생되며, 숨겨진 하이퍼바이저나 추가 추상화가 없습니다.

운영 참고 사항

프로세스 소유권이 containerd‑shim에 위임되기 때문에 dockerdcontainerd를 재시작해도 실행 중인 컨테이너가 중단되지 않습니다. 이 설계는 안전한 데몬 업그레이드, 노드 유지보수 및 워크로드를 중단하지 않는 고가용성 작업 흐름을 지원합니다.


빠른 참고

  • 핵심 아키텍처 – 실행 흐름 → 구성 요소 책임
  • 핵심 정리 – 디버깅 가이드 (운영 준비 버전)
  • 디버깅 트리 – 컨테이너 즉시 종료 → 시작 지연 → 네트워크 문제 → 일반 오류 패턴 → 복구 조치
  • 요약 – 모듈식 스택에 대한 고수준 정리
Back to Blog

관련 글

더 보기 »