1. 개요

“컨테이너는 가벼운 VM 이다” 라는 설명을 자주 본다. 틀린 말은 아니지만 이 비유 때문에 “그럼 컨테이너 안에서도 커널을 새로 부팅하나?” 같은 오해가 생긴다. 결론부터 말하면 컨테이너는 VM 과 격리를 만드는 층 자체가 다르다. 이번 시리즈에서는 인프라를 다루며 당연히 쓰지만 원리는 잘 안 짚어보는 개념들을 8편에 걸쳐 정리한다. 1편은 그중에서도 가장 기본인 컨테이너와 VM 의 차이다.


2. 핵심 내용

2-1. VM: 하드웨어를 가상화한다

VM 은 하이퍼바이저(KVM, Hyper-V 등)가 CPU, 메모리, 디스크 같은 하드웨어 자원을 흉내 내서 여러 개의 “가짜 컴퓨터”를 만드는 방식이다. 각 VM 은 자기만의 커널을 갖고 완전히 독립적으로 부팅한다. 그래서 격리 수준은 높지만, VM 하나를 띄우려면 커널이 부팅하는 시간(보통 수십 초)과 커널 자체가 쓰는 메모리(수백 MB)가 고정비로 들어간다.

2-2. 컨테이너: 커널은 하나, 보이는 것만 다르다

컨테이너는 하이퍼바이저도, 별도 커널도 없다. 호스트 커널을 그대로 공유하면서, 리눅스 커널의 네임스페이스(namespace) 기능으로 프로세스가 “보는 세계”를 분리한다. 네임스페이스 종류는 여러 개다.

  • PID — 컨테이너 안에서는 자기 프로세스가 PID 1 이다. 호스트에는 다른 PID 로 보인다.
  • NET — 컨테이너마다 독립된 네트워크 인터페이스, 라우팅 테이블, 포트 공간을 가진다.
  • MNT — 파일시스템 마운트 지점이 분리된다. 컨테이너가 / 를 봐도 실제로는 이미지 레이어 위다.
  • UTS — 호스트명이 분리된다.
  • IPC, USER — 프로세스 간 통신 채널과 UID/GID 매핑이 분리된다.

즉 컨테이너 안 프로세스는 자기가 독립된 머신에서 돌고 있다고 “착각”하지만, 실제로는 호스트 커널 위에서 도는 일반 프로세스다. ps aux 를 호스트에서 치면 컨테이너 프로세스들이 그냥 보인다.

2-3. cgroup: 얼마나 쓸 수 있는지 제한한다

네임스페이스가 “무엇이 보이는가” 를 결정한다면, cgroup(control group) 은 “얼마나 쓸 수 있는가” 를 결정한다. CPU 코어 수, 메모리 상한, 디스크 I/O 대역폭 같은 자원에 상한선을 긋는다. 쿠버네티스 매니페스트에 쓰는 resources.limits.memory 가 바로 이 cgroup 설정으로 변환된다. 메모리 제한을 넘기면 OOM killer 가 그 cgroup 안의 프로세스를 죽인다. VM 이었다면 게스트 OS 안에서 스왑을 쓰거나 멈추는 식으로 반응했겠지만, 컨테이너는 커널이 훨씬 직접적으로 개입한다.

2-4. 그래서 실무에서 뭐가 달라지나

  • 부팅이 없다: 새 프로세스를 fork/exec 하는 수준의 비용이라 컨테이너는 초 단위가 아니라 밀리초~초 단위로 뜬다.
  • 커널 취약점을 공유한다: 호스트 커널에 구멍이 있으면 모든 컨테이너가 영향권이다. VM 은 하이퍼바이저 탈출이 훨씬 어렵다. 그래서 신뢰할 수 없는 코드를 완전히 격리하려면 gVisor, Kata Containers 처럼 VM 수준 격리를 흉내 낸 런타임을 쓰기도 한다.
  • 이미지는 레이어의 합이다. MNT 네임스페이스 덕분에 여러 컨테이너가 같은 베이스 이미지 레이어를 읽기 전용으로 공유하고, 컨테이너별로 얇은 쓰기 레이어만 따로 갖는다. 이게 이미지 크기와 배포 속도에 직결된다.

3. 마무리

요약

  • VM 은 하이퍼바이저가 하드웨어를 가상화하고, 컨테이너는 커널을 공유하며 네임스페이스로 “보이는 것”만 분리한다.
  • cgroup 은 네임스페이스와 별개로 “쓸 수 있는 자원”의 상한을 긋는다. 쿠버네티스 리소스 제한이 여기로 이어진다.
  • 컨테이너는 부팅이 없어 가볍지만, 커널을 공유하는 만큼 VM 보다 격리 경계가 얇다.

다음은 2편: 리버스 프록시는 왜 필요한가 다.