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

아키텍처(Architecture)

원문 보기 위키 갱신

Kubernetes에서 PostgreSQL을 배포할 때 견고한 비즈니스 연속성 전략을 구현하기 위한 핵심 아키텍처 고려 사항을 살펴볼게요. 스트레치/비스트레치 클러스터, 노드 예약, 단일/복수 클러스터 설계까지 정리해 드릴게요.

출처: 문서

본문

:::tip[Hint] 더 깊은 이해를 위해 CNCF 블로그의 “Recommended Architectures for PostgreSQL in Kubernetes” 글을 읽어볼 것을 권장해요. Kubernetes에서 PostgreSQL 배포에 대한 모범 사례와 설계 고려 사항에 대한 귀중한 통찰력을 제공해요. :::

이 문서 페이지는 Kubernetes에서 PostgreSQL을 배포할 때 견고한 비즈니스 연속성 전략을 구현하기 위한 핵심 아키텍처 고려 사항의 개요를 제공해요. 이러한 고려 사항에는 다음이 포함돼요:

상태 동기화

PostgreSQL은 데이터베이스 관리 시스템이므로 Kubernetes에서 **상태 유지 워크로드(stateful workload)**로 다뤄야 해요. 무상태(stateless) 애플리케이션은 주로 트래픽 리디렉션으로 HA(고가용성)와 DR(재해 복구)을 달성하지만, 데이터베이스의 경우 상태를 여러 위치에 복제해야 하며, 가급적 다음 두 전략 중 하나를 채택해 연속적이고 즉각적으로 복제해야 해요:

  • 스토리지 레벨 복제, 일반적으로 퍼시스턴트 볼륨
  • 애플리케이션 레벨 복제, 이 특정 경우에는 PostgreSQL

CloudNativePG는 간단한 이유로 애플리케이션 레벨 복제에 의존해요. PostgreSQL 데이터베이스 관리 시스템은 Write Ahead Log(WAL) 시핑을 기반으로 한 견고하고 신뢰할 수 있는 내장 물리적 복제 기능을 갖추고 있으며, 이는 전 세계 수백만 사용자가 10년 넘게 프로덕션에서 사용해 왔어요.

PostgreSQL은 네트워크를 통한 비동기 및 동기 스트리밍 복제와 비동기 파일 기반 로그 시핑(일반적으로 폴백 옵션으로, 예를 들어 WAL 파일을 오브젝트 스토어에 저장하는 데 사용)을 모두 지원해요. 복제본은 보통 스탠바이 서버라고 불리며, Hot Standby 기능 덕분에 읽기 전용 워크로드에도 사용할 수 있어요.

:::info[Important] PostgreSQL에서 스토리지 레벨 복제는 권장하지 않아요. CloudNativePG가 그 전략을 채택할 수 있게 해주더라도 말이에요. 자세한 내용은 Chris Milsted와 Gabriele Bartolini가 KubeCon NA 2022에서 한 "Data On Kubernetes, Deploying And Running PostgreSQL And Patterns For Databases In a Kubernetes Cluster"라는 강연을 참고해 주세요. :::

Kubernetes 아키텍처

Kubernetes는 데이터 센터, 장애 영역, 또는 더 자주 **가용 영역(availability zones)**이라 불리는 분리된 물리적 위치를 중복되고 저지연인 프라이빗 네트워크 연결로 연결하는 것을 네이티브로 지원해요.

분산 시스템이므로 Kubernetes 클러스터의 권장 최소 가용 영역 수는 3개예요. 단일 영역의 장애에도 컨트롤 플레인이 복원력을 갖도록 하기 위해서예요. 자세한 내용은 "Running in multiple zones"를 참고하세요. 이는 각 데이터 센터가 항상 활성 상태이고 동시에 워크로드를 실행할 수 있다는 뜻이에요.

:::note 대부분의 퍼블릭 클라우드 제공자의 관리형 Kubernetes 서비스는 이미 각 리전에 3개 이상의 가용 영역을 제공해요. :::

