컴퓨터 구조 운영체제 네트워크 자료구조 알고리즘 데이터베이스 내 학습
os · 15

VM vs 컨테이너

Docker가상화컨테이너

서버 한 대에서 여러 애플리케이션을 서로 방해하지 않게 돌리려면 격리가 필요합니다. 오랫동안 쓰인 방법이 가상 머신(VM)입니다. 하이퍼바이저가 하드웨어를 가상화해 가상의 컴퓨터를 여러 대 만들고, 각 가상 컴퓨터에 게스트 운영체제를 따로 설치해 실행합니다. 격리는 강하지만 앱마다 운영체제 한 벌을 통째로 띄우는 비용이 듭니다. 컨테이너는 다른 접근입니다. 운영체제를 새로 띄우지 않고, 호스트의 커널을 공유한 채 프로세스를 격리해 마치 독립된 환경처럼 보이게 합니다. 게스트 운영체제가 없어서 가볍고 빠르게 시작합니다.

컨테이너는 앱과 그 실행에 필요한 라이브러리, 설정을 이미지로 묶어 어디서나 같은 환경으로 실행하게 해 주어 배포와 확장에 널리 쓰입니다. 대신 호스트 커널을 공유하므로 격리 경계가 VM보다 얇고, 호스트와 같은 종류의 커널 위에서만 돌 수 있습니다. 이 토픽에서는 두 방식이 쌓이는 층의 차이, 자원과 시작 시간의 차이, 격리 경계의 차이를 봅니다.

핵심 개념

가상 머신

하이퍼바이저가 만든 가상 하드웨어 위에서 게스트 운영체제가 통째로 실행되는 방식입니다. 게스트마다 자기 커널을 가지므로 호스트와 다른 종류의 운영체제도 실행할 수 있습니다.

핵심 개념

하이퍼바이저

하드웨어 자원을 여러 가상 머신에 나누어 주고 서로 격리하는 소프트웨어입니다. VMware ESXi, KVM, Hyper-V, Xen 등이 있습니다.

핵심 개념

컨테이너

호스트 운영체제의 커널을 공유하면서 프로세스를 격리해 실행하는 방식입니다. 컨테이너 안의 프로세스는 호스트에서 보면 일반 프로세스이며, 격리는 커널의 기능으로 만들어집니다.

핵심 개념

컨테이너 이미지

앱과 실행에 필요한 파일을 묶은 읽기 전용 템플릿입니다. 여러 층(레이어)으로 이뤄져 공통 층을 컨테이너끼리 재사용하고, 이미지로부터 컨테이너를 실행합니다.

핵심 개념

커널 공유의 의미

컨테이너는 게스트 운영체제를 부팅하지 않으므로 시작이 빠르고 메모리와 디스크를 적게 씁니다. 반대로 호스트 커널이 곧 모든 컨테이너의 커널이라 호스트와 다른 종류의 커널은 쓸 수 없습니다.

핵심 개념

격리의 강도

VM은 게스트 커널과 하이퍼바이저가 경계를 이루고, 컨테이너는 공유하는 커널의 격리 기능이 경계입니다. 커널의 취약점은 컨테이너에서 더 넓은 영향을 줄 수 있어 보안이 중요하면 둘을 함께 쓰기도 합니다.

VM은 컴퓨터를, 컨테이너는 프로세스를 격리합니다 — VM은 하드웨어 수준에서 컴퓨터 전체를 가상화하고, 컨테이너는 운영체제 수준에서 프로세스의 시야와 자원을 격리합니다.
컨테이너가 가벼운 이유는 게스트 OS가 없기 때문입니다 — 운영체제를 부팅하고 상주시키는 비용이 사라져 시작이 빠르고 같은 서버에 더 많이 올릴 수 있습니다.
격리 경계가 다릅니다 — 컨테이너는 호스트 커널을 공유해 커널 취약점의 영향이 여러 컨테이너에 미칠 수 있고, VM은 게스트마다 커널이 분리됩니다.
어느 쪽이 낫다기보다 용도가 다릅니다 — 다른 운영체제나 강한 격리가 필요하면 VM, 같은 커널 위에서 빠르게 배포하고 확장하려면 컨테이너가 알맞습니다.
이 시각화에서 확인할 것 — "구조 비교" 탭에서 두 방식이 쌓이는 층과 커널 수를, "자원과 시작" 탭에서 자원 차이를, "격리의 경계" 탭에서 커널 취약점이 미치는 범위를 STEP으로 확인하세요.

가상화와 컨테이너의 배경

