이 가이드에서는 Zalando Postgres 연산자를 사용하여 Postgres 클러스터를 Google Kubernetes Engine(GKE)에 배포하는 방법을 설명합니다.
PostgreSQL은 수십 년간의 활발한 개발이 이루어진 강력한 오픈소스 객체 관계형 데이터베이스 시스템으로, 안정성, 기능 견고성, 성능으로 탄탄한 평판을 쌓았습니다.
이 가이드는 PostgreSQL용 Cloud SQL을 사용하는 대신 PostgreSQL을 GKE에서 데이터베이스 애플리케이션으로 실행하는 데 관심이 있는 플랫폼 관리자, 클라우드 설계자, 운영 전문가를 대상으로 합니다.
환경 설정
환경을 설정하려면 다음 단계를 수행합니다.
환경 변수를 설정합니다.
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/postgres-zalando
클러스터 인프라 만들기
이 섹션에서는 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개)
- 로깅 및 모니터링 권한이 있는
ServiceAccount
- 재해 복구를 위한 Backup for GKE
- 클러스터 모니터링을 위한 Google Cloud Managed Service for Prometheus
출력은 다음과 비슷합니다.
...
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}
클러스터에 Zalando 연산자 배포
Helm 차트를 사용하여 Kubernetes 클러스터에 Zalando 연산자를 배포합니다.
Zalando 연산자 Helm 차트 저장소를 추가합니다.
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
Zalando 연산자 및 Postgres 클러스터의 네임스페이스를 만듭니다.
kubectl create ns postgres kubectl create ns zalando
Helm 명령줄 도구를 사용하여 Zalando 연산자를 배포합니다.
helm install postgres-operator postgres-operator-charts/postgres-operator -n zalando \ --set configKubernetes.enable_pod_antiaffinity=true \ --set configKubernetes.pod_antiaffinity_preferred_during_scheduling=true \ --set configKubernetes.pod_antiaffinity_topology_key="topology.kubernetes.io/zone" \ --set configKubernetes.spilo_fsgroup="103"
Postgres 클러스터를 나타내는 커스텀 리소스에서 직접
podAntiAffinity
설정을 구성할 수 없습니다. 대신 연산자 설정에서 모든 Postgres 클러스터에 대해podAntiAffinity
설정을 전역적으로 설정합니다.Helm을 사용하여 Zalando 연산자의 배포 상태를 확인합니다.
helm ls -n zalando
출력은 다음과 비슷합니다.
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION postgres-operator zalando 1 2023-10-13 16:04:13.945614 +0200 CEST deployed postgres-operator-1.10.1 1.10.1
Postgres 배포
Postgres 클러스터 인스턴스의 기본 구성에는 다음 구성요소가 포함됩니다.
- Postgres 복제본 3개: 리더 1개와 대기 복제본 2개
- CPU 요청 1개 및 CPU 한도 2개의 CPU 리소스 할당(4GB 메모리 요청 및 한도)
- Kubernetes 노드 간 적절한 배포를 보장하고 해당 노드 풀 및 서로 다른 가용성 영역을 활용하는 각 워크로드에 구성된 톨러레이션(toleration),
nodeAffinities
,topologySpreadConstraints
이 구성은 프로덕션에 사용 가능한 Postgres 클러스터를 만드는 데 필요한 최소 설정을 나타냅니다.
다음 매니페스트에서는 Postgres 클러스터를 설명합니다.
이 매니페스트에는 다음과 같은 필드가 있습니다.
spec.teamId
: 선택한 클러스터 객체의 프리픽스spec.numberOfInstances
: 클러스터의 총 인스턴스 수spec.users
: 권한이 있는 사용자 목록spec.databases
:dbname: ownername
형식의 데이터베이스 목록spec.postgresql
: postgres 매개변수spec.volume
: 영구 디스크 매개변수spec.tolerations
: 클러스터 포드를pool-postgres
노드에 예약할 수 있는 톨러레이션(toleration) 포드 템플릿spec.nodeAffinity
: 클러스터 포드가pool-postgres
노드에 예약되는 것을 GKE에 알려주는nodeAffinity
포드 템플릿spec.resources
: 클러스터 포드의 요청 및 한도spec.sidecars
:postgres-exporter
가 포함된 사이드카 컨테이너 목록
자세한 내용은 Postgres 문서의 클러스터 매니페스트 참조를 확인하세요.
기본 Postgres 클러스터 만들기
기본 구성을 사용하여 새 Postgres 클러스터를 만듭니다.
kubectl apply -n postgres -f manifests/01-basic-cluster/my-cluster.yaml
이 명령어는 다음을 사용하여 Zalando 연산자의 PostgreSQL 커스텀 리소스를 만듭니다.
- CPU 및 메모리 요청과 한도
- 프로비저닝된 포드 복제본을 GKE 노드 간에 배포하기 위한 taint 및 어피니티
- 데이터베이스
- 데이터베이스 소유자 권한이 있는 사용자 두 명
- 권한이 없는 사용자
GKE가 필요한 워크로드를 시작할 때까지 기다립니다.
kubectl wait pods -l cluster-name=my-cluster --for condition=Ready --timeout=300s -n postgres
이 명령어를 완료하는 데 몇 분이 걸릴 수 있습니다.
GKE에서 Postgres 워크로드를 생성했는지 확인합니다.
kubectl get pod,svc,statefulset,deploy,pdb,secret -n postgres
출력은 다음과 비슷합니다.
NAME READY STATUS RESTARTS AGE pod/my-cluster-0 1/1 Running 0 6m41s pod/my-cluster-1 1/1 Running 0 5m56s pod/my-cluster-2 1/1 Running 0 5m16s pod/postgres-operator-db9667d4d-rgcs8 1/1 Running 0 12m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-cluster ClusterIP 10.52.12.109 <none> 5432/TCP 6m43s service/my-cluster-config ClusterIP None <none> <none> 5m55s service/my-cluster-repl ClusterIP 10.52.6.152 <none> 5432/TCP 6m43s service/postgres-operator ClusterIP 10.52.8.176 <none> 8080/TCP 12m NAME READY AGE statefulset.apps/my-cluster 3/3 6m43s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/postgres-operator 1/1 1 1 12m NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE poddisruptionbudget.policy/postgres-my-cluster-pdb 1 N/A 0 6m44s NAME TYPE DATA AGE secret/my-user.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m45s secret/postgres.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/sh.helm.release.v1.postgres-operator.v1 helm.sh/release.v1 1 12m secret/standby.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s secret/zalando.my-cluster.credentials.postgresql.acid.zalan.do Opaque 2 6m44s
연산자는 다음 리소스를 만듭니다.
- Postgres용 포드 복제본 세 개를 제어하는 Postgres StatefulSet
- 사용 가능한 복제본 최소 1개를 보장하는
PodDisruptionBudgets
- 리더 복제본만 대상으로 하는
my-cluster
서비스 my-cluster-repl
서비스, 수신되는 연결과 Postgres 복제본 간의 복제를 위한 Postgres 포트 노출- 실행 중인 Postgres 포드 복제본의 목록을 가져오기 위한
my-cluster-config
헤드리스 서비스 - Postgres 노드 간 복제와 데이터베이스에 액세스하기 위한 사용자 인증 정보가 포함된 보안 비밀
Postgres 인증
Postgres 사용자를 만들고 데이터베이스 권한을 할당할 수 있습니다. 예를 들어 다음 매니페스트는 사용자와 역할을 할당하는 커스텀 리소스를 설명합니다.
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
users:
mydatabaseowner:
- superuser
- createdb
myuser: []
databases:
mydatabase: mydatabaseowner
이 매니페스트에서 각 항목은 다음을 수행합니다.
mydatabaseowner
사용자에게는 전체 관리자 권한(예: Postgres 구성 관리, 새 데이터베이스, 테이블, 사용자 만들기)을 허용하는SUPERUSER
및CREATEDB
역할이 있습니다. 이 사용자를 클라이언트와 공유해서는 안 됩니다. 예를 들어 Cloud SQL에서는 고객이SUPERUSER
역할이 있는 사용자에게 액세스하는 것을 허용하지 않습니다.myuser
사용자에게 할당된 역할이 없습니다. 따라서SUPERUSER
를 사용하여 최소 권한으로 사용자를 만드는 권장사항을 따릅니다.mydatabaseowner
에서myuser
에게 세분화된 권한을 부여합니다. 보안을 유지하려면myuser
사용자 인증 정보를 클라이언트 애플리케이션에만 공유해야 합니다.
비밀번호 저장
scram-sha-256
비밀번호 저장에 권장되는 방법을 사용해야 합니다. 예를 들어 다음 매니페스트는 postgresql.parameters.password_encryption
필드를 사용하여 scram-sha-256
암호화를 지정하는 커스텀 리소스를 설명합니다.
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
postgresql:
parameters:
password_encryption: scram-sha-256
사용자 인증 정보 순환
Zalando를 사용하여 Kubernetes 보안 비밀에 저장된 사용자 인증 정보를 순환할 수 있습니다. 예를 들어 다음 매니페스트는 usersWithSecretRotation
필드를 사용하여 사용자 인증 정보 순환을 정의하는 커스텀 리소스를 설명합니다.
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: my-cluster
spec:
...
usersWithSecretRotation:
- myuser
- myanotheruser
- ...
인증 예시: Postgres에 연결
이 섹션에서는 예시 Postgres 클라이언트를 배포하고 Kubernetes 보안 비밀의 비밀번호를 사용하여 데이터베이스에 연결하는 방법을 보여줍니다.
클라이언트 포드를 실행하여 Postgres 클러스터와 상호 작용합니다.
kubectl apply -n postgres -f manifests/02-auth/client-pod.yaml
myuser
및mydatabaseowner
사용자의 사용자 인증 정보는 관련 보안 비밀에서 가져와 환경 변수로 포드에 마운트합니다.준비되면 포드에 연결합니다.
kubectl wait pod postgres-client --for=condition=Ready --timeout=300s -n postgres kubectl exec -it postgres-client -n postgres -- /bin/bash
Postgres에 연결하고
myuser
사용자 인증 정보를 사용하여 새 테이블 만들기를 시도합니다.PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);"
다음과 유사한 오류가 표시되면서 명령어가 실패합니다.
ERROR: permission denied for schema public LINE 1: CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR...
기본적으로 권한이 할당되지 않은 사용자는 Postgres에 로그인하고 데이터베이스를 나열할 수만 있기 때문에 명령어가 실패합니다.
mydatabaseowner
사용자 인증 정보로 테이블을 만들고 테이블에 대한 모든 권한을myuser
에 부여합니다.PGPASSWORD=$OWNERPASSWORD psql \ -h my-cluster \ -U $OWNERUSERNAME \ -d mydatabase \ -c "CREATE TABLE test (id serial PRIMARY KEY, randomdata VARCHAR ( 50 ) NOT NULL);GRANT ALL ON test TO myuser;GRANT ALL ON SEQUENCE test_id_seq TO myuser;"
출력은 다음과 비슷합니다.
CREATE TABLE GRANT GRANT
myuser
사용자 인증 정보를 사용하여 테이블에 임의의 데이터를 삽입합니다.for i in {1..10}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" done
출력은 다음과 비슷합니다.
INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1 INSERT 0 1
삽입한 값을 가져옵니다.
PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "SELECT * FROM test;"
출력은 다음과 비슷합니다.
id | randomdata ----+--------------- 1 | jup9HYsAjwtW4 2 | 9rLAyBlcpLgNT 3 | wcXSqxb5Yz75g 4 | KoDRSrx3muD6T 5 | b9atC7RPai7En 6 | 20d7kC8E6Vt1V 7 | GmgNxaWbkevGq 8 | BkTwFWH6hWC7r 9 | nkLXHclkaqkqy 10 | HEebZ9Lp71Nm3 (10 rows)
포드 셸을 종료합니다.
exit
Prometheus가 Postgres 클러스터에 대해 측정항목을 수집하는 방법 이해
다음 다이어그램은 Prometheus 측정항목 수집의 작동 방식을 보여줍니다.
다이어그램에서 GKE 비공개 클러스터에는 다음이 포함됩니다.
/
경로 및9187
포트로 측정항목을 수집하는 Postgres 포드- Postgres 포드의 측정항목을 처리하는 Prometheus 기반 수집기
- Cloud Monitoring으로 측정항목을 전송하는
PodMonitoring
리소스
Google Cloud Managed Service for Prometheus는 Prometheus 형식의 측정항목 수집을 지원합니다. Cloud Monitoring은 Postgres 측정항목에 대해 통합 대시보드를 사용합니다.
Zalando는 postgres_exporter 구성요소를 사이드카 컨테이너로 사용하여 Prometheus 형식으로 클러스터 측정항목을 노출합니다.
labelSelector
로 측정항목을 스크래핑하도록PodMonitoring
리소스를 만듭니다.kubectl apply -n postgres -f manifests/03-prometheus-metrics/pod-monitoring.yaml
Google Cloud 콘솔에서 GKE 클러스터 대시보드 페이지로 이동합니다.
대시보드에 0이 아닌 측정항목 수집 비율이 표시됩니다.
Google Cloud 콘솔에서 대시보드 페이지로 이동합니다.
PostgreSQL Prometheus 개요 대시보드를 엽니다. 대시보드에 가져온 행의 수가 표시됩니다. 대시보드가 자동 프로비저닝되는 데 몇 분 정도 걸릴 수 있습니다.
클라이언트 포드에 연결합니다.
kubectl exec -it postgres-client -n postgres -- /bin/bash
임의 데이터를 삽입합니다.
for i in {1..100}; do DATA=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13) PGPASSWORD=$CLIENTPASSWORD psql \ -h my-cluster \ -U $CLIENTUSERNAME \ -d mydatabase \ -c "INSERT INTO test(randomdata) VALUES ('$DATA');" done
페이지를 새로고침합니다. 행 및 블록 그래프가 실제 데이터베이스 상태를 표시하도록 업데이트됩니다.
포드 셸을 종료합니다.
exit