7.2.2 레플리카셋 명세 (Spec) 분석

앞서 레플리카셋이 지정된 수의 파드 복제본을 유지하고, 장애 발생 시 자동으로 복구하는 역할을 한다고 말씀드렸습니다. 그렇다면 레플리카셋은 이러한 역할을 수행하기 위해 어떤 정보를 필요로 할까요? 바로 레플리카셋 명세(Spec)를 통해 이러한 정보들이 정의됩니다.

쿠버네티스의 모든 오브젝트와 마찬가지로, 레플리카셋 또한 YAML(또는 JSON) 형식의 매니페스트 파일을 통해 선언적으로 정의됩니다. 이 명세 파일에는 레플리카셋의 이름, 레이블과 같은 메타데이터와 함께, 레플리카셋이 어떻게 동작해야 하는지를 기술하는 spec 필드가 포함됩니다. spec 필드에는 레플리카셋의 핵심 동작을 결정짓는 중요한 하위 필드들이 있는데, 이들을 이해하는 것은 레플리카셋을 효과적으로 사용하는 첫걸음입니다.

마치 요리 레시피처럼, 레플리카셋 명세는 쿠버네티스에게 ‘어떤 재료(파드 템플릿)를 사용해서, 몇 개의 요리(파드 복제본)를 만들고, 이 요리들을 어떻게 식별(셀렉터)할 것인지’를 상세히 알려주는 지시서와 같습니다. 이제부터 레플리카셋 명세의 핵심 필드인 replicas, selector, template에 대해 하나씩 자세히 살펴보겠습니다.

7.2.2.1 replicas 필드

레플리카셋 명세에서 가장 직관적이면서도 중요한 필드 중 하나가 바로 replicas 필드입니다. 이 필드는 레플리카셋이 항상 유지해야 하는 파드의 복제본 수를 명시적으로 지정합니다. 간단히 말해, “나는 이 파드를 N개 실행하고 싶어”라고 쿠버네티스에게 알리는 부분입니다.

예를 들어, replicas: 3이라고 명세에 정의하면, 레플리카셋은 현재 클러스터에 해당 파드가 3개 실행되도록 관리합니다. 만약 현재 실행 중인 파드가 2개뿐이라면, 레플리카셋은 파드 템플릿(뒤이어 설명할 template 필드)을 기반으로 새로운 파드 1개를 추가로 생성합니다. 반대로, 만약 어떤 이유로 4개의 파드가 실행 중이라면, 레플리카셋은 1개의 파드를 종료시켜 3개를 유지하려고 시도합니다.

이 replicas 필드 값은 정수(integer)로 표현되며, 0 이상의 값을 가질 수 있습니다.

  • replicas: 0: 만약 replicas 값을 0으로 설정하면, 레플리카셋은 자신이 관리하는 모든 파드를 종료시킵니다. 이는 특정 애플리케이션을 일시적으로 중단시키거나, 더 이상 필요 없는 레플리카셋을 정리하기 전에 파드들을 먼저 안전하게 제거하는 용도로 사용될 수 있습니다.
  • replicas > 0: 0보다 큰 값을 설정하면, 해당 숫자만큼의 파드 복제본을 유지하려고 노력합니다. 이 값이 클수록 더 많은 트래픽을 처리할 수 있고, 일부 파드에 장애가 발생하더라도 서비스 가용성을 높일 수 있습니다.

replicas 필드는 애플리케이션의 확장성(Scalability)을 직접적으로 제어하는 수단입니다. 서비스에 대한 부하가 증가하면 이 값을 늘려 파드 수를 확장(scale-out)할 수 있고, 부하가 감소하면 값을 줄여 자원을 효율적으로 사용할 수 있도록 축소(scale-in)할 수 있습니다. 물론, 실제 운영 환경에서는 사용량에 따라 자동으로 replicas 값을 조절해주는 Horizontal Pod Autoscaler (HPA)와 같은 고급 기능을 함께 사용하기도 합니다. 하지만 그 기반에는 이 replicas 필드가 핵심적인 역할을 하고 있음을 기억해야 합니다.