서버 가상화는 한 대의 물리 서버를 여러 대처럼 쓰려는 필요에서 널리 퍼졌고, 하이퍼바이저가 그 기반입니다. 이후 리눅스 커널에 격리 기능(네임스페이스)과 자원 제한 기능(cgroups)이 갖춰지면서 프로세스 수준의 격리가 가능해졌고, 이를 쉽게 쓰게 해 주는 도구(예: Docker)가 나오면서 컨테이너가 널리 쓰이게 되었습니다. 컨테이너 이미지와 런타임의 형식은 OCI(Open Container Initiative) 표준으로 정리되어 있습니다.

숫자로 확인하기

커널 수 — 앱 3개를 VM으로 격리하면 게스트 커널이 3개 더 생기고, 컨테이너로 격리하면 호스트 커널 하나를 공유해 추가 커널이 0개입니다.
자원 비교(가정값) — 게스트 운영체제를 1,024MB, 앱을 100MB로 가정하면 앱 3개는 VM에서 3 × 1,124 = 3,372MB, 컨테이너에서 3 × 100 = 300MB입니다. 실제 크기는 환경마다 다릅니다.
시작 시간(상대 단위, 가정) — VM은 게스트 운영체제를 부팅해야 해서 30, 컨테이너는 프로세스를 시작하면 되어 1로 가정해 차이를 보입니다.

자주 하는 오해

컨테이너는 작은 VM이다 — 컨테이너에는 게스트 운영체제가 없습니다. 호스트 커널 위에서 격리된 프로세스로 실행됩니다.
컨테이너는 어떤 운영체제 이미지든 실행한다 — 호스트 커널을 쓰므로 리눅스 컨테이너는 리눅스 커널 위에서 돌아갑니다. 윈도우나 맥에서 리눅스 컨테이너를 쓰는 도구는 내부에 리눅스 VM을 둡니다.
컨테이너는 VM보다 항상 안전하다 또는 위험하다 — 격리 경계가 다를 뿐입니다. 설정과 권한, 커널 업데이트에 따라 안전성이 달라지고, 강한 격리가 필요하면 둘을 함께 쓰는 구성도 있습니다.
컨테이너를 쓰면 성능 손실이 없다 — 격리 기능의 비용은 작지만 공유 자원 경쟁과 자원 제한 설정에 따라 성능이 달라질 수 있습니다.

면접에서 이렇게 물어요

면접 질문

VM과 컨테이너의 차이는?

VM은 하이퍼바이저 위에 게스트 운영체제를 통째로 실행하고, 컨테이너는 호스트 커널을 공유하며 프로세스 단위로 격리합니다. 컨테이너가 가볍고 빠르지만 격리 경계는 더 얇습니다.

면접 질문

컨테이너가 가벼운 이유는?

각 컨테이너가 게스트 운영체제를 따로 띄우지 않고 호스트 커널을 공유하기 때문입니다. 운영체제 부팅과 상주 비용이 없습니다.

면접 질문

컨테이너의 격리가 약하다고 하는 이유는?

모든 컨테이너가 호스트 커널을 공유해서 커널 취약점이 악용되면 여러 컨테이너와 호스트에 영향을 줄 수 있기 때문입니다. VM은 게스트마다 커널이 분리되어 경계가 더 강합니다.

면접 질문

컨테이너 이미지는 왜 레이어로 이루어졌나요?

변경된 부분만 새 레이어로 쌓고 공통 레이어는 이미지와 컨테이너가 재사용해, 저장 공간과 내려받는 시간을 줄이고 빌드를 캐시할 수 있게 하려는 설계입니다.

실제 시스템에서는

Docker — Docker 문서는 컨테이너를 격리된 프로세스로 설명하고 모든 컨테이너가 같은 커널을 공유한다고 설명합니다. 윈도우와 맥의 Docker Desktop은 리눅스 컨테이너를 위해 내부에서 리눅스 VM을 사용합니다.
마이크로 VM — AWS의 Firecracker는 컨테이너처럼 빠르게 시작하면서 VM의 격리를 얻으려는 마이크로 VM이며, AWS Lambda와 Fargate에 쓰인다고 공개되어 있습니다.
윈도우 컨테이너 — 마이크로소프트 문서는 윈도우 컨테이너에 호스트 커널을 공유하는 프로세스 격리와, 컨테이너마다 가벼운 VM을 쓰는 Hyper-V 격리를 구분합니다.
오케스트레이션 — 쿠버네티스는 여러 서버에 걸쳐 컨테이너를 배치하고 관리합니다.

함께 보면 좋은 토픽

프로세스 — 컨테이너가 격리하는 대상인 프로세스가 무엇인지 봅니다.
가상 메모리 — 하드웨어와 운영체제가 주소 공간을 격리하는 기본 원리를 봅니다.
시스템 콜 — 컨테이너 안의 프로세스도 호스트 커널의 시스템 콜을 호출함을 봅니다.
메모리 관리 — 컨테이너의 메모리 제한이 걸리는 바탕을 봅니다.

