VM vs 컨테이너
서버 한 대에서 여러 애플리케이션을 서로 방해하지 않게 돌리려면 격리가 필요합니다. 오랫동안 쓰인 방법이 가상 머신(VM)입니다. 하이퍼바이저가 하드웨어를 가상화해 가상의 컴퓨터를 여러 대 만들고, 각 가상 컴퓨터에 게스트 운영체제를 따로 설치해 실행합니다. 격리는 강하지만 앱마다 운영체제 한 벌을 통째로 띄우는 비용이 듭니다. 컨테이너는 다른 접근입니다. 운영체제를 새로 띄우지 않고, 호스트의 커널을 공유한 채 프로세스를 격리해 마치 독립된 환경처럼 보이게 합니다. 게스트 운영체제가 없어서 가볍고 빠르게 시작합니다.
컨테이너는 앱과 그 실행에 필요한 라이브러리, 설정을 이미지로 묶어 어디서나 같은 환경으로 실행하게 해 주어 배포와 확장에 널리 쓰입니다. 대신 호스트 커널을 공유하므로 격리 경계가 VM보다 얇고, 호스트와 같은 종류의 커널 위에서만 돌 수 있습니다. 이 토픽에서는 두 방식이 쌓이는 층의 차이, 자원과 시작 시간의 차이, 격리 경계의 차이를 봅니다.
핵심 개념
가상 머신
하이퍼바이저가 만든 가상 하드웨어 위에서 게스트 운영체제가 통째로 실행되는 방식입니다. 게스트마다 자기 커널을 가지므로 호스트와 다른 종류의 운영체제도 실행할 수 있습니다.
핵심 개념
하이퍼바이저
하드웨어 자원을 여러 가상 머신에 나누어 주고 서로 격리하는 소프트웨어입니다. VMware ESXi, KVM, Hyper-V, Xen 등이 있습니다.
핵심 개념
컨테이너
호스트 운영체제의 커널을 공유하면서 프로세스를 격리해 실행하는 방식입니다. 컨테이너 안의 프로세스는 호스트에서 보면 일반 프로세스이며, 격리는 커널의 기능으로 만들어집니다.
핵심 개념
컨테이너 이미지
앱과 실행에 필요한 파일을 묶은 읽기 전용 템플릿입니다. 여러 층(레이어)으로 이뤄져 공통 층을 컨테이너끼리 재사용하고, 이미지로부터 컨테이너를 실행합니다.
핵심 개념
커널 공유의 의미
컨테이너는 게스트 운영체제를 부팅하지 않으므로 시작이 빠르고 메모리와 디스크를 적게 씁니다. 반대로 호스트 커널이 곧 모든 컨테이너의 커널이라 호스트와 다른 종류의 커널은 쓸 수 없습니다.
핵심 개념
격리의 강도
VM은 게스트 커널과 하이퍼바이저가 경계를 이루고, 컨테이너는 공유하는 커널의 격리 기능이 경계입니다. 커널의 취약점은 컨테이너에서 더 넓은 영향을 줄 수 있어 보안이 중요하면 둘을 함께 쓰기도 합니다.
가상화와 컨테이너의 배경
서버 가상화는 한 대의 물리 서버를 여러 대처럼 쓰려는 필요에서 널리 퍼졌고, 하이퍼바이저가 그 기반입니다. 이후 리눅스 커널에 격리 기능(네임스페이스)과 자원 제한 기능(cgroups)이 갖춰지면서 프로세스 수준의 격리가 가능해졌고, 이를 쉽게 쓰게 해 주는 도구(예: Docker)가 나오면서 컨테이너가 널리 쓰이게 되었습니다. 컨테이너 이미지와 런타임의 형식은 OCI(Open Container Initiative) 표준으로 정리되어 있습니다.
숫자로 확인하기
자주 하는 오해
면접에서 이렇게 물어요
면접 질문
VM과 컨테이너의 차이는?
VM은 하이퍼바이저 위에 게스트 운영체제를 통째로 실행하고, 컨테이너는 호스트 커널을 공유하며 프로세스 단위로 격리합니다. 컨테이너가 가볍고 빠르지만 격리 경계는 더 얇습니다.
면접 질문
컨테이너가 가벼운 이유는?
각 컨테이너가 게스트 운영체제를 따로 띄우지 않고 호스트 커널을 공유하기 때문입니다. 운영체제 부팅과 상주 비용이 없습니다.
면접 질문
컨테이너의 격리가 약하다고 하는 이유는?
모든 컨테이너가 호스트 커널을 공유해서 커널 취약점이 악용되면 여러 컨테이너와 호스트에 영향을 줄 수 있기 때문입니다. VM은 게스트마다 커널이 분리되어 경계가 더 강합니다.
면접 질문
컨테이너 이미지는 왜 레이어로 이루어졌나요?
변경된 부분만 새 레이어로 쌓고 공통 레이어는 이미지와 컨테이너가 재사용해, 저장 공간과 내려받는 시간을 줄이고 빌드를 캐시할 수 있게 하려는 설계입니다.
실제 시스템에서는
함께 보면 좋은 토픽
참고 자료
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)보다 가벼운 주된 이유는?
Q2
가상 머신을 만들고 관리하는 소프트웨어(또는 펌웨어 계층)를 무엇이라 부를까?
Q3
컨테이너의 격리 수준이 VM보다 상대적으로 약하다고 평가되는 이유는?