멀티 가용 영역 Kubernetes 클러스터

세 개(3) 이상의 영역이 있는 멀티 가용 영역 Kubernetes 아키텍처는 PostgreSQL 사용에 권장하는 방식이에요. 이 시나리오는 클라우드 제공자가 관리하는 Kubernetes 서비스의 전형이에요.

Kubernetes cluster spanning over 3 independent data centers

이러한 아키텍처는 CloudNativePG 오퍼레이터가 모든 가용 영역을 활성으로 취급하여 단일 Kubernetes 클러스터 내 영역 전체에서 Cluster 리소스의 전체 수명 주기를 제어할 수 있게 해줘요. 여기에는 무엇보다도 스케줄링(친화성 규칙, 톨러레이션, 노드 셀렉터 기반 선언적 방식), 자동 페일오버, 자체 치유, 업데이트가 포함돼요. 이 모든 것이 단일 Kubernetes 클러스터의 영역 전체에서 원활하게 동작해요.

단일 Kubernetes 클러스터 내에서 스토리지, 워커 노드, 가용 영역 레벨의 shared-nothing 배포를 통해 PostgreSQL 클러스터를 설계하는 방법에 대한 자세한 내용은 아래의 "PostgreSQL 아키텍처" 섹션을 참고하세요.

또한 Kubernetes 클러스터를 활용해 다른 리전에 "수동(passive)" PostgreSQL 복제 클러스터를 호스팅하는 분산 PostgreSQL 토폴로지를 배포하고 선언적 구성으로 관리할 수 있어요. 이 설정은 재해 복구(DR), 읽기 전용 작업, 또는 교차 리전 가용성에 이상적이에요.

:::info[Important] 각 오퍼레이터 배포는 로컬 Kubernetes 클러스터 내의 작업만 관리할 수 있어요. 제어된 스위치오버나 예기치 않은 페일오버 같은 Kubernetes 클러스터 간 작업은 (예: GitOps를 통한) 수동 조정 또는 상위 레벨 클러스터 관리 도구를 사용해 처리해야 해요. :::

Example of a multiple Kubernetes cluster architecture distributed over 3 regions each with 3 independent data centers

단일 가용 영역 Kubernetes 클러스터

Kubernetes 클러스터에 가용 영역이 하나뿐이라면 CloudNativePG가 여전히 PostgreSQL 데이터베이스의 HA와 DR 결과를 개선하는 많은 기능을 제공해요. 단일 장애 지점(SPoF)을 최대한 영역 레벨로 끌어올려요 — 즉, CloudNativePG 클러스터가 장애를 겪기 전에 먼저 영역 자체에 중단(outage)이 있어야 해요.

이 시나리오는 데이터 센터가 하나뿐인 자체 관리 온프레미스 Kubernetes 클러스터의 전형이에요.

단일 가용 영역 Kubernetes 클러스터는 저지연 연결(일반적으로 같은 도심권)로 도달할 수 있는 두 개의 데이터 센터만 있는 경우 유일한 실행 가능한 옵션이에요. 두 개의 영역만 있으면 최소 3개가 필요한 멀티 가용 영역 Kubernetes 클러스터를 만들 수 없어요. 결과적으로 사용자는 active/passive 구성으로 두 개의 별도 Kubernetes 클러스터를 만들어야 하며, 두 번째 클러스터는 주로 재해 복구에 사용돼요. (복제 클러스터 기능 참고)

Example of a Kubernetes architecture with only 2 data centers

:::tip[Hint] Kubernetes 여정의 초기 단계에 있다면 이 문서를 인프라 팀과 공유해 주세요. 두 데이터 센터 설정은 기존 베어메탈이나 VM 기반 인프라에서 Kubernetes로의 단순한 "lift-and-shift" 전환 결과일 수 있어요. 3+ 영역 시나리오에서 Kubernetes가 제공하는 이점이 인프라 아키텍처 설계 시점에 알려지지 않았거나 다뤄지지 않았을 수 있어요. 궁극적으로 나머지 두 곳에 연결된 세 번째 물리적 위치는 조직에게 유효한 선택지가 될 수 있어요. 일상적인 복잡성을 애플리케이션 레벨에서 물리적 인프라 레벨로 옮겨 인프라의 전체 비용을 줄여 주기 때문이에요. :::

