커널을 공유하면서 격리된 실행 환경을 만드는 기술.
가상 머신과의 차이
[가상 머신] [컨테이너]
앱 · 라이브러리 · 게스트 OS 커널 앱 · 라이브러리
하이퍼바이저 컨테이너 런타임
호스트 OS · 하드웨어 호스트 OS 커널 · 하드웨어
-
VM — 커널까지 통째로 가상화한다
- 격리가 강하다. 다른 OS 도 돌릴 수 있다
- 무겁다 (수 GB · 부팅 수십 초)
-
컨테이너 — 커널을 공유하고 프로세스만 격리한다
- 가볍다 (수십 MB · 시작 수백 ms)
- 격리가 약하다. 호스트와 같은 커널이어야 한다
컨테이너는 "가벼운 VM"이 아니라 격리된 프로세스다 — 이 문장이 대부분의 오해를 정리한다.
두 축
namespace — 무엇이 '보이는가' 를 가른다
pid 프로세스 목록 (컨테이너 안에서는 자기 것만 보인다. 자기가 PID 1)
net 네트워크 인터페이스 · 라우팅 · 포트
mnt 마운트된 파일 시스템
uts 호스트명
ipc 프로세스 간 통신
user UID/GID 매핑 (안에서는 root, 밖에서는 일반 사용자)
cgroup — 얼마나 '쓸 수 있는가' 를 가른다
- CPU · 메모리 · 디스크 I/O · 네트워크 대역
ls -l /proc/<pid>/ns/ # 이 프로세스의 네임스페이스
cat /sys/fs/cgroup/memory.max # cgroup v2 메모리 한도
lsns # 네임스페이스 목록
실무에서 부딪히는 지점
-
① 컨테이너 메모리 한도는 cgroup 이다
- 호스트에 메모리가 남아도 cgroup 한도를 넘으면 OOMKilled 된다
- 런타임이 이 한도를 인식하는지 확인해야 한다
-
② 앱이 PID 1 이 된다
- 좀비를 거둘 init 이 없고, 시그널 기본 동작이 다르다
- --init 을 쓰거나 tini 같은 최소 init 을 넣는다
-
③ 코어 수도 cgroup 으로 제한된다
- nproc 은 호스트 코어를 보여 주지만 실제로 쓸 수 있는 건 quota 만큼이다
- 스레드 풀 크기를 호스트 코어 수로 잡으면 과도해진다
cat /sys/fs/cgroup/cpu.max # "200000 100000" = 코어 2개 분량
격리가 약하다는 뜻
커널을 공유하므로 커널 취약점 하나가 모든 컨테이너를 뚫을 수 있다
보완
- 비특권 컨테이너 (user namespace 로 root 를 매핑)
- seccomp 로 쓸 수 있는 시스템 콜을 줄인다
- 강한 격리가 필요하면 gVisor · Kata Containers (경량 VM 을 끼운다)
면접 함정
- ❌ "컨테이너는 가벼운 VM" → 커널을 공유하는 격리된 프로세스다.
- ❌ "컨테이너 안의 root는 안전하다" → user namespace를 안 쓰면 호스트 root와 같은 UID다.
이미지 레이어
이미지는 읽기 전용 레이어의 겹침이다
- 베이스 OS → 런타임 설치 → 앱 복사 → ...
컨테이너를 띄우면 맨 위에 쓰기 가능한 얇은 레이어가 얹힌다
- 파일을 수정하면 아래 레이어에서 복사해 위로 올린다 (copy-on-write)
- 그래서 같은 베이스를 쓰는 컨테이너 100개가 베이스를 공유한다
큰 파일을 자주 수정하는 워크로드는 이 복사 때문에 느리다
- 볼륨을 마운트해 레이어 밖에서 다루는 것이 정석
진단
# 컨테이너가 실제로 받은 자원 한도
cat /sys/fs/cgroup/memory.max # cgroup v2
cat /sys/fs/cgroup/cpu.max
cat /sys/fs/cgroup/memory.events # oom_kill 횟수 ← 재시작 원인 확인
# 네임스페이스가 정말 분리됐는지
sudo nsenter -t <pid> -n ip addr # 그 컨테이너의 네트워크 네임스페이스로 들어가 본다
왜 컨테이너가 빠른가
부팅할 커널이 없다 — 프로세스를 하나 띄우는 것과 같다 이미지 레이어를 공유한다 — 디스크와 페이지 캐시를 아낀다 하이퍼바이저 계층이 없다 — I/O 와 시스템 콜에 중간 단계가 없다
대가는 격리 강도다. 커널을 공유하므로 커널 취약점에 함께 노출된다