direcf Backend & Ops for AI Engineers Ch07 Kubernetes Fundamentals
Chapter 07 · 10 chapters
☸️

Kubernetes Fundamentals

쿠버네티스 기초
컨테이너를 수십~수천 개로 자동 관리하는 쿠버네티스의 핵심 개념(Pod, Deployment, Service)과 AI 서비스 배포 패턴을 익힌다.
Chapter 7 Cheat Sheet
🍌 Nano Banana — Chapter 7 Visual Summary

🎯 학습 목표

5 goals
Learning Goals
  • 쿠버네티스의 컨트롤 플레인과 워커 노드 아키텍처를 설명할 수 있다
  • Deployment로 애플리케이션을 배포하고 롤링 업데이트를 수행할 수 있다
  • Service 타입(ClusterIP, NodePort, LoadBalancer)의 차이를 알고 적절히 선택할 수 있다
  • HPA로 CPU/메모리 기반 자동 확장을 설정할 수 있다
  • GPU 리소스를 요청해 AI 추론 워크로드를 배포할 수 있다

Docker가 단일 컨테이너를 관리하는 도구라면, Kubernetes(K8s)는 수십~수천 개의 컨테이너를 여러 서버에 걸쳐 자동으로 관리하는 오케스트레이터입니다. 2014년 구글이 내부에서 10년간 사용한 Borg 시스템을 오픈소스로 공개한 것으로, 현재 클라우드 네이티브 인프라의 사실상 표준입니다.

K8s가 해결하는 문제들은 구체적입니다. 서버가 죽으면? → 자동으로 다른 서버에 컨테이너를 재시작. 트래픽이 갑자기 10배 증가하면? → 자동으로 컨테이너 수를 늘림. 새 버전 배포 시 다운타임 없이? → 롤링 업데이트. 이 모든 것을 선언적(declarative) YAML 파일로 관리합니다.

AI 엔지니어에게 K8s는 ML 파이프라인의 인프라입니다. Kubeflow, Argo Workflows, KServe 모두 K8s 위에서 실행됩니다. GPU 노드 관리, 배치 추론 작업 스케줄링, 모델 서빙 스케일링이 모두 K8s로 이루어집니다.

핵심 내용

쿠버네티스 아키텍처

K8s 클러스터는 컨트롤 플레인(Control Plane)워커 노드(Worker Node) 로 구성됩니다.

컨트롤 플레인 은 클러스터의 두뇌입니다.

- API Server: 모든 K8s 명령의 진입점. kubectl은 API Server와 통신합니다.

- etcd: 클러스터 상태를 저장하는 분산 키-값 저장소. "진실의 단일 출처(Single Source of Truth)" - Scheduler: 새 Pod를 어떤 노드에 배치할지 결정합니다. 리소스 요구사항, 노드 상태를 고려합니다.

- Controller Manager: 현재 상태와 원하는 상태의 차이를 감지하고 조정합니다.

워커 노드 는 실제 컨테이너가 실행되는 서버입니다.

- kubelet: 각 노드에서 실행되며 컨트롤 플레인의 지시를 따릅니다. Pod를 시작/중지합니다.

- kube-proxy: 네트워크 규칙을 관리해 Pod 간 통신을 처리합니다.

- Container Runtime: 컨테이너를 실제로 실행하는 엔진 (containerd, CRI-O).

선언적 모델: K8s는 "Pod 3개를 실행하라"는 명령이 아니라 "Pod가 3개인 상태"를 선언합니다. 컨트롤러가 현재 상태(현재 Pod 수)와 원하는 상태(3개)를 지속적으로 비교하고 차이를 메웁니다. Pod 하나가 죽으면 자동으로 새 Pod를 시작합니다.

핵심 오브젝트: Pod, Deployment, Service

Pod 는 K8s의 최소 배포 단위입니다. 하나 이상의 컨테이너를 함께 묶습니다. 같은 Pod 안의 컨테이너들은 네트워크 네임스페이스를 공유하므로 localhost로 통신할 수 있습니다. Pod는 수명이 짧습니다 — 노드가 죽으면 Pod도 사라집니다.

Deployment 는 Pod를 관리하는 오브젝트입니다. replicas: 3으로 항상 3개의 Pod를 유지합니다. kubectl rollout으로 롤링 업데이트(점진적 교체)와 롤백을 지원합니다. Deployment가 ReplicaSet을 관리하고, ReplicaSet이 Pod를 관리합니다.

Service 는 Pod 집합에 안정적인 네트워크 엔드포인트를 제공합니다. Pod는 재시작될 때마다 IP가 바뀌지만, Service는 고정된 가상 IP(ClusterIP)와 DNS 이름을 가집니다. app: ml-server 레이블을 가진 모든 Pod로 트래픽을 분산합니다.

