서론: Kubernetes 핵심 리소스 마스터하기

Kubernetes를 효과적으로 활용하려면 세 가지 핵심 리소스를 완벽히 이해해야 합니다: Pod, Deployment, Service. 이 세 가지는 Kubernetes에서 애플리케이션을 배포하고 운영하는 데 가장 기본이 되는 빌딩 블록입니다. 이번 8편에서는 각 리소스의 개념, YAML 작성법, 그리고 실제 사용 패턴까지 상세히 알아보겠습니다.

1. Pod 상세 이해

Pod는 Kubernetes에서 배포 가능한 가장 작은 단위입니다. 하나 이상의 컨테이너를 포함하며, 같은 Pod 내의 컨테이너들은 네트워크와 스토리지를 공유합니다.

1.1 Pod의 특징

  • 컨테이너 그룹: 하나의 Pod에 여러 컨테이너를 배치할 수 있음
  • 공유 네트워크: 같은 Pod 내 컨테이너는 localhost로 통신
  • 공유 스토리지: 볼륨을 통해 데이터 공유 가능
  • 일시적 존재: Pod는 언제든 삭제되고 재생성될 수 있음
  • 고유 IP: 각 Pod는 클러스터 내에서 고유한 IP 주소를 가짐

1.2 사이드카 패턴 (Sidecar Pattern)

사이드카 패턴은 메인 컨테이너를 보조하는 컨테이너를 함께 배치하는 패턴입니다. 로그 수집, 프록시, 설정 관리 등에 활용됩니다.

# sidecar-example.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-with-sidecar
spec:
  containers:
  # 메인 애플리케이션 컨테이너
  - name: web-app
    image: nginx:1.25
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx

  # 사이드카: 로그 수집
  - name: log-collector
    image: busybox
    command: ['sh', '-c', 'tail -F /var/log/nginx/access.log']
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx

  volumes:
  - name: shared-logs
    emptyDir: {}

1.3 Init Container

Init Container는 메인 컨테이너가 시작되기 전에 실행되는 초기화 컨테이너입니다. 데이터베이스 대기, 설정 파일 생성, 권한 설정 등에 사용됩니다.

# init-container-example.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
  # 첫 번째 Init Container: DB 대기
  - name: wait-for-db
    image: busybox
    command: ['sh', '-c', 'until nc -z mysql-service 3306; do echo waiting for db; sleep 2; done']

  # 두 번째 Init Container: 설정 파일 준비
  - name: prepare-config
    image: busybox
    command: ['sh', '-c', 'cp /config-source/app.conf /config/app.conf']
    volumeMounts:
    - name: config-volume
      mountPath: /config
    - name: config-source
      mountPath: /config-source

  containers:
  - name: main-app
    image: my-app:latest
    volumeMounts:
    - name: config-volume
      mountPath: /app/config

  volumes:
  - name: config-volume
    emptyDir: {}
  - name: config-source
    configMap:
      name: app-config

1.4 Pod YAML 작성

완전한 Pod YAML 예제를 살펴보겠습니다.

# complete-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: web
    environment: production
  annotations:
    description: "프로덕션 웹 서버"
spec:
  # 재시작 정책
  restartPolicy: Always  # Always, OnFailure, Never

  # 노드 선택
  nodeSelector:
    disktype: ssd

  # 컨테이너 정의
  containers:
  - name: web
    image: nginx:1.25

    # 포트 설정
    ports:
    - name: http
      containerPort: 80
      protocol: TCP

    # 리소스 제한
    resources:
      requests:
        memory: "128Mi"
        cpu: "250m"
      limits:
        memory: "256Mi"
        cpu: "500m"

    # 환경 변수
    env:
    - name: ENV_NAME
      value: "production"
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secrets
          key: password

    # 헬스 체크
    livenessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 30
      periodSeconds: 10

    readinessProbe:
      httpGet:
        path: /ready
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5

    # 볼륨 마운트
    volumeMounts:
    - name: data-volume
      mountPath: /data

  volumes:
  - name: data-volume
    persistentVolumeClaim:
      claimName: my-pvc

2. Deployment 완전 이해

Deployment는 Pod의 선언적 업데이트를 관리합니다. ReplicaSet을 통해 원하는 수의 Pod를 유지하고, 롤링 업데이트와 롤백 기능을 제공합니다.

2.1 Deployment와 ReplicaSet의 관계

Deployment는 ReplicaSet을 생성하고 관리합니다. ReplicaSet은 지정된 수의 Pod 복제본을 유지합니다.

  • Deployment: 상위 레벨 추상화, 업데이트 전략 관리
  • ReplicaSet: Pod 복제본 수 유지
  • Pod: 실제 애플리케이션 실행

