컨테이너화 (Containerization)

애플리케이션과 의존성을 격리된 환경에 패키징하여, 개발·스테이징·프로덕션에서 동일하게 실행 가능하게 하는 기술.

설명

컨테이너화는 다음 문제를 해결한다:

문제: “내 컴퓨터(Mac/Windows)에서는 되는데 서버(Linux)에서 안 된다”

  • 개발 환경: Python 3.9, 라이브러리 v1.0
  • 서버 환경: Python 3.11, 라이브러리 v2.0
  • 결과: 호환성 오류, 운영 비용 증가

해결책: 애플리케이션 + 의존성을 하나의 “컨테이너”로 패키징

  • Dockerfile = 인프라 코드화 (git 버전 관리 가능)
  • 동일한 이미지 → 어디서나 동일한 실행 환경

핵심 개념

컨테이너 (Container)

호스트 Linux 커널을 공유하면서 격리된 환경:

  • 파일 시스템 격리
  • 네트워크 격리
  • 프로세스 격리

이점:

  • 경량 (VM의 1/10 크기)
  • 빠른 시작 (초 단위)
  • 확장성 (여러 인스턴스 병렬 실행)

이미지 (Image)

컨테이너 생성 시 사용할 정적 패키지:

  • 파일 시스템 스냅샷
  • 환경변수
  • 시작 명령

레이어 (Layer)

Dockerfile의 각 명령은 하나의 “레이어”로 캐시된다:

FROM python:3.11-slim          # 레이어 1 (베이스 이미지)
COPY requirements.txt .        # 레이어 2
RUN pip install -r requirements.txt  # 레이어 3 (캐시 키: 레이어 2)
COPY . .                       # 레이어 4
CMD ["fastapi", "run", "app/main.py"]  # 레이어 5

캐싱 원리:

  • 레이어 1-3 미변경 → 캐시 재사용 (빠름)
  • 레이어 4 변경 (코드) → 레이어 4-5만 재실행

캐싱 최적화

변경 빈도 오름차순으로 배열:

순서명령변경 빈도캐싱
1FROM거의 안 함거의 항상 재사용
2COPY requirements.txt낮음 (수주 단위)자주 재사용
3RUN pip install낮음 (레이어 2 미변경 시)자주 재사용
4COPY . .높음 (매일)자주 캐시 미스
5CMD낮음거의 항상 재사용

결과: 빌드 시간 10초 (캐시 hit) vs 100초 (캐시 miss)

5단계 배포 흐름

1단계: Dockerfile 작성

FROM python:3.11-slim
WORKDIR /app
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["fastapi", "run", "app/main.py", "--port", "8000"]

2단계: 이미지 빌드

docker build -t myapp:1.0 .

3단계: 로컬 테스트 (Docker Desktop)

docker run -p 8000:8000 myapp:1.0

4단계: 이미지 레지스트리 푸시

docker tag myapp:1.0 myregistry/myapp:1.0
docker push myregistry/myapp:1.0

레지스트리: Docker Hub, AWS ECR, Google GCR 등

5단계: 클라우드 배포

  • ECS: AWS 관리형 컨테이너 서비스
  • GKE: Google Kubernetes Engine
  • ACI: Azure Container Instances
  • K8s: 자체 관리 오케스트레이션

보안 모범 사례

1. 최신 베이스 이미지

FROM python:3.11-slim  # 정기 보안 업데이트

알려진 취약점 패치 포함.

2. Non-root 사용자

RUN useradd -m appuser
USER appuser

컨테이너 침입 시 피해 최소화.

3. 이미지 스캔

docker scan myapp:1.0

CVE(알려진 취약점) 검사 및 업데이트 제시.

4. 민감 정보 외부화

ENV DATABASE_URL=  # 비워두기

.env 파일로 런타임에 주입.

헬스체크 & 자동 재시작

Docker가 애플리케이션 상태를 정기적으로 확인:

HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1
  • 3회 연속 실패 → 컨테이너 자동 재시작
  • Kubernetes/ECS는 이 정보로 pod/task 교체

Docker Compose: 다중 서비스

version: '3'
services:
  web:
    build: .
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
  
  db:
    image: postgres:15
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 10s

실행:

docker-compose up

모든 서비스 동시 시작, 의존성 자동 관리.

수평 확장 (Horizontal Scaling)

문제: 단일 컨테이너 = 단일 프로세스 = 동시성 제한

해결책: 여러 인스턴스 + 로드 밸런서

[로드 밸런서 (Nginx/Traefik)]
    ↓
[FastAPI 인스턴스 1]
[FastAPI 인스턴스 2]
[FastAPI 인스턴스 3]

각 인스턴스는 독립적 컨테이너, 병렬 처리 가능.

관련 개념

실전 적용

docker 의 도구

  • Dockerfile 작성
  • 이미지 빌드·레지스트리 관리
  • 컨테이너 실행·모니터링

fastapi 컨테이너화

  • ASGI 웹 프레임워크를 Docker로 배포
  • Uvicorn으로 다중 워커 실행

traefik 와의 연계

  • 여러 FastAPI 컨테이너 자동 발견
  • HTTPS/SSL 종료

소스