Docker 개요

허동빈·2026년 1월 27일

docker

목록 보기
1/8
post-thumbnail

Chapter 01: 개요 및 아키텍처

Docker 컨테이너화가 왜 필요한지, 전체 시스템 구조를 이해.


1. 왜 Docker를 사용하는가?

AWS EC2 t3.micro 환경을 로컬에서 재현하여 부하 테스트

Before (Docker 사용 전)

개발자 로컬 환경
├─ CPU: 8 코어 (M1/M2/M3 Mac, i7/i9 등)
├─ 메모리: 16GB ~ 32GB
└─ 결과: 실제 프로덕션 환경과 다른 성능 측정치

문제점:

  • 로컬에서는 잘 돌아가는데 서버에서는 느림
  • 부하 테스트 결과를 신뢰할 수 없음
  • "내 컴퓨터에서는 잘 되는데요?" 증후군

After (Docker 사용 후)

Docker 컨테이너 환경
├─ CPU: 2.0 코어로 제한 (AWS EC2 t3.micro와 동일)
├─ 메모리: 980MB로 제한 (AWS와 동일)
└─ 결과: 실제 프로덕션 환경과 거의 동일한 성능

해결:

  • 로컬에서 실제 서버 환경 시뮬레이션
  • 신뢰할 수 있는 부하 테스트 결과
  • 배포 전 성능 이슈 사전 발견

2. 프로젝트 배경 및 목표

배경

현재 개발하고 있는 프로젝트는 중고 거래 + 경매 플랫폼입니다. 특히 경매 입찰 기능은 다음과 같은 특성이 있습니다:

  1. 동시성 문제: 여러 사용자가 동시에 같은 상품에 입찰
  2. 실시간성: 입찰가는 즉시 반영되어야 함
  3. 데이터 정합성: 비관적 락으로 해결

목표

목표설명
환경 일치로컬 개발 환경 ≈ AWS 프로덕션 환경
성능 측정EC2 t3.micro에서 동작할 때의 성능 예측
리소스 제약CPU/메모리 제한 하에서 최적화
팀 협업누구나 동일한 환경에서 테스트 가능

3. 아키텍처

컴포넌트 역할

컴포넌트역할실행 방식이유
Spring Boot백엔드 API 서버Docker 컨테이너리소스 제한 적용
MySQL데이터베이스Docker 컨테이너리소스 제한 적용
Redis캐시 서버Docker 컨테이너리소스 제한 적용
K6부하 테스트 도구Native (로컬)호스트 리소스 사용
Prometheus메트릭 수집Native (로컬)컨테이너 메트릭 수집
Grafana대시보드Native (로컬)시각화

데이터 흐름

1️⃣ 부하 테스트 실행
   K6 → Spring Boot (8080) → MySQL (3307) / Redis (6380)

2️⃣ 메트릭 수집
   Spring Boot (/actuator/prometheus) → Prometheus → Grafana

3️⃣ K6 메트릭 전송
   K6 → Prometheus (Remote Write)

4. 기술 스택 및 선택 이유

🐳 Docker

선택 이유:

  • 리소스 제한 기능 (CPU, Memory)
  • 환경 일관성 (개발/테스트/운영)
  • 빠른 환경 구축
  • 팀원 간 동일한 환경 공유

대안:

  • VM (VirtualBox, VMware): 무겁고 느림
  • 직접 설치: 환경마다 다른 설정

Docker Compose

선택 이유:

  • 여러 컨테이너 관리 편리
  • YAML 파일로 설정 관리
  • 의존성 관리 (depends_on)

대안:

  • docker run 명령어: 복잡하고 관리 어려움
  • Kubernetes: 오버 엔지니어링 (로컬 개발용으로 과함)

K6 (부하 테스트)

선택 이유:

  • Prometheus 직접 연동 (Remote Write)
  • JavaScript로 시나리오 작성 (쉬움)
  • CLI 기반 (CI/CD 연동 쉬움)

대안:

  • JMeter: GUI 기반, Prometheus 연동 복잡
  • Gatling: Scala 학습 곡선

Prometheus + Grafana

선택 이유:

  • Spring Boot Actuator와 네이티브 연동
  • 오픈소스 표준 (산업 표준)
  • 시계열 데이터 저장 최적화

대안:

  • ELK Stack: 로그 중심 (메트릭엔 비효율)
  • DataDog: 유료 (학습/테스트 목적엔 과함)

5. 리소스 제한 전략

AWS EC2 t3.micro 스펙 기준

항목AWS 실제 스펙Docker 제한비율이유
CPU2 vCPU2.0 코어100%버스트 모드 활용
Memory1024MB980MB95%OS 오버헤드 20MB
JVM Heap-750MB76%메타스페이스 여유

왜 100%가 아닌 95%인가?

메모리 분배 (980MB 기준):

┌─────────────────────────────────────┐
│ 총 메모리: 980MB                      │
├─────────────────────────────────────┤
│ JVM Heap: 750MB (77%)               │ ← 애플리케이션 객체
│ Metaspace: 180MB (18%)              │ ← 클래스 메타데이터
│ Native Memory: 50MB (5%)            │ ← 스레드, NIO 버퍼 등
└─────────────────────────────────────┘

이유:

  • Docker 컨테이너도 최소한의 OS 오버헤드 필요
  • JVM은 Heap 외에도 Metaspace, Native Memory 사용
  • 여유 공간 없으면 OOMKilled 발생

6. 멀티 스테이지 빌드 전략

왜 멀티 스테이지 빌드?

단일 스테이지 (비효율):

FROM gradle:8.5-jdk21
# Gradle + JDK 포함
# 최종 이미지 크기: ~1.2GB 

멀티 스테이지 (효율):

# Stage 1: 빌드 (Gradle + JDK)
FROM gradle:8.5-jdk21 AS builder
RUN ./gradlew bootJar

# Stage 2: 실행 (JRE만)
FROM eclipse-temurin:21-jre
COPY --from=builder /app/build/libs/*.jar app.jar
# 최종 이미지 크기: ~300MB 

효과:

  • 이미지 크기 75% 감소
  • 빌드 도구 제외 (보안 향상)
  • 컨테이너 시작 속도 향상

9. 보안 고려사항

비루트 사용자 실행

왜?

  • Docker 컨테이너 기본 사용자는 root
  • 만약 컨테이너가 해킹당하면 호스트도 위험

해결:

# 비루트 사용자 생성
RUN groupadd -r spring && useradd -r -g spring spring
USER spring:spring

효과:

  • 권한 최소화 (Principle of Least Privilege)
  • 컨테이너 탈출 공격 방어

참고 자료

profile
백엔드 공부

0개의 댓글