쿠버네티스 공부하기! 디플로이먼트와 파드의 차이

반응형

1. Pod란 무엇인가?

Pod는 쿠버네티스에서 생성하고 관리할 수 있는 가장 작은 배포 단위이다. 하나의 Pod는 하나 이상의 컨테이너 그룹으로 구성되며, 스토리지와 네트워크 리소스를 공유하고, 컨테이너 실행 방법에 대한 명세를 포함한다.

같은 Pod에 속한 컨테이너는 항상 같은 노드에 함께 배치되고 함께 스케줄링되며, 공유된 컨텍스트에서 실행된다.

Pod는 애플리케이션 관점의 "논리적 호스트(logical host)"를 모델링한다. 즉, 비교적 밀접하게 결합된 하나 이상의 애플리케이션 컨테이너를 포함한다.

아래는 쿠버네티스 클러스터의 전체 구조를 나타낸 공식 다이어그램이다. Pod는 노드(Node) 위에서 실행되며, 노드들이 모여 클러스터를 구성한다.

 

쿠버네티스 클러스터 컴포넌트

이미지 출처: Kubernetes Documentation - Cluster Architecture

 

2. Pod의 한계

직접 생성한 Pod에는 다음과 같은 한계가 있다.

  • Pod가 속한 노드에 장애가 발생하면 해당 Pod는 사라진다.
  • Pod가 종료되면 자동으로 다시 생성되지 않는다.
  • 복제본을 늘리거나 줄이는 기능이 없다.
  • 새 버전으로의 업데이트나 롤백 기능이 없다.
    이러한 이유로 쿠버네티스는 Pod를 직접 생성하는 대신, 워크로드 리소스와 그 컨트롤러를 통해 Pod를 관리하는 것을 권장한다.

 

3. Deployment란 무엇인가?

Deployment는 일반적으로 상태를 유지하지 않는(stateless) 애플리케이션 워크로드를 실행하기 위해 Pod 집합을 관리하는 리소스이다.

Deployment는 Pod와 ReplicaSet에 대한 선언적(declarative) 업데이트를 제공한다. 사용자가 Deployment에 원하는 상태(desired state)를 기술하면, Deployment 컨트롤러가 실제 상태(actual state)를 원하는 상태로 정해진 비율에 따라 변경한다.

여기서 등장하는 "상태를 유지하지 않는다", "선언적", "원하는 상태" 같은 표현은 처음 보면 이해하기 어렵다.

 

4. 상태를 유지하지 않는다는 것 (Stateless)

여기서 말하는 상태(state)는 애플리케이션이 기억하고 있어야 하는 데이터를 의미한다.

웹 서버를 예로 들어 보자. 사용자가 어떤 페이지를 요청하면 서버는 응답을 만들어 돌려준다. 이때 서버는 직전 요청이 무엇이었는지 기억할 필요가 없으며, 매 요청을 독립적으로 처리한다. 이러한 애플리케이션을 상태를 유지하지 않는(stateless) 애플리케이션이라고 한다.

이 특성이 중요한 이유는 다음과 같다. 애플리케이션이 stateless하면 그 Pod는 언제든 다른 Pod로 교체할 수 있다. 어떤 Pod가 죽어서 새 Pod로 대체되어도, 새 Pod 역시 요청을 동일하게 처음부터 처리하므로 사용자 입장에서는 차이가 없다. 즉, Pod끼리 서로 대체 가능(interchangeable)하다. Deployment가 Pod를 자유롭게 생성하고 종료하고 다른 노드로 이동시킬 수 있는 것은 바로 이 특성 덕분이다.

반대로 상태를 유지하는(stateful) 애플리케이션은 데이터를 기억해야 한다. 대표적인 예가 데이터베이스이다. 데이터베이스 Pod는 자신이 가진 데이터가 곧 정체성이므로, 함부로 종료하고 새 Pod로 교체하면 데이터가 손실된다. 이러한 애플리케이션은 Deployment가 아니라 StatefulSet이라는 별도의 리소스로 관리한다.

