본문 바로가기

DevOps/Docker

Docker

Docker는 전통적인 하이퍼바이저 기반 가상머신(VM)과 달리, 리눅스 커널이 제공하는 다양한 기능을 조합해 호스트 커널을 공유하면서도 독립된 프로세스 환경을 제공하는 경량 컨테이너 플랫폼이다. OS 수준의 가상화(OS-level virtualization)라고 부르며, 프로세스 격리와 자원 제어만으로 빠르고 효율적인 애플리케이션 배포·운영을 가능케 한다.


컨테이너 vs VM

  가상머신 (VM) 컨테이너(Docker)
커널 각 VM마다 별도 커널과 OS 호스트 커널을 공유
가동 시간 수십 초 이상 (부팅 필요) 수 밀리초~수 초 (프로세스로 실행)
오버헤드 메모리·디스크·CPU 오버헤드 큼 최소한의 사용자 공간 레이어만 추가
격리 수준 꽉 막힌 격리 네임스페이스·Cgroups 기반 격리

컨테이너는 결국 “독립된 프로세스”이므로, VM과 달리 오버헤드 없이 즉시 실행할 수 있다.

Docker를 가능하게 한 핵심 리눅스 기술

1. 네임스페이스 (Namespace)

리눅스 커널이 프로세스별로 보이는 리소스 영역(Resource View)을 분리한다. Docker는 여러 네임스페이스를 결합해 컨테이너 격리를 구현한다.

네임스페이스 종류 설명
PID  프로세스 ID 분리 (컨테이너 안은 1번 PID부터 시작)
Mount  파일 시스템 분리 (루트 디렉토리 / 분리)
Network  네트워크 인터페이스(IP 주소, 포트 등) 격리
IPC  프로세스 간 통신 리소스 분리
UTS  호스트명(Hostname)과 도메인명 분리
User UID/GID 맵핑으로 비권한 사용자 환경 제공

 

👉 이 덕분에, 컨테이너 안에서는 자신만의 프로세스, 네트워크, 파일 시스템을 가진 것처럼 보인다.

2. 컨트롤 그룹 (Cgroup)

프로세스 그룹별로 CPU, 메모리, 블록 I/O, 네트워크 대역폭 등을 제한·계량·격리한다.

  • CPU 제한: --cpus=".5" (전체 CPU의 50% 사용)
  • 메모리 제한: -m 256m (256MB 상한)
  • 블록 I/O 제한: --device-write-bps, --device-read-bps
  • Cgroup v2: 단일 계층 구조로 간단해진 리소스 관리
docker run --rm --cpus=".5" -m 256m nginx

 

 

👉 그래서 하나의 컨테이너가 서버 자원을 독점하는 상황을 방지하고, 여러 컨테이너가 자원을 공정하게 나눠 쓸 수 있게 한다.

3. 유니온 파일 시스템(OverlayFS)

Copy-on-Write 기반의 다중 레이어 파일 시스템으로, 베이스 이미지 레이어는 읽기 전용으로 유지하고 컨테이너의 변경사항만 별도 레이어에 기록한다.

  1. Lower (읽기 전용): 베이스 이미지 레이어
  2. Upper (쓰기 가능): 실행 중 생성된 변경사항
  3. Work (작업 디렉토리): 오버레이 동작에 필요한 임시 디렉토리
mount -t overlay overlay \
  -o lowerdir=/image/base,upperdir=/container/diff,workdir=/container/work \
  /container/rootfs

 

 

👉 파일시스템 복사 없이도 이미지 공유와 빠른 컨테이너 생성이 가능하다.

4 루트 파일시스템 분리: chroot, pivot_root

  • chroot: 프로세스의 루트 디렉토리를 변경하지만, 네임스페이스 없이 우회 가능
  • pivot_root: 마운트 네임스페이스 내에서 전체 파일시스템을 교체해 더 견고한 격리 제공

Docker는 내부적으로 pivot_root를 사용해 컨테이너마다 완전 분리된 루트 파일시스템을 구성한다.

컨테이너 런타임의 진화: libcontainer → containerd → runc

  1. libcontainer (Docker v1.0): 리눅스 네임스페이스·Cgroups를 직접 다루는 Go 라이브러리
  2. containerd (추출된 런타임): libcontainer 기반으로 컨테이너 라이프사이클(생성·실행·종료) 관리
  3. runc (OCI 표준 런타임): containerd가 호출하는 최소 실행 바이너리 (libcontainer → OCI 호환)