🏗️ 1. VM vs Container: 아키텍처의 차이
왜 Docker는 “가볍다"고 할까요? 비밀은 Guest OS의 유무에 있습니다.
graph TD
subgraph VM [Virtual Machine Architecture]
Hyper[Hypervisor]
GOS["Guest OS <br/>(Heavy, GBs)"]
App1[Application]
end
subgraph Container [Container Architecture]
Docker[Docker Engine]
App2[Application]
P[Allocated Process]
end
Hyper --> GOS --> App1
Docker --> App2
%% Styles
style VM fill:#ffebee,stroke:#c62828
style Container fill:#e8f5e9,stroke:#2e7d32
style GOS fill:#ffcdd2,stroke:#b71c1c,stroke-width:2px
style Docker fill:#c8e6c9,stroke:#1b5e20,stroke-width:2px
- VM: 하드웨어를 가상화합니다. 각 VM마다 Windows/Linux를 통째로 설치하므로 무겁고(GB 단위), 부팅이 느립니다.
- Container: OS(리눅스 커널)를 공유합니다. 격리된 프로세스일 뿐이므로 가볍고(MB 단위), 1초 만에 켜집니다.
🍰 2. 이미지 레이어(Layer)와 Copy-on-Write
Docker 이미지는 통짜 파일이 아닙니다. 여러 겹의 케이크입니다.
graph BT
L1[Base Layer: Ubuntu] --> L2[Add Java]
L2[Add Java] --> L3[Add Application Code]
L3[Add Application Code] --> C["Container Layer <br/>(Read-Write)"]
%% Styles
classDef readOnly fill:#eeeeee,stroke:#9e9e9e,stroke-dasharray: 5 5;
classDef writeAble fill:#fff3e0,stroke:#ff9800,stroke-width:2px;
class L1,L2,L3 readOnly;
class C writeAble;
이미지의 모든 레이어는 Read-Only입니다. 컨테이너를 실행하면 그 위에 얇은 R/W 레이어 한 장만 올라갑니다.
- 효율성: 여러 컨테이너가 Base Image(Ubuntu, Java 등)를 공유합니다. 디스크를 아낍니다.
- 속도: 이미지는 읽기 전용이라 캐싱하기 좋습니다.
📜 3. Dockerfile의 핵심 (멀티 스테이지 빌드)
“이미지 크기를 줄이는 법"이 실무의 핵심입니다.
flowchart LR
subgraph Stage 1 [Builder Stage]
Src[Source Code] --> Build[Gradle Build]
Build --> Jar[Spring Boot JAR]
end
subgraph Stage 2 [Runtime Stage]
Base[OpenJDK Slim Image] --> Copy[Copy JAR from Stage 1]
Copy --> Run[Run Application]
end
Jar -.-> Copy
style Stage 1 fill:#f3e5f5,stroke:#7b1fa2
style Stage 2 fill:#e3f2fd,stroke:#1565c0
# 🏗️ Build Stage
FROM gradle:jdk17 AS builder
COPY . .
RUN ./gradlew build # 여기서 소스 컴파일 (무거움)
# 🚀 Run Stage
FROM openjdk:17-slim # 가벼운 런타임 이미지
COPY --from=builder /app/build/libs/myapp.jar .
ENTRYPOINT ["java", "-jar", "myapp.jar"]
빌드 도구(Gradle, Maven)는 런타임에 필요 없습니다. 결과물(Jar)만 쏙 빼서 새 이미지에 담는 Multi-stage Build를 쓰면 용량이 1/10으로 줄어듭니다.
🐙 4. Docker Compose: “나의 작은 오케스트라”
컨테이너 하나(App)만 띄우는 일은 드뭅니다. DB도 띄워야 하고 Redis도 띄워야 하죠. 이들을 한 방에 관리하는 도구입니다.
services:
app:
build: .
depends_on: [db, redis] # 순서 보장
ports: ["8080:8080"]
db:
image: mysql:8.0
volumes: ["db_data:/var/lib/mysql"] # 데이터 영속성
redis:
image: redis:alpine
가장 중요한 건 volumes입니다. 컨테이너를 지워도 DB 데이터가 날아가면 안 되니까요.
요약
- 가벼움: OS 커널을 공유하는 프로세스 격리 기술이다.
- 레이어: 이미지는 겹겹이 쌓이며 재사용된다. 컨테이너는 그 위에 쓰는 얇은 종이다.
- Dockerfile: 빌드 단계와 실행 단계를 나누는 것이 국룰이다.
💬 댓글