두 경우를 비교하면 다음과 같다.

  • Stateless 애플리케이션: 콜센터 상담원에 비유할 수 있다. 누가 전화를 받든 상관없으며, 한 명이 자리를 비우면 다른 사람이 받으면 된다.
  • Stateful 애플리케이션: 환자의 병력을 기억하는 주치의에 비유할 수 있다. 특정 인물을 다른 사람으로 대체할 수 없다.
    Deployment가 stateless 애플리케이션에 적합하다고 하는 것은 이러한 맥락이다.

 

5. 제어 루프와 원하는 상태 (Control Loop)

제어 루프는 쿠버네티스가 어떻게 자동으로 동작하는지를 설명하는 핵심 원리이다. 쿠버네티스 공식 문서는 이를 온도 조절기에 비유한다.

집에 있는 보일러 온도계를 22도로 설정했다고 하자. 그러면 다음과 같은 과정이 반복된다.

  1. 원하는 상태(desired state): 22도. 사용자가 설정한 값이다.
  2. 실제 상태(actual state): 현재 방의 온도. 예를 들어 19도이다.
  3. 온도계가 둘을 비교하여 차이를 확인하고, 보일러를 켠다.
  4. 방이 22도에 도달하면 보일러를 끈다.
  5. 다시 온도가 내려가면 1번으로 돌아가 과정을 반복한다.
    이처럼 실제 상태와 원하는 상태를 비교하고, 차이를 메우고, 다시 비교하는 과정을 끝없이 반복하는 것이 제어 루프이다. 한 번 실행되고 끝나는 것이 아니라 멈추지 않고 계속 동작한다.

쿠버네티스의 컨트롤러는 이 온도계와 동일하게 동작한다. Deployment에 replicas: 3이라고 지정하면 다음 과정이 반복된다.

  1. 원하는 상태: Pod 3개
  2. 실제 상태: 현재 실행 중인 Pod의 수. 예를 들어 하나가 죽어서 2개이다.
  3. 컨트롤러가 둘을 비교하여 1개가 부족함을 확인하고, 새 Pod를 생성한다.
  4. 다시 Pod가 3개가 된다.
  5. 또 하나가 죽으면 1번으로 돌아가 과정을 반복한다.
    Pod가 죽어도 자동으로 복구되는 것은 이 때문이다. 사람이 상태를 지켜보다가 Pod를 만드는 것이 아니라, 컨트롤러가 온도계처럼 쉬지 않고 실제 상태와 원하는 상태를 비교하며 차이를 메우고 있기 때문이다.

이 과정에서 사용자가 하는 일은 "Pod를 몇 개 만들어라"라고 명령하는 것이 아니라, "Pod가 3개인 상태를 원한다"라고 결과를 기술하는 것뿐이다. 이렇게 원하는 결과만 선언하면 시스템이 알아서 그 상태로 맞추는 방식을 선언적(declarative) 방식이라고 한다.

 

6. 두 개념의 연결

Stateless와 제어 루프는 서로 이어져 있다. 제어 루프는 Pod가 부족하면 새 Pod를 생성한다. 그런데 새로 만든 Pod가 죽은 Pod와 동일하게 동작하려면, 그 Pod가 stateless해야 한다. 만약 stateful한 Pod였다면 새 Pod는 이전 Pod의 데이터를 알지 못하므로, 이는 복구가 아니라 데이터 손실이 된다.

따라서 Deployment는 다음과 같이 정리할 수 있다. 제어 루프를 통해 Pod 개수를 자동으로 유지하되, 그 동작이 의미를 가지려면 Pod가 서로 대체 가능한 stateless 상태여야 한다.

 

7. Pod와 Deployment의 계층 관계

Deployment는 Pod를 직접 관리하지 않는다. Deployment는 ReplicaSet을 관리하고, ReplicaSet이 Pod를 관리한다.

Deployment → ReplicaSet → Pod

 

각 리소스의 역할은 다음과 같다.

  • ReplicaSet: 지정된 수의 동일한 Pod 복제본이 항상 실행되고 있음을 보장한다. Pod가 너무 많으면 초과분을 종료하고, 너무 적으면 추가로 생성한다.
  • Deployment: ReplicaSet을 소유하며, 선언적 방식의 서버 측 롤링 업데이트를 통해 ReplicaSet과 그에 속한 Pod를 업데이트한다.
    롤링 업데이트가 발생하면 Deployment는 새 ReplicaSet을 생성하고 기존 ReplicaSet의 Pod 수를 점진적으로 줄이면서 새 ReplicaSet으로 전환한다. 기존 ReplicaSet은 리비전 이력으로 남아 있으므로, 이전 상태로의 롤백이 가능하다.

