본 글은 쿠버네티스 스터디를 목적으로 책 '쿠버네티스 인 액션' 을 매주 1장 단위로 읽고 정리한 것입니다.

  • 복제된 파드에 개별 스토리지 제공
  • 파드에 안정적인 아이덴티티 제공
  • 스테이트풀셋을 위한 헤드리스 거버닝 서비스 생성
  • 스테이프풀셋 스케일링 및 업데이트
  • DNS를 통한 스테이트풀셋 피어 디스커버리
  • 호스트 이름을 통한 다른 멤버 연결
  • 스테이트풀 파드 강제 삭제

10. 1 스테이트풀 파드 복제하기 (스테이트풀셋의 필요성)

10. 1. 1 개별 스토리지를 갖는 레플리카 여러 개 실행하기

레플리카셋을 통해 파드 템플릿으로 여러 파드 레플리카를 생성하는 경우, 각 레플리카가 별도의 퍼시스턴트 볼륨 클레임을 사용하도록 만들 수 없음. 각 인스턴스 별로 각각의 스토리지를 갖도록 하기 위해서는 레플리카셋 사용이 어려움. 개별 스토리지를 갖는 레플리카 여러 개를 만들기 위해서는 아래의 방법들이 존재함

  1. 수동으로 파드 생성하기
    단, 파드의 감시 및 관리 측면에서 번거로우므로 제외
  2. 파드 인스턴스 별로 각각의 레플리카셋 생성
    단, 스케일링 측면에서 레플리카 수 변경이 어려우므로 추가 레플리카셋을 수동으로 생성해주는 번거로움이 발생
  3. 동일 볼륨을 여러 디렉토리로 사용
    각 인스턴스가 생성되는 시점에 다른 인스턴스가 사용하지 않는 데이터 디렉터리를 자동으로 선택 혹은 생성하도록 함
    다만 인스턴스 간 조정이 필요하고 공유 스토리지 볼륨에 병목 현상이 발생할 우려가 있어 권고되진 않음

 

10. 1. 2 각 파드에 안정적인(장시간 지속적으로 변하지 않는) 아이덴티티 제공하기

파드가 교체되어 새로운 호스트 이름과 IP를 지니게 될 경우 새로운 네트워크 아이덴티티를 가지게 되는 것이므로
이때마다 애플리케이션의 모든 클러스터 멤버들의 각 설정 파일에 그 변경사항을 기재해줘야함
즉, 리스케줄링마다 애플리케이션 클러스터의 재구성이 진행되어야만 함

그럼에도 오랜 시간 지속적으로 변하지 않는 아이덴티티(호스트 이름과 IP 주소)를 애플리케이션에 제공해야 하는 경우가 생길 수 있음

이를 해결하기 위해서는 각 개별 멤버에 전용 쿠버네티스 서비스를 생성해 안정적인 네트워크 주소를 제공해야함

 

 

10. 2 스테이트풀셋 이해하기

위에서 설명한 유형의 파드를 실행하기 위해 레플리카셋을 사용하는 대신 스테이트풀셋 리소스를 생성

이는 애플리케이션의 인스턴스가 각각 안정적인 이름과 상태를 가지며 개별적으로 취급돼야 하는 애플리케이션에 알맞게 만들어졌음

 

공식문서에서는 구체적으로 아래와 같은 요구사항이 있는 애플리케이션에 사용하면 된다고 나와있음
https://kubernetes.io/ko/docs/concepts/workloads/controllers/statefulset/#스테이트풀셋-사용

안정된, 고유한 네트워크 식별자.
안정된, 지속성을 갖는 스토리지.
순차적인, 정상 배포(graceful deployment)와 스케일링.
순차적인, 자동 롤링 업데이트.

 

10. 2. 1 스테이트풀셋과 레플리카셋 비교하기

  레플리카셋 레플리케이션 컨트롤러 스테이트풀셋
