컨테이너 vs 가상머신 — Docker, Kubernetes, 그리고 왜 컨테이너인가

2026. 3. 19. 17:23·개발
반응형

컨테이너 vs 가상머신 — Docker, Kubernetes, 그리고 왜 컨테이너인가

핵심 정리

가상머신(VM)의 구조

┌───────────┐ ┌───────────┐ ┌───────────┐
│   App A   │ │   App B   │ │   App C   │
├───────────┤ ├───────────┤ ├───────────┤
│ Guest OS  │ │ Guest OS  │ │ Guest OS  │  ← 각각 완전한 OS
│ (Ubuntu)  │ │ (CentOS)  │ │ (Debian)  │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
      └──────────────┼──────────────┘
              ┌──────┴──────┐
              │ Hypervisor  │  ← 하드웨어 가상화
              │(KVM/VMware) │
              ├─────────────┤
              │  Host OS    │
              ├─────────────┤
              │  Hardware   │
              └─────────────┘
  • 각 VM마다 완전한 OS 커널을 포함 (수백 MB ~ 수 GB)
  • Hypervisor가 하드웨어를 에뮬레이션
  • 부팅 시간: 수십 초 ~ 분 단위
  • 강한 격리: 별도의 커널이므로 보안 경계가 명확

컨테이너(Container)의 구조

┌───────────┐ ┌───────────┐ ┌───────────┐
│   App A   │ │   App B   │ │   App C   │
├───────────┤ ├───────────┤ ├───────────┤
│  Libs/Bins│ │  Libs/Bins│ │  Libs/Bins│  ← 라이브러리만 포함
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
      └──────────────┼──────────────┘
              ┌──────┴──────┐
              │Container    │
              │Runtime      │  ← Docker/containerd
              │(runc)       │
              ├─────────────┤
              │ Host OS     │
              │ (커널 공유)  │  ← 단 하나의 Linux 커널
              ├─────────────┤
              │  Hardware   │
              └─────────────┘
  • 모든 컨테이너가 호스트의 커널을 공유
  • OS 없이 애플리케이션 + 의존성만 패키징 (수 MB ~ 수백 MB)
  • 시작 시간: 밀리초 ~ 수 초
  • 커널의 Namespace + cgroups로 격리

핵심 비교

구분 가상머신 (VM) 컨테이너 (Container)
격리 수준 하드웨어 레벨 (강함) 프로세스 레벨 (상대적으로 약함)
커널 각각 독립 커널 호스트 커널 공유
이미지 크기 GB 단위 MB 단위
시작 시간 분 단위 초 ~ 밀리초
리소스 오버헤드 크다 (Guest OS 메모리) 작다 (프로세스 수준)
밀도 1대 서버에 수십 개 1대 서버에 수백 ~ 수천 개
이식성 하이퍼바이저 의존 OCI 표준으로 어디서든 실행

커널이 컨테이너를 만드는 방법

1. Namespace — "뭘 볼 수 있는가"를 격리

호스트 PID 목록:  PID 1(systemd), PID 100(dockerd), PID 200(nginx), PID 201(worker)

컨테이너 A가 보는 세상:  PID 1(nginx), PID 2(worker)  ← PID Namespace
컨테이너 B가 보는 세상:  PID 1(java), PID 2(thread)   ← 별도의 PID Namespace
Namespace 종류 격리 대상
PID 프로세스 ID (컨테이너 내부에서 PID 1부터 시작)
Network 네트워크 인터페이스, IP, 포트, 라우팅 테이블
Mount 파일 시스템 마운트 포인트
UTS 호스트명
IPC System V IPC, POSIX 메시지 큐
User UID/GID (컨테이너 내 root ≠ 호스트 root)
Cgroup cgroup 루트 디렉토리

2. cgroups — "얼마나 쓸 수 있는가"를 제한

# Docker에서의 리소스 제한
docker run --cpus="2.0" --memory="512m" --memory-swap="1g" nginx
  • CPU: 사용 가능한 CPU 코어 수, CPU 시간 비율
  • Memory: 최대 메모리, swap 제한 → 초과 시 OOM Kill
  • Block I/O: 디스크 읽기/쓰기 속도 제한
  • Network: 대역폭 제한 (tc와 결합)

3. OverlayFS — 이미지 레이어 시스템

┌─────────────────────┐
│  Container Layer    │  ← 쓰기 가능 (변경사항만 저장)
├─────────────────────┤
│  App Layer          │  ← 읽기 전용 (COPY app.jar)
├─────────────────────┤
│  JDK Layer          │  ← 읽기 전용 (RUN apt install openjdk)
├─────────────────────┤
│  Base Image Layer   │  ← 읽기 전용 (FROM ubuntu:22.04)
└─────────────────────┘
  • 여러 읽기 전용 레이어 위에 하나의 쓰기 가능 레이어를 올림
  • 같은 베이스 이미지를 쓰는 컨테이너들은 레이어를 공유 → 디스크 절약

왜 컨테이너를 선호하는가? — 실무 관점

1. 개발-배포 일관성

"내 로컬에서는 되는데요?" → 컨테이너로 해결

Dockerfile로 환경을 코드화하면 개발/스테이징/프로덕션 환경이 동일하다.

2. 마이크로서비스에 최적

  • VM: 서비스 하나에 OS 하나 → 리소스 낭비
  • 컨테이너: 서비스 하나에 프로세스 하나 → 경량, 독립 배포 가능

3. 빠른 스케일링

VM 스케일 아웃: OS 부팅 → 설정 → 앱 시작 (수 분)
컨테이너 스케일 아웃: 컨테이너 시작 (수 초)

K8s HPA(Horizontal Pod Autoscaler)가 트래픽에 따라 자동으로 Pod를 늘리고 줄인다.