단일 가용 영역 Kubernetes 클러스터 내에서 스토리지와 워커 노드 레벨에서만 shared-nothing 배포를 통해 PostgreSQL 클러스터를 설계하는 방법에 대한 자세한 내용은 아래의 "PostgreSQL 아키텍처" 섹션을 참고하세요. HA를 위해 이러한 시나리오에서는 PostgreSQL 인스턴스가 다른 워커 노드에 있고 같은 스토리지를 공유하지 않는 것이 훨씬 더 중요해져요.

DR을 위해 추가 Kubernetes 클러스터를 사용해 "수동" PostgreSQL 복제 클러스터를 호스팅하는 분산 토폴로지를 정의하여 SPoF를 단일 영역 위로 끌어올릴 수 있어요. 이 시나리오의 다른 Kubernetes 워크로드와 마찬가지로 Kubernetes 클러스터를 프라이머리로 승격하는 것은 수동으로 해야 해요.

복제 클러스터 기능을 통해 분산 PostgreSQL 토폴로지를 정의하고, 먼저 프라이머리 클러스터를 강등(demote)한 다음 복제 클러스터를 승격(promote)하여 데이터 센터 간 제어된 스위치오버를 조정할 수 있어요. 이전 프라이머리를 다시 클로닝할 필요가 없어요. 페일오버는 이제 완전히 선언적이지만, Kubernetes 클러스터 간 자동 페일오버는 CloudNativePG의 범위에 없어요. 오퍼레이터는 단일 Kubernetes 클러스터 내에서만 동작할 수 있기 때문이에요.

:::info[Important] CloudNativePG는 상위 레벨 오퍼레이터나 관리 도구를 통해 다른 Kubernetes 클러스터 간 PostgreSQL active/passive 토폴로지를 조정하는 데 필요한 모든 기본 요소와 프로브를 제공해요. :::

PostgreSQL 워크로드를 위한 노드 예약

멀티 가용 영역 환경이든, 더 중요하게는 단일 가용 영역 내에서든, 프로덕션에서는 특정 워커 노드를 postgres에만 전용으로 할당해 PostgreSQL 워크로드를 격리할 것을 강력히 권장해요. PostgreSQL 워크로드를 실행하는 데 전용인 Kubernetes 워커 노드를 Postgres 노드 또는 postgres 노드라고 해요. 이 접근 방식은 데이터베이스 운영에 최적의 성능과 리소스 할당을 보장해요.

:::tip[Hint] 일반적인 경험칙으로 Postgres 노드를 3의 배수로 배포하세요. 이상적으로 가용 영역당 하나의 노드예요. 세 개의 노드가 최적의 수인 이유는 세 인스턴스(하나의 프라이머리와 두 개의 스탠바이 복제본)로 구성된 PostgreSQL 클러스터가 서로 다른 노드에 분산되어 장애 허용성과 가용성을 높이기 때문이에요. :::

Kubernetes에서는 노드 레이블과 테인트(taint)를 선언적으로 사용해 이를 달성할 수 있으며, 이는 IaC(Infrastructure as Code) 관행과 일치해요. 레이블은 노드가 postgres 워크로드를 실행할 수 있음을 보장하고, 테인트는 postgres가 아닌 워크로드가 해당 노드에 스케줄링되는 것을 방지하는 데 도움이 돼요.

:::info[Important] 이 방법은 PostgreSQL 워크로드를 컴퓨팅 리소스와 로컬 연결 디스크 사용 시 스토리지 측면에서 모두 다른 워크로드와 격리하는 가장 간단한 방법이에요. 서로 다른 PostgreSQL 클러스터가 같은 노드를 공유할 수 있지만, 레이블과 테인트를 사용해 노드를 특정 Cluster의 단일 인스턴스에 전용으로 만들 수도 있어요. :::