참고 자료

마이크로소프트 — Hyper-V isolation for containers
교재 — Silberschatz 외, "Operating System Concepts"의 가상화 장

Dockerfile — 스프링 부트 앱을 컨테이너 이미지로

FROM eclipse-temurin:21-jre
WORKDIR /app
COPY build/libs/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

파일을 바꾸는 명령(RUN, COPY 등)이 이미지의 층(레이어)을 만들고, EXPOSE나 ENTRYPOINT 같은 설정 명령은 메타데이터만 바꿉니다. FROM이 자바 실행 환경이 담긴 기반 이미지의 층을 가져오고, COPY가 앱 jar를 한 층으로 얹습니다. 기반 이미지에는 앱이 필요로 하는 사용자 공간의 파일과 라이브러리가 들어 있고, 게스트 운영체제 커널을 따로 담지 않습니다. 컨테이너는 실행할 때 호스트의 커널을 그대로 씁니다. 자주 바뀌는 앱 jar를 뒤쪽 층에 두면 기반 층은 캐시와 재사용이 되어 빌드와 내려받기가 빨라집니다.

셸 — 호스트와 컨테이너의 커널 비교, 자원 제한

# 리눅스 호스트에서 호스트와 컨테이너의 커널 버전이 같다
uname -r
docker run --rm alpine uname -r

# 컨테이너에 메모리와 CPU 상한을 걸어 실행 (cgroups 이용)
docker run -d --name web --memory 512m --cpus 1 nginx

# 사용량 확인
docker stats --no-stream web

alpine 컨테이너 안에서 uname -r을 실행하면 호스트와 같은 커널 버전이 나옵니다. 컨테이너에는 자기 커널이 없고 호스트 커널을 쓰기 때문입니다. VM이라면 게스트 안에서 uname -r이 게스트 운영체제의 커널 버전을 보여 주므로 호스트와 다를 수 있습니다. 윈도우나 맥의 Docker Desktop에서는 내부 리눅스 VM의 커널이 나옵니다. --memory와 --cpus는 컨테이너가 쓸 수 있는 자원의 상한을 정하며, 리눅스에서는 cgroups 기능으로 구현됩니다.

셸 — 이미지 레이어와 크기, 시작 시간 관찰

# 이미지가 어떤 레이어로 이뤄졌는지
docker history nginx

# 내려받은 이미지 목록과 크기
docker image ls

# 컨테이너 하나를 띄우고 끝날 때까지 걸리는 시간
time docker run --rm alpine echo hello

docker history는 이미지를 이룬 레이어를 순서대로 보여 줍니다. 같은 기반 이미지를 쓰는 이미지끼리는 공통 레이어를 한 번만 저장하므로 저장 공간이 절약됩니다. time으로 컨테이너 하나를 띄워 끝낼 때까지 재 보면 게스트 운영체제를 부팅하는 VM에 비해 시작이 빠르다는 것을 체감할 수 있습니다. 이미지를 처음 내려받을 때는 그 시간이 더해지므로 두 번째 실행부터 비교하는 것이 좋습니다. 측정값은 하드웨어와 이미지, 도커 설정에 따라 크게 달라지므로 절대 수치보다 상대적인 차이를 봅니다.

Q1

컨테이너가 가상 머신(VM)보다 가벼운 주된 이유는?

VM은 컴퓨터 전체를 흉내 내지만 컨테이너는 프로세스를 격리합니다.
VM은 하이퍼바이저 위에 게스트 OS까지 통째로 실행하지만, 컨테이너는 호스트 커널을 공유하면서 프로세스 단위로 격리하므로 시작이 빠르고 자원을 적게 씁니다.

Q2

가상 머신을 만들고 관리하는 소프트웨어(또는 펌웨어 계층)를 무엇이라 부를까?

"감독자" 라는 의미의 이름을 가졌습니다.
하이퍼바이저는 하드웨어 자원을 여러 가상 머신에 나누어 주고 서로 격리시키는 소프트웨어입니다. VMware, KVM, Hyper-V 등이 대표적입니다.

Q3

컨테이너의 격리 수준이 VM보다 상대적으로 약하다고 평가되는 이유는?

컨테이너들이 같은 것을 함께 쓰고 있습니다.
컨테이너는 호스트 커널을 공유하므로 커널의 취약점이 악용되면 다른 컨테이너까지 영향을 받을 수 있습니다. VM은 게스트마다 커널이 분리되어 있어 격리 경계가 더 강합니다.