Docker 컨테이너의 격리는 마법이 아니라, 리눅스 커널의 namespace와 cgroup이라는 두 기능의 조합입니다. 이 두 가지를 이해하면 컨테이너의 실체가 보입니다.


핵심 개념

PLAINTEXT
컨테이너 = namespace(격리) + cgroup(자원 제한) + rootfs(파일 시스템)

namespace: "뭘 볼 수 있는가" 제한
cgroup:    "얼마나 쓸 수 있는가" 제한

Namespace (이름공간)

프로세스가 시스템 자원의 독립된 뷰 를 갖도록 합니다.

Namespace격리 대상플래그
PID프로세스 IDCLONE_NEWPID
Network네트워크 스택CLONE_NEWNET
Mount파일 시스템 마운트CLONE_NEWNS
UTS호스트네임CLONE_NEWUTS
IPCIPC 자원CLONE_NEWIPC
UserUID/GIDCLONE_NEWUSER
Cgroupcgroup 뷰CLONE_NEWCGROUP
Time시스템 시간CLONE_NEWTIME

PID Namespace

PLAINTEXT
호스트:               컨테이너 A:        컨테이너 B:
PID 1 (systemd)      PID 1 (nginx)     PID 1 (java)
PID 2 (...)          PID 2 (worker)    PID 2 (...)
...
PID 1234 (nginx)     ← 호스트에서는 PID 1234
PID 5678 (java)                        ← 호스트에서는 PID 5678

컨테이너 내부에서 ps aux를 치면 PID 1부터 시작하는 독립된 프로세스 트리를 봅니다.

Network Namespace

PLAINTEXT
호스트:  eth0 (192.168.1.10)

         veth pair (가상 이더넷)

컨테이너: eth0 (172.17.0.2)  ← 독립된 네트워크 스택

각 컨테이너는 독립된 IP, 라우팅 테이블, iptables 규칙을 가집니다.

Namespace 실습

BASH
# 새 네트워크 namespace 생성
sudo ip netns add myns

# namespace 안에서 명령 실행
sudo ip netns exec myns ip addr    # 독립된 네트워크 인터페이스

# 프로세스의 namespace 확인
ls -la /proc/self/ns/

# unshare로 새 namespace에서 프로세스 실행
sudo unshare --pid --fork --mount-proc bash
# 이 셸 안에서 ps aux를 치면 bash만 보임

Cgroup (Control Group)

프로세스 그룹의 자원 사용량을 제한하고 모니터링 합니다.

제어 가능한 자원

컨트롤러제어 대상
cpuCPU 시간 할당
memory메모리 사용 제한
io (blkio)디스크 I/O 대역폭
pids최대 프로세스 수
cpuset특정 CPU 코어 할당

cgroup v2 실습

BASH
# cgroup v2 마운트 확인
mount | grep cgroup2

# 새 cgroup 생성
sudo mkdir /sys/fs/cgroup/mygroup

# 메모리 제한 설정 (100MB)
echo 104857600 > /sys/fs/cgroup/mygroup/memory.max

# CPU 제한 (50%)
echo "50000 100000" > /sys/fs/cgroup/mygroup/cpu.max

# 프로세스를 cgroup에 추가
echo $PID > /sys/fs/cgroup/mygroup/cgroup.procs

# 현재 메모리 사용량 확인
cat /sys/fs/cgroup/mygroup/memory.current

Docker에서의 cgroup

BASH
# Docker 컨테이너의 메모리/CPU 제한
docker run --memory=512m --cpus=1.5 nginx

# 내부적으로 cgroup이 생성됨
ls /sys/fs/cgroup/system.slice/docker-<container_id>.scope/

Docker 컨테이너의 전체 구조

PLAINTEXT
docker run 실행 시:

1. 이미지에서 rootfs 준비 (OverlayFS)
2. Namespace 생성:
   - PID namespace: 독립된 프로세스 트리
   - Network namespace: 독립된 네트워크 (veth pair + bridge)
   - Mount namespace: 독립된 파일 시스템 뷰
   - UTS namespace: 독립된 호스트네임
   - IPC namespace: 독립된 IPC
3. Cgroup 설정:
   - CPU, 메모리, I/O 제한 적용
4. 프로세스 실행:
   - 격리된 환경에서 PID 1로 시작

핵심 포인트

  • 컨테이너가 VM이 아닌 이유: 커널을 공유함 — namespace로 뷰를 격리할 뿐 별도 커널이 아님
  • namespace vs cgroup: namespace는 "보이는 범위", cgroup은 "쓸 수 있는 양"
  • cgroup의 OOM: 메모리 제한 초과 시 cgroup 내 프로세스가 OOM Kill됨
  • Docker는 리눅스 전용인가: 핵심 기술(namespace, cgroup)이 리눅스 전용 — Windows/Mac에서는 VM 위에서 실행

정리

namespace와 cgroup은 컨테이너 기술의 핵심입니다. Docker, Kubernetes, containerd 모두 이 두 커널 기능 위에 구축되어 있습니다. "Docker는 내부적으로 어떻게 격리하나요?"에 대해에 대한 답이 바로 namespace + cgroup입니다.

댓글 로딩 중...