제안된 노드 레이블

CloudNativePG는 node-role.kubernetes.io/postgres 레이블을 권장해요. 예약된 레이블(*.kubernetes.io)이므로 워커 노드가 생성된 후에만 적용할 수 있어요.

노드에 postgres 레이블을 할당하려면 다음 명령을 사용하세요:

kubectl label node <NODE-NAME> node-role.kubernetes.io/postgres=

Cluster 리소스가 postgres 노드에 스케줄링되도록 하려면 매니페스트에서 .spec.affinity.nodeSelector stanza를 올바르게 구성해야 해요. 예시는 다음과 같아요:

spec:
  # <snip>
  affinity:
    # <snip>
    nodeSelector:
      node-role.kubernetes.io/postgres: ""

제안된 노드 테인트

CloudNativePG는 node-role.kubernetes.io/postgres 테인트를 권장해요.

노드에 postgres 테인트를 할당하려면 다음 명령을 사용하세요:

kubectl taint node <NODE-NAME> node-role.kubernetes.io/postgres=:NoSchedule

Cluster 리소스가 postgres 테인트가 있는 노드에 스케줄링되도록 하려면 매니페스트에서 .spec.affinity.tolerations stanza를 올바르게 구성해야 해요. 예시는 다음과 같아요:

spec:
  # <snip>
  affinity:
    # <snip>
    tolerations:
    - key: node-role.kubernetes.io/postgres
      operator: Exists
      effect: NoSchedule

PostgreSQL 아키텍처

CloudNativePG는 같은 Kubernetes 클러스터 내에서 여러 핫 스탠바이 복제본을 관리하기 위해 비동기 및 동기 스트리밍 복제를 기반으로 한 클러스터를 지원해요. 사양은 다음과 같아요:

  • 하나의 프라이머리와 HA용 선택적 여러 핫 스탠바이 복제본

  • 애플리케이션용 사용 가능한 서비스:

    • -rw: 애플리케이션이 클러스터의 프라이머리 인스턴스에만 연결
    • -ro: 애플리케이션이 읽기 전용 워크로드를 위해 핫 스탠바이 복제본에만 연결 (선택적)
    • -r: 애플리케이션이 읽기 전용 워크로드를 위해 임의의 인스턴스에 연결 (선택적)
  • PostgreSQL 클러스터의 더 나은 복원력을 위한 shared-nothing 아키텍처 권장:

    • PostgreSQL 인스턴스는 서로 다른 Kubernetes 워커 노드에 있어야 하며 네트워크만 공유해야 해요. 결과적으로 인스턴스는 스토리지를 공유하지 않아야 하고, 가능하면 실행되는 노드에 연결된 로컬 볼륨을 사용해야 해요
    • PostgreSQL 인스턴스는 같은 Kubernetes 클러스터/리전 내에서 서로 다른 가용 영역에 있어야 해요

:::info[Important] Cluster 구성의 managed.services 섹션을 통해 위 서비스를 구성할 수 있어요. 서비스 수를 줄이고 유형(기본값은 ClusterIP)을 선택하면 돼요. 자세한 내용은 아래의 "Service Management" 섹션을 참고해 주세요. :::

아래 다이어그램은 3개의 서로 다른 가용 영역에 걸쳐 있고, 각각 PostgreSQL 데이터용 전용 로컬 스토리지가 있는 별도 노드에서 실행되는 PostgreSQL 클러스터의 권장 shared-nothing 아키텍처의 단순화된 뷰를 제공해요.

Bird-eye view of the recommended shared nothing architecture for PostgreSQL in Kubernetes

CloudNativePG는 클러스터 토폴로지가 변경되면 위 서비스가 자동으로 업데이트되도록 처리해요. 예를 들어 페일오버 시 -rw 서비스를 승격된 프라이머리를 가리키도록 자동으로 업데이트해 애플리케이션 트래픽이 원활하게 리디렉션되도록 해요.