4. 효율적인 리소스 사용

  • 동일 서버에서 VM 10개 vs 컨테이너 100개 실행 가능
  • Guest OS의 메모리/CPU 오버헤드가 없다

5. 불변 인프라 (Immutable Infrastructure)

  • 서버를 "수정"하지 않고 새 이미지를 빌드해서 교체
  • 롤백이 이전 이미지 태그로 배포하는 것만큼 간단

Docker와 Kubernetes의 관계

Docker: 컨테이너를 "만들고 실행"하는 도구
Kubernetes: 컨테이너를 "운영하고 관리"하는 오케스트레이터

[Kubernetes]
├── Node 1
│   ├── Pod (Container A + Sidecar)
│   ├── Pod (Container B)
│   └── kubelet + containerd  ← 실제 컨테이너 런타임
├── Node 2
│   ├── Pod (Container A replica)
│   └── Pod (Container C)
└── Control Plane
    ├── API Server
    ├── Scheduler       ← 어떤 Node에 Pod를 배치할지
    ├── Controller Manager
    └── etcd            ← 클러스터 상태 저장

K8s가 컨테이너 환경에서 하는 일:

  • 자동 배포/롤백: 새 버전 배포 시 Rolling Update, 문제 시 자동 롤백
  • 자동 복구: Pod가 죽으면 자동 재시작/재배치
  • 오토스케일링: HPA/VPA/Cluster Autoscaler
  • 서비스 디스커버리: DNS 기반 서비스 이름 해석
  • 설정 관리: ConfigMap, Secret

헷갈렸던 포인트

Q1: 컨테이너가 커널을 공유하면 보안이 취약하지 않나?

맞다. VM보다 격리가 약하다. 그래서 보완책이 존재한다:

보완 기술 설명
seccomp 사용 가능한 시스템 콜 제한 (Docker 기본 적용)
AppArmor/SELinux 강제 접근 제어
Rootless Container 컨테이너를 비-root 유저로 실행
gVisor 유저 스페이스 커널로 시스템 콜 가로채기
Kata Containers 경량 VM 안에서 컨테이너 실행 (VM급 격리 + 컨테이너 편의성)

금융/의료처럼 강한 격리가 필요한 환경에서는 Kata Containers나 Firecracker(AWS Lambda가 사용)처럼 microVM을 사용하기도 한다.

Q2: Docker는 Linux에서만 되나? macOS/Windows에서는?

Docker는 Linux 커널 기능(Namespace, cgroups) 에 의존한다.

  • macOS: 내부적으로 경량 Linux VM(LinuxKit)을 실행하고 그 위에서 컨테이너 구동
  • Windows: WSL2(Windows Subsystem for Linux 2)의 Linux 커널 위에서 컨테이너 구동
  • 즉, macOS/Windows에서도 결국 Linux 커널 위에서 컨테이너가 돌아간다

Q3: "컨테이너 = Docker"인가?

아니다. Docker는 컨테이너 기술의 대중화를 이끌었지만, 컨테이너 런타임은 여러 가지다:

런타임 설명
containerd Docker에서 분리된 산업 표준 런타임 (K8s 기본)
CRI-O K8s 전용 경량 런타임 (Red Hat 주도)
runc OCI 표준 구현체, 실제 컨테이너 생성 담당
Podman Docker 호환, 데몬리스, Rootless 기본 지원

K8s 1.24부터 dockershim이 제거되어 containerd/CRI-O를 직접 사용한다.

참고 자료

  • Docker 공식 문서 — Container Overview
  • Kubernetes 공식 문서 — Concepts
  • Linux Namespaces — man7.org
반응형
저작자표시 비영리 동일조건 (새창열림)

'개발' 카테고리의 다른 글

코틀린은 왜 등장했나, 그리고 자바를 거쳐 컴파일되는가?  (0) 2026.05.11
프록시(Proxy)와 리버스 프록시(Reverse Proxy)  (0) 2026.03.20
Java Thread vs CompletableFuture vs Kotlin Coroutine — 셋은 근본적으로 다른 계층의 개념이다  (0) 2026.03.16
Cache Stampede 해결기 — 주기적 DB 부하 급증의 원인을 찾아서  (0) 2026.03.12
JVM 메모리 구조  (0) 2026.03.09
'개발' 카테고리의 다른 글
  • 코틀린은 왜 등장했나, 그리고 자바를 거쳐 컴파일되는가?
  • 프록시(Proxy)와 리버스 프록시(Reverse Proxy)
  • Java Thread vs CompletableFuture vs Kotlin Coroutine — 셋은 근본적으로 다른 계층의 개념이다
  • Cache Stampede 해결기 — 주기적 DB 부하 급증의 원인을 찾아서
senyalog
senyalog
개발 블로그 https://github.com/iamyunjuda
  • senyalog
    Senya의 개발 블로그
    senyalog
  • 전체
    오늘
    어제
    • 분류 전체보기 (96)
      • 일상 (6)
      • 알고리즘 이론 (14)
        • 백준 (8)
      • 개발 (41)
        • Server (10)
        • 인턴 (11)
        • Javascript (0)
      • 경제 (8)
  • 블로그 메뉴

    • Github
    • 홈
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    CS
    코딩
    생각
    경제
    백엔드
    GIT
    nestjs
    이마고웍스
    공부
    백준문제
    대학생
    대학생인턴
    개발
    MSA
    서버
    백준풀이
    자바
    카페
    공대생
    코틀린
    깃
    컴공
    jvm
    인턴
    백준
    일상
    개발자
    알고리즘공부
    알고리즘
    컴퓨터공학
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
senyalog
컨테이너 vs 가상머신 — Docker, Kubernetes, 그리고 왜 컨테이너인가
상단으로

티스토리툴바