공식 문서는 ReplicaSet을 직접 다루지 않고 Deployment를 사용할 것을 권장하며, Deployment가 소유한 ReplicaSet을 직접 관리하지 말 것을 명시하고 있다.

 

8. Deployment의 주요 사용 사례

Deployment의 대표적인 사용 사례는 다음과 같다.

  • 롤아웃: ReplicaSet을 롤아웃하기 위한 Deployment를 생성한다. ReplicaSet은 백그라운드에서 Pod를 생성한다.
  • 업데이트: Deployment의 PodTemplateSpec을 업데이트하여 Pod의 새로운 상태를 선언한다. 새 ReplicaSet이 생성되고, 정해진 비율로 기존 ReplicaSet에서 새 ReplicaSet으로 Pod가 이전된다.
  • 롤백: 이전 Deployment 리비전으로 되돌린다.
  • 스케일링: 부하 처리를 위해 Deployment를 스케일 업 한다.

 

9. 매니페스트 비교

1) Pod

직접 정의한 단일 Pod 매니페스트이다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80

 

2) Deployment

동일한 Pod를 세 개의 복제본으로 관리하는 Deployment 매니페스트이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

 

Deployment 매니페스트의 구성 요소는 다음과 같다.

  • spec.replicas: 유지할 Pod 복제본의 수를 지정한다. 이 값이 제어 루프의 원하는 상태가 된다.
  • spec.selector: Deployment가 관리할 Pod를 식별하는 기준이다. matchLabels에 지정된 레이블을 가진 Pod를 대상으로 한다.
  • spec.template: 생성할 Pod의 명세(PodTemplate)이다. template.metadata.labels의 레이블은 selector.matchLabels와 일치해야 한다.
    spec.template 하위의 내용은 단일 Pod 매니페스트의 spec과 거의 동일하다. Deployment는 이 템플릿을 기준으로 Pod를 생성하며, replicas 값에 따라 해당 수의 Pod를 유지한다.

 

10. 생성 및 상태 확인

kubectl apply -f nginx-deployment.yaml
kubectl get deployments

 

kubectl get deployments 출력에 표시되는 필드는 다음과 같다.

  • NAME: 네임스페이스 내 Deployment의 이름
  • READY: 사용자가 사용할 수 있는 복제본의 수를 사용 가능/원하는 수 형식으로 표시
  • UP-TO-DATE: 원하는 상태에 도달하기 위해 업데이트된 복제본의 수
  • AVAILABLE: 사용자가 사용할 수 있는 복제본의 수정리

Pod는 컨테이너를 실행하는 가장 작은 단위이지만 자체적인 복구 및 스케일링 기능이 없다. Deployment는 ReplicaSet을 통해 Pod 집합을 관리하며, 원하는 상태 유지, 스케일링, 롤링 업데이트, 롤백을 선언적으로 제공한다.

이 글에서 다룬 핵심 개념을 요약하면 다음과 같다.

  • Stateless: 애플리케이션이 데이터를 기억하지 않아 Pod끼리 서로 대체할 수 있는 특성이다. Deployment가 Pod를 자유롭게 교체할 수 있는 전제 조건이다.
  • 제어 루프: 실제 상태와 원하는 상태를 끊임없이 비교하며 차이를 메우는 동작 방식이다. Pod가 죽어도 자동으로 복구되는 원리이다.
  • 선언적 방식: 수행할 동작이 아니라 원하는 결과를 기술하면 시스템이 그 상태로 맞추는 방식이다.
  • 계층 관계: Deployment는 ReplicaSet을 관리하고, ReplicaSet이 Pod를 관리한다.
    상태를 유지하지 않는 애플리케이션을 클러스터에서 실행하는 가장 일반적인 방법은 Deployment를 사용하는 것이다.

 

참고 문서

반응형