:::note[Replication] CloudNativePG가 PostgreSQL 복제(동기 설정 포함)에 어떻게 의존하는지에 대한 자세한 내용은 "Replication" 섹션을 참고해 주세요. :::

:::note[Connecting from an application] 같은 Kubernetes 클러스터 내의 무상태 애플리케이션에서 CloudNativePG에 연결하는 방법에 대한 정보는 "Connecting from an application" 섹션을 참고해 주세요. :::

:::note[Connection Pooling] PgBouncer를 커넥션 풀러로 활용하고 애플리케이션과 PostgreSQL 클러스터 사이에 접근 계층을 만드는 방법에 대한 정보는 "Connection Pooling" 섹션을 참고해 주세요. :::

읽기-쓰기 워크로드

애플리케이션은 아래 다이어그램과 같이 Kubernetes 오퍼레이터가 현재 프라이머리로 선출한 PostgreSQL 인스턴스에 연결하도록 결정할 수 있어요:

Applications writing to the single primary

애플리케이션은 -rw 접미사 서비스를 사용할 수 있어요.

프라이머리의 일시적 또는 영구적 사용 불가 상황에서 고가용성을 위해 CloudNativePG는 페일오버를 트리거해 -rw 서비스를 클러스터의 다른 인스턴스로 가리켜요.

읽기 전용 워크로드

:::info[Important] 애플리케이션은 Hot Standby가 제시하는 한계를 인지하고, PostgreSQL이 이러한 워크로드를 다룰 때 어떻게 동작하는지 익숙해야 해요. :::

애플리케이션은 오퍼레이터가 제공하는 -ro 서비스를 통해 핫 스탠바이 복제본에 접근할 수 있어요. 이 서비스는 애플리케이션이 읽기 전용 쿼리를 프라이머리 노드에서 오프로드할 수 있게 해줘요.

다음 다이어그램은 아키텍처를 보여줘요:

Applications reading from hot standby replicas in round robin

애플리케이션은 -r 서비스를 통해 임의의 PostgreSQL 인스턴스에도 접근할 수 있어요.

Kubernetes 클러스터 간 배포

:::info CloudNativePG는 이 섹션에서 설명하는 복제 클러스터를 사용해 분산 PostgreSQL 토폴로지를 정의할 수 있는 기능을 통해 여러 Kubernetes 클러스터에 PostgreSQL을 배포하는 것을 지원해요. :::

분산 PostgreSQL 클러스터에서는 항상 단일 PostgreSQL 인스턴스만 프라이머리로 동작할 수 있어요. 즉, 애플리케이션은 언제든지 단일 Kubernetes 클러스터 안에서만 쓸 수 있어요.

하지만 비즈니스 연속성 목표를 위해 다음이 근본적으로 중요해요:

  • PostgreSQL 백업 데이터를 여러 위치, 리전에 저장하고 가능하면 다른 프로바이더를 사용해 전체 **복구 시점 목표(RPO)**를 줄인다 (재해 복구)
  • 프라이머리 Kubernetes 클러스터 너머로 PostgreSQL 복제를 활용해 전체 **복구 시간 목표(RTO)**를 줄인다 (고가용성)

위 우려를 해결하기 위해 CloudNativePG는 서로 다른 Kubernetes 클러스터에 분산되고, 프라이머리 PostgreSQL 클러스터와 하나 이상의 PostgreSQL 복제 클러스터로 구성된 PostgreSQL 토폴로지 개념을 도입해요. 이 기능을 복제 클러스터를 사용한 분산 PostgreSQL 토폴로지라고 하며, 프라이빗, 퍼블릭, 하이브리드, 멀티 클라우드 환경에서 멀티 클러스터 배포를 가능하게 해요.

복제 클러스터는 WAL 아카이브에서의 WAL 시핑 또는 프라이머리나 스탠바이로부터의 스트리밍 복제(캐스케이딩)를 통해 다른 소스에서 연속 복구하며 복제하는 별도의 Cluster 리소스예요.