Service 타입 세 가지:

- ClusterIP (기본값): 클러스터 내부에서만 접근 가능. 마이크로서비스 간 통신에 사용.

- NodePort: 각 노드의 특정 포트로 외부 접근 허용. 개발·테스트 환경에 적합.

- LoadBalancer: 클라우드 로드 밸런서와 연동해 외부 IP를 부여. 프로덕션 외부 노출에 사용.

ConfigMap과 Secret: 설정 분리

12-factor 앱 원칙에 따르면 설정은 코드와 분리되어야 합니다. K8s의 ConfigMap과 Secret이 이를 담당합니다.

ConfigMap 은 비민감 설정 데이터(환경 설정, 앱 설정 파일)를 저장합니다. 환경 변수로 주입하거나 파일로 마운트할 수 있습니다. ConfigMap을 업데이트하면 볼륨 마운트 방식은 Pod 재시작 없이 자동 반영됩니다.

Secret 은 민감 데이터(DB 비밀번호, API 키, TLS 인증서)를 저장합니다. Base64로 인코딩되어 저장되지만 이는 인코딩이지 암호화가 아닙니다. 프로덕션에서는 etcd 암호화 또는 외부 시크릿 매니저(Vault, AWS Secrets Manager)와 연동해야 합니다.

K8s Secret의 보안 모범 사례:

- RBAC으로 Secret 접근 권한을 최소화합니다 - 시크릿 값을 kubectl describe에서 숨기려면 stringData 대신 data(base64)를 사용합니다 - External Secrets Operator로 AWS/GCP 시크릿 매니저와 동기화합니다

자동 확장: HPA와 VPA

K8s의 강력한 기능 중 하나는 부하에 따라 Pod 수를 자동으로 조정하는 것입니다.

HPA(Horizontal Pod Autoscaler) 는 Pod 수를 조정합니다. CPU 사용률이 70%를 넘으면 Pod를 추가하고, 낮아지면 줄입니다. 메트릭 서버(metrics-server)가 필요합니다.

HPA 설정 파라미터:

- minReplicas: 최소 Pod 수 (트래픽이 없어도 유지) - maxReplicas: 최대 Pod 수 (비용 상한) - targetCPUUtilizationPercentage: 목표 CPU 사용률

AI 서비스에서 HPA를 사용할 때 주의점이 있습니다. GPU 추론 서버는 CPU 사용률보다 요청 큐 길이GPU 사용률 기반으로 확장하는 것이 더 적합합니다. Prometheus + KEDA(Kubernetes Event-Driven Autoscaling)로 커스텀 메트릭 기반 확장을 구현합니다.

VPA(Vertical Pod Autoscaler) 는 각 Pod의 CPU/메모리 요청값을 자동으로 조정합니다. 처음 resources.requests를 얼마로 설정해야 할지 모를 때 VPA가 추천값을 제안합니다.

GPU 워크로드와 AI 서빙 패턴

K8s에서 GPU 리소스를 사용하려면 NVIDIA Device Plugin이 설치되어 있어야 합니다. Pod 스펙에 nvidia.com/gpu: 1을 명시하면 스케줄러가 GPU가 있는 노드에만 배치합니다.

노드 셀렉터와 어피니티 로 특정 하드웨어(GPU 모델, 메모리)를 가진 노드에만 배치할 수 있습니다. nodeSelector: cloud.google.com/gke-accelerator: nvidia-tesla-a100 처럼 레이블을 사용합니다.

Job 은 일회성 배치 작업에 사용합니다. 모델 학습, 대규모 배치 추론, 데이터 전처리가 해당됩니다. Job은 완료되면 종료되고, 실패 시 재시도합니다.

CronJob 은 주기적인 작업에 사용합니다. 매일 새벽 모델 재학습, 시간별 피처 집계 등에 활용합니다.

KServe (구 KFServing)는 K8s 위에서 모델 서빙을 단순화하는 플랫폼입니다. InferenceService 오브젝트 하나로 모델 로딩, 스케일링, 카나리 배포, GPU 스케줄링을 자동화합니다.

💡 비유로 이해하기

Analogy
항공 관제 시스템

쿠버네티스를 이해하는 가장 좋은 비유는 공항 관제 시스템입니다. 공항(K8s 클러스터)에 수십~수백 대의 비행기(컨테이너)가 이착륙합니다. 항공 관제사(컨트롤 플레인)는 각 비행기의 위치를 파악하고, 활주로(노드)에 비행기를 할당하며, 비상 상황 시 대체 경로를 지시합니다.