이처럼 replicas 필드는 레플리카셋의 가장 기본적인 목표, 즉 ‘원하는 수의 파드를 유지한다’는 것을 정의하는 핵심 지표입니다. 이 값 하나를 변경하는 것만으로도 쿠버네티스는 자동으로 파드를 생성하거나 삭제하여 우리가 원하는 상태를 만들어주니, 정말 편리하지 않나요?

7.2.2.2 selector 필드 (파드 식별)

레플리카셋은 replicas 필드를 통해 ‘몇 개의 파드를 유지할 것인가’를 알게 됩니다. 그렇다면 다음 질문은 ‘어떤 파드들을 그 수에 맞춰 관리할 것인가?’가 될 것입니다. 레플리카셋은 클러스터 내의 수많은 파드 중에서 자신이 관리해야 할 대상을 정확히 식별할 수 있어야 합니다. 바로 이 역할을 하는 것이 selector 필드입니다.

selector 필드는 레플리카셋이 어떤 레이블(Label)을 가진 파드들을 자신의 관리 대상으로 삼을지 정의합니다. 쿠버네티스에서 레이블은 파드를 비롯한 다양한 오브젝트에 ‘키-값’ 쌍으로 태그를 붙이는 방식입니다. 예를 들어, app: my-nginx 또는 tier: frontend 와 같이 특정 애플리케이션이나 역할을 나타내는 레이블을 파드에 부여할 수 있습니다.

레플리카셋의 selector는 이러한 레이블을 기준으로 파드를 필터링합니다. selector에 명시된 레이블 조건을 만족하는 파드들만이 해당 레플리카셋의 관리 범위에 포함됩니다.

selector 필드는 주로 두 가지 방식으로 레이블을 매칭합니다.

  1. matchLabels: 가장 일반적이고 간단한 방식입니다. 여기에 명시된 ‘키-값’ 쌍의 레이블들이 파드의 레이블과 정확히 일치해야 합니다.
    클립보드에 복사
    위 예시에서 레플리카셋은 app: my-app 레이블과 environment: production 레이블을 모두 가지고 있는 파드들만을 관리 대상으로 인식합니다.
  2. matchExpressions: 좀 더 복잡하고 유연한 조건을 설정할 수 있게 해줍니다. key, operator, values 세 가지 항목으로 표현식을 구성합니다.
    • key: 레이블의 키를 지정합니다.
    • operator: 매칭 조건을 지정합니다.
      • In: values 배열에 포함된 값 중 하나라도 레이블 값과 일치하면 매칭됩니다.
      • NotIn: values 배열에 포함된 값과 모두 일치하지 않아야 매칭됩니다.
      • Exists: 해당 key를 가진 레이블이 존재하기만 하면 매칭됩니다 (values 불필요).
      • DoesNotExist: 해당 key를 가진 레이블이 존재하지 않아야 매칭됩니다 (values 불필요).
    • values: operator가 In 또는 NotIn일 경우 비교할 값들의 배열입니다.
      클립보드에 복사
      위 예시에서 레플리카셋은 tier 레이블 값이 frontend 또는 backend이고, version 레이블 값이 deprecated가 아니며, experimental 레이블을 가지고 있는 파드들을 관리합니다.

매우 중요한 점은 selector 필드에 정의된 레이블 조건이 바로 다음에 설명할 template.metadata.labels 필드에 정의된 레이블과 반드시 일치해야 한다는 것입니다. 만약 이 둘이 일치하지 않으면, 레플리카셋은 자신이 생성한 파드를 자신이 관리해야 할 파드로 인식하지 못하는 문제가 발생합니다. 이 경우 레플리카셋은 계속해서 ‘관리해야 할 파드가 부족하다’고 판단하여 무한정 새로운 파드를 생성하려고 시도할 수 있습니다. 이는 초보자들이 흔히 겪는 실수 중 하나이므로 꼭 기억해두셔야 합니다.

정리하자면, selector는 레플리카셋에게 “이러이러한 이름표(레이블)를 단 아이들(파드)만 내 책임하에 돌봐줘!”라고 지시하는 것과 같습니다. 이 지시가 명확해야만 레플리카셋은 자신의 임무를 정확히 수행할 수 있습니다.

7.2.2.3 template 필드 (파드 명세)

