이 가이드에서는 CloudNativePG 연산자를 사용하여 Google Kubernetes Engine(GKE)에 PostgreSQL 클러스터를 배포하는 방법을 보여줍니다.
PostgreSQL은 수십 년간의 활발한 개발이 이루어진 오픈소스 객체 관계형 데이터베이스로, 안정적인 클라이언트 성능을 보장합니다. 복제, PITR(point-in-time recovery), 보안 기능, 확장성을 등 다양한 기능을 제공합니다. PostgreSQL은 주요 운영체제와 호환되며 ACID(원자성, 일관성, 격리, 내구성) 표준을 완벽하게 준수합니다.
이 가이드는 Postgres 클러스터를 GKE에 배포하는 데 관심이 있는 플랫폼 관리자, 클라우드 설계자, 운영 전문가를 대상으로 합니다. Cloud SQL을 사용하는 대신 GKE에서 Postgres를 실행하면 숙련된 데이터베이스 관리자에게 더 많은 유연성과 구성 제어를 제공할 수 있습니다.
이점
CloudNativePG는 Apache 2 라이선스가 적용되는 EDB에서 개발된 오픈소스 연산자로, PostgreSQL 배포에 다음 기능을 제공합니다.
- PostgreSQL 클러스터를 관리하고 구성하는 선언적 Kubernetes 기반 방식
- 볼륨 스냅샷 또는 Cloud Storage를 사용한 백업 관리
- 전송 중 암호화된 TLS 연결, 사용자의 인증 기관 사용, 인증 관리자와의 통합을 통한 자동 TLS 인증서 발급 및 순환
- 부 PostgreSQL 출시 버전의 순차적 업데이트
- 고가용성을 위해 추가 도구 없이 Kubernetes API 서버를 사용하여 PostgreSQL 클러스터 상태 및 장애 조치 유지
- SQL로 작성된 사용자 정의 측정항목을 통해 기본 제공되는 Prometheus 내보내기 구성
환경 설정
환경을 설정하려면 다음 단계를 수행합니다.
- 환경 변수를 설정합니다. - export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1- PROJECT_ID를 Google Cloud 프로젝트 ID로 바꿉니다.
- GitHub 저장소를 클론합니다. - git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
- 작업 디렉터리로 변경합니다. - cd kubernetes-engine-samples/databases/postgresql-cloudnativepg
클러스터 인프라 만들기
이 섹션에서는 Terraform 스크립트를 실행하여 가용성이 높은 비공개 리전 GKE 클러스터를 만듭니다.
Standard 또는 Autopilot 클러스터를 사용하여 연산자를 설치할 수 있습니다.
표준
다음 다이어그램에서는 서로 다른 영역 3개에 배포된 비공개 리전 Standard GKE 클러스터를 보여줍니다.
이 인프라를 배포하려면 다음 명령어를 실행합니다.
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply \
-var project_id=${PROJECT_ID}   \
-var region=${REGION}  \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
메시지가 표시되면 yes를 입력합니다. 이 명령어가 완료되고 클러스터에 준비 상태가 표시되는 데 몇 분 정도 걸릴 수 있습니다.
Terraform에서 다음 리소스를 만듭니다.
- Kubernetes 노드의 VPC 네트워크 및 비공개 서브넷
- NAT를 통해 인터넷에 액세스할 수 있는 라우터
- us-central1리전의 비공개 GKE 클러스터
- 자동 확장이 사용 설정된 노드 풀(영역당 노드 1~2개, 최소 영역당 노드 1개)
출력은 다음과 비슷합니다.
...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...
Autopilot
다음 다이어그램에서는 비공개 리전 Autopilot GKE 클러스터를 보여줍니다.
인프라를 배포하려면 다음 명령어를 실행합니다.
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply \
-var project_id=${PROJECT_ID} \
-var region=${REGION} \
-var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
메시지가 표시되면 yes를 입력합니다. 이 명령어가 완료되고 클러스터에 준비 상태가 표시되는 데 몇 분 정도 걸릴 수 있습니다.
Terraform에서 다음 리소스를 만듭니다.
- Kubernetes 노드의 VPC 네트워크 및 비공개 서브넷
- NAT를 통해 인터넷에 액세스할 수 있는 라우터
- us-central1리전의 비공개 GKE 클러스터
- 로깅 및 모니터링 권한이 있는 ServiceAccount
- 클러스터 모니터링을 위한 Google Cloud Managed Service for Prometheus
출력은 다음과 비슷합니다.
...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...
클러스터에 연결
클러스터와 통신하도록 kubectl을 구성합니다.
gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${REGION}
CloudNativePG 연산자 배포
Helm 차트를 사용하여 Kubernetes 클러스터에 CloudNativePG를 배포합니다.
- CloudNativePG 연산자 Helm 차트 저장소를 추가합니다. - helm repo add cnpg https://cloudnative-pg.github.io/charts
- Helm 명령줄 도구를 사용하여 CloudNativePG 연산자를 배포합니다. - helm upgrade --install cnpg \ --namespace cnpg-system \ --create-namespace \ cnpg/cloudnative-pg- 출력은 다음과 비슷합니다. - Release "cnpg" does not exist. Installing it now. NAME: cnpg LAST DEPLOYED: Fri Oct 13 13:52:36 2023 NAMESPACE: cnpg-system STATUS: deployed REVISION: 1 TEST SUITE: None ...
Postgres 배포
다음 매니페스트에서는 CloudNativePG 연산자의 커스텀 리소스에서 정의한 PostgreSQL 클러스터를 설명합니다.
이 매니페스트에는 다음과 같은 필드가 있습니다.
- spec.instances: 클러스터 포드 수
- spec.primaryUpdateStrategy: 순차적 업데이트 전략:- Unsupervised: 복제본 노드 후 기본 클러스터 노드를 자율적으로 업데이트합니다.
- Supervised: 기본 클러스터 노드에 수동 전환이 필요합니다.
 