2.2 Deployment YAML 작성

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  labels:
    app: web
spec:
  # 복제본 수
  replicas: 3

  # 셀렉터 (어떤 Pod를 관리할지)
  selector:
    matchLabels:
      app: web

  # 업데이트 전략
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 추가로 생성할 수 있는 Pod 수
      maxUnavailable: 0  # 사용 불가능한 Pod 최대 수

  # Pod 템플릿
  template:
    metadata:
      labels:
        app: web
        version: v1
    spec:
      containers:
      - name: web
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3

2.3 롤링 업데이트

롤링 업데이트는 점진적으로 새 버전의 Pod를 배포하면서 기존 Pod를 교체합니다.

# 이미지 업데이트 (롤링 업데이트 트리거)
kubectl set image deployment/web-deployment web=nginx:1.26

# 업데이트 상태 확인
kubectl rollout status deployment/web-deployment

# 업데이트 히스토리 확인
kubectl rollout history deployment/web-deployment

# 특정 리비전 상세 확인
kubectl rollout history deployment/web-deployment --revision=2

2.4 롤백

문제가 발생하면 이전 버전으로 쉽게 롤백할 수 있습니다.

# 이전 버전으로 롤백
kubectl rollout undo deployment/web-deployment

# 특정 리비전으로 롤백
kubectl rollout undo deployment/web-deployment --to-revision=2

# 롤백 후 상태 확인
kubectl rollout status deployment/web-deployment

3. 스케일링

Kubernetes는 수동 스케일링과 자동 스케일링(HPA)을 모두 지원합니다.

3.1 수동 스케일링

# 복제본 수 조정
kubectl scale deployment/web-deployment --replicas=5

# 현재 상태 확인
kubectl get deployment web-deployment

# YAML 수정을 통한 스케일링
kubectl edit deployment web-deployment

3.2 HPA (Horizontal Pod Autoscaler)

HPA는 CPU, 메모리 사용량 또는 커스텀 메트릭을 기반으로 자동으로 Pod 수를 조절합니다.

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-deployment

  minReplicas: 2
  maxReplicas: 10

  metrics:
  # CPU 기반 스케일링
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

  # 메모리 기반 스케일링
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

  # 스케일링 동작 세부 설정
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 스케일 다운 전 대기 시간
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
      - type: Percent
        value: 100
        periodSeconds: 15
      - type: Pods
        value: 4
        periodSeconds: 15
      selectPolicy: Max
# HPA 생성 (명령어)
kubectl autoscale deployment web-deployment --min=2 --max=10 --cpu-percent=70

# HPA 상태 확인
kubectl get hpa

# HPA 상세 정보
kubectl describe hpa web-hpa

4. Service 종류

Service는 Pod 집합에 대한 안정적인 네트워크 엔드포인트를 제공합니다. Pod의 IP는 변경될 수 있지만, Service의 IP는 고정됩니다.

4.1 ClusterIP (기본값)

클러스터 내부에서만 접근 가능한 가상 IP를 제공합니다.

# clusterip-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: ClusterIP  # 기본값이므로 생략 가능
  selector:
    app: web
  ports:
  - name: http
    protocol: TCP
    port: 80        # 서비스 포트
    targetPort: 80  # Pod 포트

사용 사례: 내부 마이크로서비스 간 통신, 데이터베이스 연결

4.2 NodePort

각 노드의 특정 포트를 통해 외부에서 접근할 수 있습니다.

# nodeport-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort
  selector:
    app: web
  ports:
  - name: http
    protocol: TCP
    port: 80         # 서비스 포트
    targetPort: 80   # Pod 포트
    nodePort: 30080  # 노드 포트 (30000-32767)

사용 사례: 개발/테스트 환경, 로드밸런서 없이 외부 접근 필요 시

4.3 LoadBalancer

클라우드 제공업체의 로드밸런서를 통해 외부 IP를 할당받습니다.

# loadbalancer-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-loadbalancer
  annotations:
    # AWS 예시
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
  - name: https
    protocol: TCP
    port: 443
    targetPort: 443

사용 사례: 프로덕션 환경의 외부 서비스 노출

4.4 ExternalName

외부 서비스에 대한 DNS CNAME을 제공합니다.

# externalname-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: db.example.com

사용 사례: 외부 데이터베이스, 외부 API 서비스 연결

4.5 Service YAML 종합 예제