지금까지 레플리카셋이 ‘몇 개의'(replicas) ‘어떤'(selector) 파드를 관리할지 정의하는 방법을 보았습니다. 이제 마지막으로 ‘만약 파드가 부족해서 새로 만들어야 한다면, 어떤 모습의 파드를 만들어야 할까?’에 대한 답이 필요합니다. 이 역할을 하는 것이 바로 template 필드입니다.

template 필드는 레플리카셋이 새로운 파드를 생성할 때 사용할 파드의 청사진 또는 설계도와 같습니다. 이 필드 안에는 완전한 하나의 파드 명세(Pod Spec)가 그대로 포함됩니다. 즉, 우리가 독립적으로 파드를 정의할 때 사용하는 apiVersion, kind, metadata, spec 구조가 template 필드 하위에 중첩되어 들어가는 형태입니다.

template 필드의 주요 구성 요소를 살펴보겠습니다.

  • template.metadata:
    • labels: 여기에 정의된 레이블은 새로 생성될 파드에 부착됩니다. 앞서 강조했듯이, 이 template.metadata.labels는 레플리카셋의 최상위 selector 필드와 반드시 일치하거나, 최소한 selector의 조건을 만족해야 합니다. 이것이 일치하지 않으면 레플리카셋은 자신이 생성한 파드를 제어할 수 없습니다. 예를 들어, selector.matchLabels가 app: my-app 이라면, template.metadata.labels 에도 app: my-app 이 반드시 포함되어야 합니다.
    • annotations: 파드에 추가적인 메타데이터를 부여할 때 사용됩니다.
  • template.spec:
    • 이 부분은 일반적인 파드 명세의 spec 부분과 동일합니다. 즉, 파드가 어떤 컨테이너를 실행할지, 어떤 이미지를 사용할지, 어떤 포트를 노출할지, 어떤 환경 변수를 가질지, 어떤 볼륨을 마운트할지 등 파드의 실제 동작을 정의하는 모든 내용이 여기에 기술됩니다.
    • 예를 들어, containers 배열 안에는 하나 이상의 컨테이너 정의가 포함되며, 각 컨테이너는 name, image, ports 등의 필드를 가집니다.

아래는 레플리카셋 명세에서 template 필드가 어떻게 사용되는지 보여주는 간단한 예시입니다.

클립보드에 복사

위 예시에서 template 필드는 app: my-nginx-pod와 version: “1.0” 레이블을 가지고, nginx:1.21 이미지를 사용하는 nginx-container라는 이름의 컨테이너를 하나 실행하며, 80번 포트를 노출하는 파드를 생성하도록 정의하고 있습니다. 레플리카셋은 이 template을 사용하여 replicas: 3에 맞춰 3개의 동일한 파드를 생성하고, selector.matchLabels.app: my-nginx-pod를 통해 이들을 관리합니다.

중요한 점은, 레플리카셋이 한번 생성된 후에는 template 필드를 직접 수정하는 것이 일반적이지 않다는 것입니다. 만약 파드의 정의(예: 컨테이너 이미지 버전 변경)를 업데이트하고 싶다면, 보통 새로운 template을 가진 새로운 레플리카셋을 만들거나, 더 상위 레벨의 컨트롤러인 디플로이먼트(Deployment)를 사용하여 롤링 업데이트를 수행합니다. 디플로이먼트는 내부적으로 레플리카셋을 이용하여 이러한 업데이트 과정을 안전하고 효율적으로 관리해줍니다.

결론적으로, template 필드는 레플리카셋이 “이 설계도대로 똑같은 파드들을 만들어줘!”라고 쿠버네티스에 전달하는 역할을 합니다. 이 설계도가 명확하고 정확해야만, 레플리카셋은 우리가 의도한 대로 애플리케이션 인스턴스들을 생성하고 관리할 수 있습니다.

지금까지 살펴본 replicas, selector, template 필드는 레플리카셋의 동작을 이해하는 데 있어 가장 핵심적인 세 가지 요소입니다. 이들이 어떻게 상호작용하는지 정확히 파악하신다면, 쿠버네티스에서 애플리케이션을 안정적으로 배포하고 운영하는 데 큰 도움이 될 것입니다.