본문 바로가기
WIKI 기술 지식 베이스

커스텀 Pod 컨트롤러

원문 보기 위키 갱신

커스텀 Pod 컨트롤러 (Custom Pod Controller)

Kubernetes는 컨트롤러 패턴을 사용해서 현재 클러스터의 상태를 원하는 상태(desired state)에 맞춰 정렬해요.

상태를 가진(stateful) 애플리케이션은 보통 StatefulSet 컨트롤러로 관리해요. 이 컨트롤러는 동일한 스펙으로 만들어진 Pod 묶음을 생성·리컨실(reconcile)하고, 각 Pod에 고정된(sticky) 신원을 부여하죠.

CloudNativePG는 StatefulSet 컨트롤러에 의존하지 않고, PostgreSQL 인스턴스를 관리하기 위한 자체 커스텀 컨트롤러를 구현해요. 이 설계 선택은 구현을 더 복잡하게 만들기도 하지만, 그 대가로 연산자가 클러스터를 관리하는 방식에 훨씬 더 많은 유연성을 제공하고, PostgreSQL 클러스터의 토폴로지에 대해서는 투명하게 동작해요.

설계 영역의 많은 선택이 그렇듯, 다른 선택은 다른 절충을 낳아요. 아래 섹션들에서는 이런 설계 선택 덕분에 CloudNativePG의 구현이 더 안정적이고 이해하기 쉬워진 몇 가지 지점을 다뤄볼게요.

출처: 문서

본문

PVC 크기 조정 (PVC resizing)

이건 StatefulSet의 잘 알려진 한계예요. StatefulSet은 PVC 크기 조정을 지원하지 않아요. 데이터베이스 입장에선 굉장히 불편하죠. 볼륨 크기를 조정하려면 복잡한 우회 방법이 필요해요.

반면 CloudNativePG는 설정된 스토리지 클래스를 활용해서 기반이 되는 PVC를 직접 관리하고, 스토리지 클래스가 지원한다면 PVC 크기 조정도 처리할 수 있어요.

프라이머리 인스턴스와 레플리카 (Primary Instances versus Replicas)

StatefulSet 컨트롤러는 단 하나의 템플릿으로부터 Pod 묶음을 만드는 설계예요. CloudNativePG는 PostgreSQL 인스턴스마다 Pod 하나를 사용하기 때문에, 두 종류의 Pod가 생기죠:

  1. 프라이머리 인스턴스 (딱 하나)
  2. 레플리카 (여러 개, 선택 사항)

이 차이는 특정 작업을 위해 올바른 배포 전략을 결정할 때 중요해요.

어떤 작업은 레플리카에 먼저 수행하고, 그다음에 프라이머리에 수행해야 해요. 단, 갱신된 레플리카가 새 프라이머리로 승격된 뒤에만 가능하죠. 예를 들어 다른 PostgreSQL 이미지 버전을 적용할 때, 또는 max_connections 같은 구성 파라미터를 늘릴 때가 그래요. (이 파라미터는 CloudNativePG가 핫 스탠바이 레플리카를 사용하기 때문에 PostgreSQL에서 특별히 취급하는 값이에요.)

이때 CloudNativePG는 PostgreSQL 인스턴스의 일련번호만이 아니라 그 역할(role) 을 고려해요.

때로는 연산자가 반대 순서를 따라야 할 때도 있어요. 즉 프라이머리를 먼저 다루고 그다음 레플리카를 다루는 방식이죠. 예를 들어 max_connections을 낮출 때가 그렇습니다. 이 경우 CloudNativePG는:

  • 프라이머리 인스턴스에 새 설정을 적용하고
  • 재시작하고
  • 레플리카에 새 설정을 적용해요

StatefulSet 컨트롤러는 애플리케이션에 무관한(application-independent) 설계라서, PostgreSQL 네이티브 복제 기술에 특화된 이런 동작은 담을 수가 없어요.

PVC의 정합성 (Coherence of PVCs)

PostgreSQL 인스턴스는 여러 PVC와 함께 동작하도록 구성할 수 있어요. 이것이 바로 WAL 스토리지를 PGDATA와 분리하는 방식이에요.

두 데이터 저장소는 동시에 사용되므로 PostgreSQL 관점에서 서로 정합적(coherent)이어야 해요. 만약 어떤 인스턴스의 WAL 스토리지에 해당하는 PVC를 삭제하면, PGDATA가 저장된 PVC도 더 이상 사용할 수 없게 돼요.

이 동작은 PostgreSQL에 특화된 것이고 StatefulSet 컨트롤러에는 구현되어 있지 않아요. 후자는 애플리케이션 특화적이지 않으니까요.

사용자가 PVC를 삭제하면 StatefulSet은 그냥 PVC를 다시 만들 뿐이라서, 손상된 PostgreSQL 인스턴스로 이어질 수 있어요.

반면 CloudNativePG는 남은 PVC를 사용 불가로 분류하고, 다른 인스턴스가 클러스터에 올바르게 합류할 수 있도록 새 PVC 쌍을 만들기 시작해요.

로컬 스토리지, 원격 스토리지, 데이터베이스 크기

때로는 업그레이드를 하기 위해 Kubernetes 노드를 내려야 할 때가 있어요. 업그레이드 후, 업그레이드 전략에 따라 갱신된 노드가 다시 올라오거나, 새 노드가 그 자리를 대체할 수도 있어요.

다운된 노드가 PostgreSQL 인스턴스를 호스팅 중이었다고 가정해 보면, 데이터베이스 크기와 클라우드 인프라에 따라 다음 중 하나를 선택하는 게 좋을 수 있어요:

  1. 다운된 노드에 있던 PVC와 Pod를 삭제하고; 다른 PVC에서 데이터를 복제(clone)해 새 PVC를 만들고; 그 후에 Pod를 스케줄링
  2. Pod를 삭제하고, 다른 노드에 스케줄링한 뒤 그곳에서 PVC를 마운트
  3. Pod와 PVC를 그대로 두고, 노드가 다시 올라올 때까지 기다리기

첫 번째 해결책은 데이터베이스 크기가 허용할 때 실용적이에요. 원하는 수의 레플리카를 즉시 되돌릴 수 있게 해주거든요.

두 번째 해결책은 로컬 노드의 스토리지를 사용하지 않을 때만 가능해요. 그리고 다른 호스트에서 PVC를 재마운트하는 게 합리적인 시간 안에 가능해야 하죠 (이건 우리 조직만이 아는 영역이에요).

세 번째 해결책은 데이터베이스가 크고, 최대 성능과 데이터 내구성을 위해 로컬 노드 스토리지를 사용할 때 적합해요.

CloudNativePG 컨트롤러는 이 모든 전략을 구현해서, 사용자가 클러스터 레벨에서 원하는 동작을 선택할 수 있게 해줘요 (자세한 내용은 “Kubernetes upgrade” 섹션을 읽어보세요).

StatefulSet은 범용적이라서 이 정도 수준의 커스터마이징은 허용하지 않아요.

더 알아보기 (Learn more)