파드 교체성
단순 교체
(Stateless)
삭제된 파드와 동일한 이름, 호스트 이름 보장 (Stateful)
레플리카 수 지정
레플리카셋, 레플리케이션 컨트롤러, 스테이트풀셋 모두 가능
파드 템플릿 사용
레플리카셋, 레플리케이션 컨트롤러, 스테이트풀셋 모두 가능
생성 파드 특성
자체 스토리지 미보유
각 파드별 자체 볼륨 세트 (스토리지)를 보유
무작위 아이덴티티
예측가능한 아이덴티티
(파드 및 호스트 이름, 거버닝 서비스)
스케일 업
동일한 파드이므로 무작위 생성
동일한 이름, 호스트이름, 아이덴티티 부여.
신규 파드에 대한 이름 예측 가능 (인덱스 +)
스케일 다운
동일한 파드이므로 무작위 삭제
가장 높은 인덱스 인스턴스를 항상 우선 삭제
인스턴스 전체가 정상일 경우만 진행

파드만 삭제하고 볼륨 클레임은 삭제하지 않음

10. 2. 2 안정적인 네트워크 아이덴티티 제공하기

안정적인 네트워크 아이덴티티는

  1. 파드 및 호스트 이름의 예측 가능성
  2. 자체 DNS 엔트리를 지니게 하는 파드별 네트워크 아이덴티티

등으로 구성됨

안정성과 예측 가능성을 높이기 위해 파드와 호스트의 이름은 정해진 규칙에 따라 명명됨

  • 스테이트풀셋의 이름을 활용
  • 스테이트풀셋이 생성한 파드에, 0부터 시작하는 서수 인덱스가 할당됨
  • 컨테이너 호스트 이름은 파드의 이름과 동일하게 설정됨

즉, 파드의 이름은 {statefulset_name}-{pod_index}의 형태

또한, 각 파드에게 실제 네트워크 아이덴티티를 제공하기 위해 '거버닝 헤드리스 서비스'를 스테이스풀셋이 생성

 

헤드리스 서비스 복습 :
때때로 로드-밸런싱과 단일 서비스 IP는 필요치 않다. 이 경우, "헤드리스" 서비스라는 것을 만들 수 있는데, 명시적으로 클러스터 IP (.spec.clusterIP)에 "None"을 지정한다. 쿠버네티스의 구현에 묶이지 않고, 헤드리스 서비스를 사용하여 다른 서비스 디스커버리 메커니즘과 인터페이스할 수 있다. 헤드리스 서비스의 경우, 클러스터 IP가 할당되지 않고, kube-proxy가 이러한 서비스를 처리하지 않으며, 플랫폼에 의해 로드 밸런싱 또는 프록시를 하지 않는다. DNS가 자동으로 구성되는 방법은 서비스에 셀렉터가 정의되어 있는지 여부에 달려있다.
출처 : https://kubernetes.io/ko/docs/concepts/services-networking/service/

 

각 파드는 이를 통해 자체 DNS 엔트리를 가지고 클러스터 피어 혹은 클러스터 내 다른 클라이언트가 호스트 이름으로 파드 주소 지정이 가능


FQDN은 '{pod-name}.{governing_service_name}.{namespace_name}.svc.cluster.local'과 같이 설정됨
이는 레플리카셋과는 구분되는 특성

 

또한 {governing_service_name}.{namespace_name}.svc.cluster.local 도메인으로 레코드를 조회하면
DNS를 통해 모든 스테이트풀셋 내 파드 이름을 조회할 수 있음

 

 

파드 교체

스테이트풀셋의 파드가 다시 스케줄링될 경우 레플리카셋과 마찬가지로 어느 노드에 생성되는가가 중요하지는 않지만
사라진 기존 파드의 이름 및 호스트 이름이 교체할 새로운 파드의 이름/호스트 이름과 동일하도록 보장
즉, 동일한 아이덴티티를 지닌 파드로 교체하는 것

 

10. 2. 3 각 스테이트풀 인스턴스에 안정적인 전용 스토리지 제공하기