# complete-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-service
  labels:
    app: web
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "80"
spec:
  type: ClusterIP

  selector:
    app: web
    environment: production

  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: http  # Pod의 포트 이름 참조
  - name: https
    protocol: TCP
    port: 443
    targetPort: https

  # 세션 어피니티 (같은 클라이언트는 같은 Pod로)
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600

5. 레이블과 셀렉터

레이블과 셀렉터는 Kubernetes 리소스를 조직화하고 연결하는 핵심 메커니즘입니다.

5.1 레이블 (Labels)

레이블은 리소스에 부착하는 키-값 쌍입니다.

# 레이블 예시
metadata:
  labels:
    app: web
    environment: production
    version: v1.0.0
    team: backend
    tier: frontend
# 레이블로 리소스 조회
kubectl get pods -l app=web
kubectl get pods -l 'environment in (production, staging)'
kubectl get pods -l app=web,environment=production

# 레이블 추가/수정
kubectl label pods my-pod new-label=new-value

# 레이블 삭제
kubectl label pods my-pod new-label-

# 모든 레이블 표시
kubectl get pods --show-labels

5.2 셀렉터 (Selectors)

셀렉터는 레이블을 기반으로 리소스를 선택합니다.

# 등호 기반 셀렉터 (Equality-based)
selector:
  matchLabels:
    app: web
    environment: production

# 집합 기반 셀렉터 (Set-based)
selector:
  matchLabels:
    app: web
  matchExpressions:
  - key: environment
    operator: In
    values:
    - production
    - staging
  - key: version
    operator: NotIn
    values:
    - v1.0.0
  - key: team
    operator: Exists

5.3 레이블과 셀렉터 활용 예제

# 완전한 배포 예제
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  labels:
    app: web
    environment: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      environment: production
  template:
    metadata:
      labels:
        app: web
        environment: production
        version: v2.0.0
    spec:
      containers:
      - name: web
        image: nginx:1.25
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
    environment: production
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

6. 실전 명령어 정리

6.1 Pod 관련

# Pod 조회
kubectl get pods
kubectl get pods -o wide
kubectl get pods -w  # 실시간 감시

# Pod 상세 정보
kubectl describe pod my-pod

# Pod 로그 확인
kubectl logs my-pod
kubectl logs my-pod -c container-name  # 특정 컨테이너
kubectl logs my-pod -f  # 실시간 로그
kubectl logs my-pod --previous  # 이전 컨테이너 로그

# Pod 내부 접속
kubectl exec -it my-pod -- /bin/bash
kubectl exec -it my-pod -c container-name -- /bin/sh

# Pod 삭제
kubectl delete pod my-pod
kubectl delete pod my-pod --grace-period=0 --force  # 강제 삭제

6.2 Deployment 관련

# Deployment 관리
kubectl create deployment nginx --image=nginx
kubectl get deployments
kubectl describe deployment my-deployment

# 업데이트 및 롤백
kubectl set image deployment/my-deployment container=image:tag
kubectl rollout status deployment/my-deployment
kubectl rollout history deployment/my-deployment
kubectl rollout undo deployment/my-deployment

# 스케일링
kubectl scale deployment/my-deployment --replicas=5

# 일시 중지/재개
kubectl rollout pause deployment/my-deployment
kubectl rollout resume deployment/my-deployment

6.3 Service 관련

# Service 관리
kubectl expose deployment my-deployment --port=80 --type=ClusterIP
kubectl get services
kubectl describe service my-service

# 서비스 엔드포인트 확인
kubectl get endpoints my-service

# 포트 포워딩 (로컬 테스트용)
kubectl port-forward service/my-service 8080:80

결론

이번 8편에서는 Kubernetes의 핵심 리소스인 Pod, Deployment, Service에 대해 깊이 있게 살펴보았습니다. Pod는 컨테이너 그룹의 기본 단위이며 사이드카 패턴과 Init Container를 통해 다양한 패턴을 구현할 수 있습니다. Deployment는 Pod의 선언적 관리와 롤링 업데이트, 롤백 기능을 제공하며, HPA를 통해 자동 스케일링도 가능합니다. Service는 Pod에 대한 안정적인 네트워크 접근을 제공하며, 용도에 따라 ClusterIP, NodePort, LoadBalancer 등을 선택할 수 있습니다.

레이블과 셀렉터를 활용하면 이러한 리소스들을 유연하게 연결하고 관리할 수 있습니다. 다음 편에서는 ConfigMap, Secret, Volume 등 데이터와 설정 관리에 대해 알아보겠습니다.