Skip to main content

Container & Kubernetes 기초

컨테이너는 “내 컴퓨터에서는 되는데 서버에서는 안 됨” 문제를 줄이는 표준 배포 단위입니다. Kubernetes는 그 컨테이너를 안정적으로 운영하기 위한 오케스트레이션 도구입니다.

학습 목표

  • 이미지, 컨테이너, 레지스트리 관계를 이해합니다.
  • Dockerfile과 docker-compose를 작성할 수 있습니다.
  • Kubernetes 핵심 오브젝트를 역할 기준으로 구분할 수 있습니다.
  • GPU 워크로드의 컨테이너 배포와 스케줄링 기본을 이해합니다.

왜 중요한가

AI/ML 환경은 Python 버전, CUDA 버전, 라이브러리 의존성이 복잡합니다. 컨테이너는 이 환경을 코드처럼 버전 관리할 수 있게 해줍니다. “내 로컬에서는 학습이 되는데 서버에서 안 됩니다”라는 문제를 원천적으로 예방합니다.

컨테이너 기본 모델

  • 이미지: 실행 가능한 패키지 스냅샷 (Dockerfile로 정의)
  • 컨테이너: 이미지의 실행 인스턴스 (격리된 프로세스)
  • 레지스트리: 이미지 저장소 (Docker Hub, ECR, GCR, ACR)
이미지 버전을 고정하지 않으면 재현성이 무너집니다. latest 태그는 운영에서 지양합니다.

Dockerfile 예시

# ML 추론 서비스 Dockerfile
FROM python:3.11-slim

WORKDIR /app

# 의존성 먼저 복사 (캐시 최적화)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 소스 코드 복사
COPY . .

# 비root 사용자로 실행 (보안)
RUN useradd -m appuser
USER appuser

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
requirements.txt를 먼저 복사하고 설치하면, 코드 변경 시 의존성 레이어를 캐시에서 재사용할 수 있어 빌드 속도가 빨라집니다.

docker-compose 예시

# docker-compose.yml - ML 추론 서비스 로컬 환경
services:
  api:
    build: .
    ports: ["8000:8000"]
    environment:
      - MODEL_PATH=/models/my-model
    volumes: ["./models:/models"]
    depends_on: [redis]
  redis:
    image: redis:7-alpine
    ports: ["6379:6379"]
  worker:  # GPU 워커 (비동기 추론)
    build: .
    command: celery -A tasks worker --loglevel=info
    environment: ["CELERY_BROKER_URL=redis://redis:6379/0"]
    depends_on: [redis]
    deploy:
      resources:
        reservations:
          devices: [{capabilities: [gpu]}]

Kubernetes 핵심 오브젝트

오브젝트역할설명
Pod실행 단위컨테이너 1개 이상의 최소 실행 단위
Deployment배포 관리Pod 개수, 업데이트 전략, 롤백
Service네트워크Pod에 안정적인 접근 경로(IP/DNS) 제공
ConfigMap설정환경별 설정값 관리
Secret비밀정보API 키, 인증서 등 민감 데이터
HPA자동 스케일링CPU/메모리/커스텀 메트릭 기반 Pod 수 조절
PVC저장소영구 볼륨 요청 (모델 파일, 데이터셋)

배포 기본 흐름

1

이미지 빌드

Dockerfile로 이미지를 빌드하고 태그를 지정합니다. (예: v1.2.3 또는 커밋 SHA)
2

레지스트리 푸시

빌드된 이미지를 ECR, GCR, ACR 등 레지스트리에 푸시합니다.
3

Deployment 업데이트

Kubernetes Deployment의 이미지 태그를 업데이트합니다.
4

롤링 업데이트 확인

새 Pod가 정상 기동되고 기존 Pod가 순차 종료되는지 확인합니다.
5

헬스체크/로그 점검

readinessProbe 통과 여부, 에러 로그, 메트릭을 확인합니다.

GPU 스케줄링 (Kubernetes)

# GPU Pod 예시
apiVersion: v1
kind: Pod
metadata:
  name: inference-gpu
spec:
  containers:
    - name: model-server
      image: my-registry/inference:v1.2.3
      resources:
        limits:
          nvidia.com/gpu: 1    # GPU 1개 요청
        requests:
          memory: "8Gi"
          cpu: "4"
      volumeMounts:
        - name: model-volume
          mountPath: /models
  volumes:
    - name: model-volume
      persistentVolumeClaim:
        claimName: model-pvc
  tolerations:
    - key: "nvidia.com/gpu"
      operator: "Exists"
      effect: "NoSchedule"
GPU 운영 포인트:
  • NVIDIA Device Plugin이 클러스터에 설치되어 있어야 합니다.
  • GPU 노드에 taint를 설정하고, GPU Pod에만 toleration을 부여합니다.
  • GPU는 분할 할당이 안 되므로(기본), 노드당 GPU 수와 Pod 배치를 계획합니다.

운영 필수 설정

  • readinessProbe, livenessProbe 설정으로 장애 Pod를 자동 격리/재시작합니다.
  • CPU/메모리 request/limit 설정으로 리소스 과점을 방지합니다.
  • 환경변수와 시크릿을 분리합니다.
  • 롤백 가능한 배포 전략(RollingUpdate, maxSurge, maxUnavailable)을 유지합니다.
이미지가 덮어쓰기 되면 같은 배포 설정이라도 다른 결과가 나옵니다. 버전 태그(v1.2.3) 또는 커밋 SHA 태그(abc1234)를 사용하세요.
request/limit이 없으면 특정 Pod가 노드를 과점해 전체 장애로 이어질 수 있습니다. 특히 GPU 노드에서는 메모리 OOM이 다른 Pod까지 영향을 줍니다.
  1. kubectl get pods - Pod 상태 확인
  2. kubectl describe pod - 이벤트 확인
  3. kubectl logs - 컨테이너 로그 확인
  4. 프로브 설정 점검
  5. 시크릿/설정값 확인
학습 의존성(컴파일러, 빌드 도구)은 빌드 단계에서만 사용하고, 최종 이미지에는 런타임 의존성만 포함하세요. 이미지 크기가 작을수록 배포가 빠릅니다.

체크리스트

  • 이미지 태그가 고정(버전/SHA)되어 있나요?
  • 헬스체크(readiness/liveness)와 리소스 제한이 설정됐나요?
  • 시크릿이 ConfigMap과 분리되어 안전하게 관리되나요?
  • 롤백 절차를 팀이 실행할 수 있나요?
  • GPU 워크로드에 taint/toleration이 적용됐나요?
  • 이미지 크기가 불필요하게 크지 않나요?

다음 문서