리스케줄링이 되어도 신규 인스턴스가 기존에 사용하던 동일 스토리지에 연결되도록 하려면, 스테이트풀셋의 각 파드는 별도의 퍼시스턴트볼륨을 갖도록 서로 다른 퍼시스턴트 볼륨 클레임을 참조해야함
즉, 스테이트풀셋은 각 파드마다 퍼시스턴트 볼륨 클레임을 복제하도록 볼륨 클레임 템플릿을 가짐

 

스케일링

스테이트풀셋이 스케일링해서 새로운 파드를 추가로 생성한다면 위에 언급한 예측 가능한 이름 명명 규칙에 따라 기존 인스턴스 이후의 서수 인덱스를 부여

또한 항상 가장 높은 인덱스를 먼저 제거하기 때문에 스케일 다운 과정에서 어떤 파드를 삭제할 지도 예측 가능

 

단, 스테이트풀셋은 인스턴스 중 하나라도 정상 작동하지 않으면 스케일 다운이 진행되지 않음
이는 특정 스테이트풀 애플리케이션은 스케일 다운 시 시점 당 하나의 인스턴스만 스케일다운할 수 있어 그 속도가 느리다는 특성을 가질 수 있다는 점과 연관됨
예를 들어 데이터 엔트리마다 2개의 복제본을 저장하는 분산 데이터 저장소 애플리케이션이라면, 2개 노드가 동시에 다운되면 데이터를 잃으므로 순차적으로 하나씩 인스턴스를 스케일다운하면서 손실된 복사본을 대체할 추가 복제본을 다른 곳에 생성하는 시간이 소요됨
즉, 2개의 복제본 중 하나는 비정상이고 하나는 스케일 다운 대상이라면 동시에 2개가 다운된 상황이므로 2개의 클러스터 멤버의 상실이 일어나는 것

 

또한, 앞서 말했듯 스테이트풀셋은 스케일링함에 따라 파드만 생성하는 것이 아니라 파드가 참조할 퍼시스턴트볼륨 클레임을 템플릿에 따라 생성
그러나 스케일 다운 시에는 파드만 삭제하고 클레임은 삭제하지 않는데, 그 이유는 클레임에 바인딩된 퍼시스턴트볼륨이 재활용되거나 삭제될 염려가 있기 때문에 유지하는 것
볼륨에 저장된 데이터가 손실되지 않도록 자동으로 클레임을 삭제하지 않으며, 퍼시스턴트 볼륨 해제를 위해서는 수동으로 클레임을 삭제해줘야함
만약 클레임을 삭제하지 않았다면 그 이후 다시 스케일 업이 진행될 때 동일한 클레임이 새로운 파드와 연결되어 되돌릴 수 있고 지속적인 상태값을 가짐

 

10. 2. 4 스테이트풀셋 보장 이해하기

쿠버네티스가 파드 상태를 확인하기 어려울 경우에도 상관 없이 원하는 작업을 수행할 수 있도록, 스테이트풀셋은 동일한 아이덴티티를 가지는 교체 파드를 생성
즉, 기존 파드가 실행되지 않는 경우 동일하게 시스템에 실행되고 동일한 스토리지에 바인딩되고 동일한 파일을 작성하는 교체 파드를 생성해 실행하기 때문에 작업 수행의 성공을 보장한다는 의미

여러 스테이트풀 파드 인스턴스가 동시에 동일한 작업을 수행하지 않도록 최대 하나의 의미를 보장(at-most-one-semantics)해야함
즉, 교체 파드 생성 이전에 기존 파드가 실행 중이지 않음을 확신할 수 있어야 한다는 의미

 

10. 3 스테이트풀셋 사용하기

10. 3. 2 스테이트풀셋을 통한 애플리케이션 배포하기