아래 다이어그램은 두 개의 다른 Kubernetes 클러스터에 걸친 PostgreSQL 클러스터를 묘사해요. 프라이머리 클러스터는 첫 번째 Kubernetes 클러스터에, 복제 클러스터는 두 번째에 있어요. 두 번째 Kubernetes 클러스터는 회사의 재해 복구 클러스터 역할을 하며, 첫 번째 클러스터의 재해와 사용 불가 시 활성화될 준비가 돼 있어요.

An example of multi-cluster deployment with a primary and a replica cluster

복제 클러스터는 프라이머리 클러스터와 같은 아키텍처를 가질 수 있어요. 복제 클러스터에는 프라이머리 인스턴스 대신 지정 프라이머리(designated primary) 인스턴스가 있으며, 이는 스트리밍 복제에서 임의 개수의 캐스케이딩 스탠바이 서버를 가진 스탠바이 서버예요(대칭 아키텍처).

:::important 지정 프라이머리의 소스로 WAL 아카이브를 구성한다면, "Configuring Replication"에 설명된 수정 사항이 포함된 PostgreSQL 버전을 실행 중인지 확인하세요. :::

지정 프라이머리는 언제든 승격될 수 있으며, 쓰기 연결을 받아들일 수 있는 프라이머리 클러스터로 복제 클러스터를 변환해요. 이는 일반적으로 다음에 의해 트리거돼요:

  • 인간의 결정: 다른 PostgreSQL 클러스터(또는 전체 Kubernetes 클러스터)를 프라이머리로 만들기로 선택했어요. 데이터 손실을 피하고 이전 프라이머리가 (특히 대용량 데이터 세트에서) 재클로닝 없이 따라갈 수 있도록, 먼저 현재 프라이머리를 강등한 다음 CloudNativePG가 제공하는 API로 지정 프라이머리를 승격해요.
  • 예기치 않은 장애: 전체 Kubernetes 클러스터가 실패하면 데이터 손실을 겪을 수 있지만, PostgreSQL 복제 클러스터를 승격해 다른 Kubernetes 클러스터로 페일오버해야 해요.

:::warning CloudNativePG는 단일 Kubernetes 클러스터 너머로 권한을 갖지 않으므로 클러스터 간 자동 페일오버를 수행할 수 없어요. 이러한 작업은 수동으로 수행하거나 멀티 클러스터/페더레이션 클러스터 인지 권한에 위임해야 해요. :::

:::info[Important] CloudNativePG는 선언적 구성을 통해 분산 토폴로지를 제어할 수 있게 해주므로, GitOps를 포함한 IaC(Infrastructure as Code) 프로세스의 일부로 이러한 절차를 자동화할 수 있어요. :::

위 예시에서 지정 프라이머리는 스트리밍 복제(primary_conninfo)를 통해 WAL 업데이트를 받아요. 폴백으로 restore_command와 barman-cloud-wal-restore를 사용하는 Barman Cloud 플러그인처럼 파일 기반 WAL 시핑을 사용해 오브젝트 스토어에서 WAL 세그먼트를 검색할 수 있어요.

CloudNativePG는 여러 복제 클러스터가 있는 토폴로지를 정의할 수 있게 해줘요. 더 적은 수의 복제본으로 복제 클러스터를 정의한 다음, 클러스터가 프라이머리로 승격될 때 그 수를 늘릴 수도 있어요.

:::note[Replica clusters] 물리적 복제 클러스터가 어떻게 동작하고 서로 다른 Kubernetes 클러스터에 걸쳐 읽기 전용 클러스터로 분산 토폴로지를 정의하는 방법에 대한 더 자세한 정보는 "Replica Clusters" 섹션을 참고해 주세요. 이 접근 방식은 전체 재해 복구와 고가용성(HA) 전략을 크게 향상시킬 수 있어요. :::

더 알아보기 (Learn more)