- spec.postgresql: pg-hba 규칙, LDAP, 동기화 복제본이 충족해야 할 요구사항과 같은- postgres.conf파일 매개변수를 재정의합니다.
- spec.storage: 스토리지 클래스, 볼륨 크기, 미리 쓰기 로그 설정과 같은 스토리지 관련 설정입니다.
- spec.bootstrap: 클러스터에 생성된 초기 데이터베이스 파라미터, 사용자 인증 정보, 데이터베이스 복원 옵션
- spec.resources: 클러스터 포드의 요청 및 한도
- spec.affinity: 클러스터 워크로드의 어피니티 및 안티-어피니티 규칙입니다.
기본 Postgres 클러스터 만들기
- 네임스페이스를 만듭니다. - kubectl create ns pg-ns
- 커스텀 리소스를 사용하여 PostgreSQL 클러스터를 만듭니다. - kubectl apply -n pg-ns -f manifests/01-basic-cluster/postgreSQL_cluster.yaml- 이 작업을 완료하는 데 몇 분이 소요될 수 있습니다. 
- 클러스터의 상태를 확인합니다. - kubectl get cluster -n pg-ns --watch- 다음 단계로 이동하기 전에 출력에 - Cluster in healthy state상태가 표시될 때까지 기다립니다.- NAME AGE INSTANCES READY STATUS PRIMARY gke-pg-cluster 2m53s 3 3 Cluster in healthy state gke-pg-cluster-1
리소스 검사
GKE에서 클러스터의 리소스를 만들었는지 확인합니다.
kubectl get cluster,pod,svc,pvc,pdb,secret,cm -n pg-ns
출력은 다음과 비슷합니다.
NAME                                        AGE   INSTANCES   READY   STATUS                     PRIMARY
cluster.postgresql.cnpg.io/gke-pg-cluster   32m   3           3       Cluster in healthy state   gke-pg-cluster-1
NAME                   READY   STATUS    RESTARTS   AGE
pod/gke-pg-cluster-1   1/1     Running   0          31m
pod/gke-pg-cluster-2   1/1     Running   0          30m
pod/gke-pg-cluster-3   1/1     Running   0          29m
NAME                        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/gke-pg-cluster-r    ClusterIP   10.52.11.24   <none>        5432/TCP   32m
service/gke-pg-cluster-ro   ClusterIP   10.52.9.233   <none>        5432/TCP   32m
service/gke-pg-cluster-rw   ClusterIP   10.52.1.135   <none>        5432/TCP   32m
NAME                                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/gke-pg-cluster-1   Bound    pvc-bbdd1cdd-bdd9-4e7c-8f8c-1a14a87e5329   2Gi        RWO            standard       32m
persistentvolumeclaim/gke-pg-cluster-2   Bound    pvc-e7a8b4df-6a3e-43ce-beb0-b54ec1d24011   2Gi        RWO            standard       31m
persistentvolumeclaim/gke-pg-cluster-3   Bound    pvc-dac7f931-6ac5-425f-ac61-0cfc55aae72f   2Gi        RWO            standard       30m
NAME                                                MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
poddisruptionbudget.policy/gke-pg-cluster           1               N/A               1                     32m
poddisruptionbudget.policy/gke-pg-cluster-primary   1               N/A               0                     32m
NAME                                TYPE                       DATA   AGE
secret/gke-pg-cluster-app           kubernetes.io/basic-auth   3      32m
secret/gke-pg-cluster-ca            Opaque                     2      32m
secret/gke-pg-cluster-replication   kubernetes.io/tls          2      32m
secret/gke-pg-cluster-server        kubernetes.io/tls          2      32m
secret/gke-pg-cluster-superuser     kubernetes.io/basic-auth   3      32m
NAME                                DATA   AGE
configmap/cnpg-default-monitoring   1      32m
configmap/kube-root-ca.crt          1      135m
연산자는 다음 리소스를 만듭니다.
- 연산자가 제어하는 PostgreSQL 클러스터를 나타내는 클러스터 커스텀 리소스
- 해당 영구 볼륨이 있는 PersistentVolumeClaim 리소스
- Postgres 노드 간 복제와 데이터베이스에 액세스하기 위한 사용자 인증 정보가 포함된 보안 비밀
- 클러스터에 연결할 3가지 데이터베이스 엔드포인트 서비스: <name>-rw,<name>-ro,<name>-r. 자세한 내용은 PostgreSQL 아키텍처를 참조하세요.
Postgres 인증
PostgreSQL 데이터베이스에 연결하고 연산자에서 만든 다른 서비스 엔드포인트를 통해 액세스를 확인할 수 있습니다. 이렇게 하려면 PostgreSQL 클라이언트와 동기화된 애플리케이션 사용자 인증 정보가 환경 변수로 마운트된 추가 포드를 사용합니다.
- 클라이언트 포드를 실행하여 Postgres 클러스터와 상호 작용합니다. - kubectl apply -n pg-ns -f manifests/02-auth/pg-client.yaml
- pg-client포드에서- exec명령어를 실행하고- gke-pg-cluster-rw서비스에 로그인합니다.- kubectl wait --for=condition=Ready -n pg-ns pod/pg-client --timeout=300s kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
- 읽기-쓰기 권한으로 연결을 설정하려면 - gke-pg-cluster-rw서비스를 사용하여 데이터베이스에 로그인합니다.- psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app- 이 터미널은 데이터베이스 이름으로 시작합니다. - app=>
- 테이블을 만듭니다. - CREATE TABLE travel_agency_clients ( client VARCHAR ( 50 ) UNIQUE NOT NULL, address VARCHAR ( 50 ) UNIQUE NOT NULL, phone VARCHAR ( 50 ) UNIQUE NOT NULL);
- 데이터를 테이블에 삽입합니다. - INSERT INTO travel_agency_clients(client, address, phone) VALUES ('Tom', 'Warsaw', '+55555') RETURNING *;
- 생성된 데이터를 봅니다. - SELECT * FROM travel_agency_clients ;- 출력은 다음과 비슷합니다. - client | address | phone --------+---------+--------- Tom | Warsaw | +55555 (1 row)
- 현재 데이터베이스 세션에서 로그아웃합니다. - exit
- gke-pg-cluster-ro서비스를 사용하여 데이터베이스에 로그인하여 읽기 전용 액세스를 확인합니다. 이 서비스는 데이터 쿼리를 허용하지만 쓰기 작업을 제한합니다.- psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-ro.pg-ns/app
- 새 데이터를 삽입하려고 시도합니다. - INSERT INTO travel_agency_clients(client, address, phone) VALUES ('John', 'Paris', '+55555') RETURNING *;- 출력은 다음과 비슷합니다. - ERROR: cannot execute INSERT in a read-only transaction
- 데이터를 읽으려고 시도합니다. - SELECT * FROM travel_agency_clients ;- 출력은 다음과 비슷합니다. - client | address | phone --------+---------+--------- Tom | Warsaw | +55555 (1 row)
- 현재 데이터베이스 세션에서 로그아웃합니다. - exit
- 포드 셸을 종료합니다. - exit
Prometheus가 Postgres 클러스터에 대해 측정항목을 수집하는 방법 이해
다음 다이어그램은 Prometheus 측정항목 수집의 작동 방식을 보여줍니다.
다이어그램에서 GKE 비공개 클러스터에는 다음이 포함됩니다.
- /경로 및- 9187포트로 측정항목을 수집하는 Postgres 포드
- Postgres 포드의 측정항목을 처리하는 Prometheus 기반 수집기
- Cloud Monitoring으로 측정항목을 전송하는 PodMonitoring리소스
포드에서 측정항목을 수집할 수 있게 하려면 다음 단계를 수행합니다.
- PodMonitoring리소스를 만듭니다.- kubectl apply -f manifests/03-observability/pod-monitoring.yaml -n pg-ns
- Google Cloud 콘솔에서 측정항목 탐색기 페이지로 이동합니다. - 대시보드에 0이 아닌 측정항목 수집 비율이 표시됩니다. 
- 측정항목 선택에서 Prometheus 대상을 입력합니다. 
- 활성 측정항목 카테고리 섹션에서 Cnpg를 선택합니다. 
측정항목 대시보드 만들기
내보낸 측정항목을 시각화하려면 측정항목 대시보드를 만듭니다.
- 대시보드를 배포합니다. - gcloud --project "${PROJECT_ID}" monitoring dashboards create --config-from-file manifests/03-observability/gcp-pg.json
- Google Cloud 콘솔에서 대시보드 페이지로 이동합니다. 
- PostgresQL Prometheus 개요 대시보드를 선택합니다. - 대시보드가 함수를 모니터링하는 방법을 검토하려면 데이터베이스 인증 섹션의 작업을 재사용하고, 데이터베이스에 읽기 및 쓰기 요청을 적용한 다음 대시보드에서 수집된 측정항목 시각화를 검토합니다. 
- 클라이언트 포드에 연결합니다. - kubectl exec -n pg-ns -i -t pg-client -- /bin/sh
- 임의 데이터를 삽입합니다. - psql postgresql://$CLIENTUSERNAME:$CLIENTPASSWORD@gke-pg-cluster-rw.pg-ns/app -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);INSERT INTO test (randomdata) VALUES (generate_series(1, 1000));"
- 대시보드를 새로고침합니다. 그래프가 실현된 측정항목으로 업데이트됩니다. 
- 포드 셸을 종료합니다. - exit