스테이트풀 애플리케이션 배포에 필요한 오브젝트는 다음과 같음

  • 데이터 파일을 저장하기 위한 퍼시스턴트 볼륨 (동적 프로비저닝 혹은 수동)
  • 스테이트풀셋을 위한 거버닝 서비스
  • 스테이트풀셋

 

10. 4 스테이트풀셋의 피어 디스커버리

피어 디스커버리는 클러스터된 애플리케이션의 주요 사항 중 하나로 클러스터의 다른 멤버를 찾는 기능을 의미

API 서버와 직접 통신해서 확인하는 바람직하지 않은 방법말고 쿠버네티스-독립적(Kuberenetes-Agnostic)이도록 애플리케이션을 유지하면서 기능을 노출하는 것
DNS 레코드의 한 유형인 
SRV 레코드를 사용하면 가능

 

SRV 레코드

특정 서비스를 제공하는 서버의 호스트 이름과 포트를 가리키는 데에 사용됨
DNS lookup 도구인 dig를 실행해 SRV 레코드를 조회할 수 있음

쿠버네티스는 헤드리스 서비스를 뒷받침하는 파드의 호스트 이름을 가리키도록 SRV 레코드를 생성

파드가 스테이트풀셋의 다른 모든 파드의 목록을 가져오려면 SRV DNS 룩업을 수행하면 됨

 

10. 4. 1 DNS를 통한 피어 디스커버리

이제 기존에 생성한 데이터 저장소 애플리케이션이 클러스터화되지 않았으므로, 상호 간 통신이 가능하도록 변경을 우선 진행해야함
즉 클라이언트가 모든 파드의 데이터 엔트리를 확인해서 데이터를 가져오기 위해서는 많은 요청이 필요
즉, 노드가 모든 클러스터 노드의 데이터를 응답하도록 하여 개선해야함

 

아래와 같은 과정을 수행

  1. 애플리케이션이 GET 요청을 받음
  2. 요청을 받은 서버는 먼저 헤드리스 kubia 서비스의 SRV lookup, 레코드 룩업을 DNS에 수행
  3. GET 요청을 각 파드 전체에 보냄
  4. 각 노드에 저장된 데이터를 모아서 모든 노드의 리스트를 최종적으로 반환

 

10. 5 스테이트풀셋이 노드 실패를 처리하는 과정 이해하기

쿠버네티스는 기존 스테이트풀 파드가 실행 중이지 않아야만 새로운 교체용 파드를 생성
노드가 갑작스레 실패하면 쿠버네티스는 파드의 상태를 알 수 없어서 실행 중이 아닌지 스테이트풀셋이 별도로 실행할 수 있는 바가 없음
즉, 클러스터 관리자가 파드 혹은 해당 노드를 삭제하는 등의 조치를 확실하게 취해줘야함

 

노드의 네트워크 연결 해제 실습 (셧다운 시 파드 삭제 과정)

minikube에서는 실습 진행이 불가한 영역

책 속의 실습은 다음과 같은 방식으로 진행됨

  1. 노드의 네트워크 어댑터, 네트워크 인터페이스를 셧다운하기 >>
    kubelet이 더 이상 쿠버네티스 API 서버와 연결할 수 없고 노드 및 파드의 실행 여부를 확인할 수 없음
  2. 쿠버네티스 마스터에서 본 노드 상태 확인하기 >>
    컨트롤 플레인은 노드들의 상태를 NotReady로 표기
    파드의 상태는 Unknown으로 표기함
  3. Unknown 상태 파드의 삭제 과정 이해하기 >>
    노드가 다시 온라인 상태로 회복되면 컨트롤플레인(마스터)이 Unknown 상태가 지속된 파드를 자동으로 노드에서 삭제
    Kubectl이 파드가 deletion 표기를 확인하고 파드 종료를 시작
    파드 종류 사유는 NodeLost로 표기됨
    노드가 응답이 없어 노드가 손실된 것으로 간주

** 실제로는 파드의 컨테이너는 종료되지 않았음. 컨트롤 플레인의 관점에서의 처리 과정