비행기(Pod)가 고장 나면(충돌, 엔진 오류) 관제탑이 즉시 교체 비행기를 활주로로 보냅니다. 갑자기 승객이 몰리면(트래픽 급증) 비행기를 더 투입합니다(HPA). 관제사의 모든 지시는 비행 계획서(YAML 매니페스트)에 따릅니다.

kubectl은 관제탑과 통신하는 무전기입니다. kubectl apply -f deployment.yaml은 새 비행 계획서를 제출하는 것이고, kubectl get pods는 현재 비행 중인 비행기 목록을 확인하는 것입니다.

💻 코드 예시

AI 추론 서버를 K8s에 배포하는 전체 매니페스트입니다. Deployment, Service, HPA, ConfigMap을 포함합니다.

yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ml-inference-server
  labels:
    app: ml-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ml-server
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 업데이트 중 최대 추가 Pod
      maxUnavailable: 0  # 업데이트 중 최소 가용 Pod (다운타임 없음)
  template:
    metadata:
      labels:
        app: ml-server
    spec:
      containers:
      - name: inference
        image: myregistry/ml-server:v1.2.0
        ports:
        - containerPort: 8000
        resources:
          requests:
            cpu: "500m"       # 0.5 CPU 코어 요청
            memory: "1Gi"
            nvidia.com/gpu: 1 # GPU 1개 요청
          limits:
            cpu: "2000m"
            memory: "4Gi"
            nvidia.com/gpu: 1
        envFrom:
        - configMapRef:
            name: ml-server-config
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: ml-inference-svc
spec:
  selector:
    app: ml-server
  ports:
  - port: 80
    targetPort: 8000
  type: LoadBalancer
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ml-server-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ml-inference-server
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

resources.requests는 스케줄러가 노드 선택 시 참고하는 최소 보장 자원입니다. nvidia.com/gpu: 1로 GPU 1개를 요청합니다. livenessProbe는 Pod가 살아 있는지 주기적으로 확인하고, 실패 시 자동 재시작합니다. maxUnavailable: 0은 롤링 업데이트 중 항상 3개 Pod가 서빙 중임을 보장합니다.

🏭 현업에서의 평가

Industry Evaluation
K8s는 러닝 커브가 가파릅니다. 면접에서는 기본 개념 이해와 실제 트러블슈팅 경험을 봅니다.

✅ 시니어가 보는 것

  • resources.requests와 limits의 차이와 설정 이유를 설명하는가
  • OOMKilled Pod를 어떻게 디버깅하는지 아는가
  • liveness probe와 readiness probe의 차이를 구분하는가

⚠️ 레드 플래그

  • resources를 설정하지 않는 경우 (노드 OOM으로 다른 Pod에 영향)
  • Secret을 YAML 파일에 평문으로 커밋하는 경우
  • 단일 Pod로 프로덕션 서비스를 운영하는 경우 (노드 장애 시 다운타임)

🎤 예상 인터뷰 질문

  1. Pod가 CrashLoopBackOff 상태일 때 어떻게 디버깅하시나요?
  2. 새 버전 배포 중 오류가 발생했을 때 어떻게 이전 버전으로 빠르게 되돌리나요?
  3. GPU 노드가 2개뿐인데 5개의 추론 Pod를 요청하면 어떻게 되나요?
숙달 vs 익숙함: 아는 수준은 기본 YAML로 Deployment와 Service를 배포하는 것입니다. 마스터 수준은 Pod Disruption Budget으로 유지보수 중 가용성을 보장하고, Admission Webhook으로 보안 정책을 강제하며, Operator 패턴으로 상태 있는 애플리케이션(DB)을 관리하는 것입니다.

✨ 핵심 요약

선언적 모델

K8s는 명령이 아닌 원하는 상태를 선언한다. 컨트롤러가 현재 상태를 원하는 상태로 지속 조정한다.

Pod는 일시적

Pod는 죽고 재시작된다. 안정적 접근을 위해 Service를 통해 통신해야 한다.

resources 설정 필수

requests와 limits를 설정하지 않으면 노드 OOM으로 다른 서비스에 영향을 준다.

HPA = 자동 확장

CPU/메모리 기반 HPA로 트래픽 변화에 자동으로 대응한다. AI 서버는 커스텀 메트릭(큐 길이)이 더 적합하다.

GPU 리소스 요청

nvidia.com/gpu: 1로 GPU를 요청하면 스케줄러가 GPU 노드에 배치한다.

롤링 업데이트

maxUnavailable: 0으로 다운타임 없이 새 버전을 배포할 수 있다.