IT/Database

Kubernetes에 PostgreSQL HA 구성하기

yeTi 2020. 5. 14. 16:26

안녕하세요. yeTi입니다.
오늘은 Kubernetes 환경에서 PostgreSQLHA를 구성해보겠습니다.

작업환경

  • OS : Linux 4.18.0
  • Kubernetes : 1.18
  • Helm : 2.16.7

High Availability

PostgreSQL Documentation에 따르면 PostgreSQL은 자체적으로 Master-Slave형태의 replication을 제공합니다.

추가적으로 Standby의 형태를 Cold Standby, Hot Standby를 제공하고 있어 상황에 맞는 구성을 선택할 수 있습니다.

하지만 Master-Slave형태의 구성에는 클라이언트가 접속할 수 있는 End-Point를 단일화 하는 이슈가 있는데, 이를 Pgpool이라는 미들웨어를 사용하여 해결할 수 있습니다. 또한, PgpoolLoad BalanceAuto Failover를 제공하여 트래픽 분산 및 자동 복구기능을 제공합니다.

Client - PGPool - PostgreSQL Master-1/Slave-N

결론적으로 One-Read/Write Master, Multi-Read Slave 구조로 읽기에 대한 트래픽을 분산을 할 수 있도록 구성할 수 있고 이를 Helm을 이용하여 간편하게 구성할 수 있습니다.

보다 자세한 사항은 Pgpool-II Documentation를 참고하면 됩니다.

설치

아래 사이트를 참고하여 진행했습니다.

Helm repository를 다운받습니다.

# Repository 추가
$ helm repo add bitnami https://charts.bitnami.com/bitnami

# 다운로드
$ helm fetch bitnami/postgresql-ha \
--version 3.2.3

# 압축해제
$ tar -xzvf postgresql-ha-3.2.3.tgz

values.xml파일을 수정합니다.

# values.xml 수정
$ vim postgresql-ha/values.yaml

...
## 디버깅을 위한 로그를 출력하도록 모든 debug설정을 true로 변경
postgresqlImage.debug : true
pgpoolImage.debug : true
metricsImage.debug : true

## NodePort 설정
service.type: NodePort
service.nodePort: 30432

## StorageClass 설정
persistence.storageClass: "pgsql-storage"
...

pgpool.conf의 내용을 변경하기 위해 shell 스크립트를 추가합니다.

pgpool.conf를 수정하는 방법에 values.xml에 경로 정보를 설정해주는 방법이 있지만, 현재 동작하지 않아서 Pod내의 설정을 직접 변경하는 방식으로 진행하였습니다. Custom config file pgpool.conf causes pgpool to overwrite conf.d directory 참고.

$ vim postgresql-ha/files/pgpool-entrypoint-initdb.d/replace-pgpool-conf.sh
#!/bin/bash

# failover_on_backend_error 설정은 off -> on 으로 변경
# failover_on_backend_error 설정을 on으로 하는 이유는 auto-failover를 설정하기 위해서임
sed -i "s/failover_on_backend_error = 'off'/failover_on_backend_error = 'on'/g" /opt/bitnami/pgpool/conf/pgpool.conf

Persistence에 사용할 StorageClass를 생성합니다.

$ vim pgsql-storage.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: pgsql-storage
  namespace: nm-dl-pgsql
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
  clusterID: rook-ceph
  fsName: myfs
  pool: myfs-data0

  csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Delete

$ kubectl create -f pgsql-storage.yaml

PostgreSQL을 설치합니다.

# postgresql-ha 설치
$ helm install --name dl-pgsql \
--namespace nm-dl-pgsql \
./postgresql-ha

설치 후 정보를 확인합니다.

# values.xml이 적용됐는지 확인
$ helm get values dl-pgsql

# release 상태확인
$ helm status dl-pgsql

# PVC 조회
$ kubectl get pvc

# PVC 상태 조회
$ kubectl describe pvc data-dl-postgresql-postgresql-ha-postgresql-0

# pgpool 상태확인
$ export POSTGRES_PASSWORD=$(kubectl get secret --namespace nm-dl-pgsql dl-pgsql-postgresql-ha-postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode)

$ kubectl run dl-pgsql-postgresql-ha-client --rm --tty -i --restart='Never' --namespace nm-dl-pgsql --image bitnami/postgresql:11 --env="PGPASSWORD=$POSTGRES_PASSWORD"          --command -- psql -h dl-pgsql-postgresql-ha-pgpool -p 5432 -U postgres -d postgres

## failover_on_backend_error 설정확인
# pgpool show failover_on_backend_error;

## 노드 상태확인
# show pgpool_nodes;

pgAdmin을 설치하여 원격에서 PostgreSQL에 접속합니다.

$ docker run -d --name pgadmin4 \
-p 49002:80 \
-e "PGADMIN_DEFAULT_EMAIL=admin@domain.com" \
-e "PGADMIN_DEFAULT_PASSWORD=admin" \
dpage/pgadmin4

참고적으로, pgAdmin에서 저장하는 데이터는 volumes/{volume name}/_data/storage/{pgadmin 접속계정}에 저장됩니다.

파이썬을 구동하고 psycopg2 패키지를 설치합니다.

> docker run -it --rm --name ho_python python bash
> pip3 install psycopg2

반복적으로 데이터를 추가하는 스크립트를 수행합니다.

import psycopg2 as pg2
import time

conn=pg2.connect(database="postgres",user="postgres",password="N8xbcvgMiI",host="192.168.5.164",port="30432")
cur = conn.cursor()  
idx = 0;
insert_query = """ INSERT INTO public.test (id, name) VALUES (%s,%s) """

while True:
    cur.execute(insert_query, (idx, "ho_{}".format(idx)))
    conn.commit()
    print("Insert data count: {}".format(idx))
    idx += 1
    time.sleep(1)

cur.close()

PostgreSQL을 삭제합니다.

# chart 삭제
$ helm delete --purge dl-pgsql