🖼️ Section 1. 들어가며
Kubernetes 환경에서 PostgreSQL을 운영하다 보면 etcd 백업으로 클러스터는 복구했는데,
막상 PostgreSQL PVC 안의 데이터는 복구가 안 돼서 애를 먹는 경우가 많다.
이런 상황에서 PostgreSQL의 백업과 복구도 함께 자동화해놔야 etcd 복원 후에도 DB 상태를 동기화할 수 있다.
이 포스트는 그런 상황을 대비해서 만든, 실제 운영 환경에서 사용 중인 PostgreSQL 백업/복구 자동화 스크립트를 소개하고자 작성되었다.
Bitnami PostgreSQL HA 차트를 기준으로 했지만, StatefulSet 기반이라면 대부분 호환된다.
🖼️ Section 2. 백업 방식 선택: 왜 pg_basebackup인가?
PostgreSQL의 대표적인 백업 방식은 다음과 같다
| 백업 방식 | 특징 | 적합 상황 |
|---|---|---|
pg_dump | SQL 텍스트 백업 | 스키마 백업, 작은 DB |
| 파일 복사 | 데이터 디렉토리 직접 복제 | 테스트 환경 |
pg_basebackup | 전체 Physical 백업 + WAL 포함 | 실제 운영 환경 ✅ |
이 중 pg_basebackup은 PostgreSQL 내부 동작을 깨뜨리지 않으면서 전체 데이터를 복사 + WAL 포함으로 백업할 수 있어, 실무에서 가장 안정적인 선택지다.
특히 Bitnami PostgreSQL HA 차트에선 이 방법이 거의 공식처럼 사용된다.
🖼️ Section 3. 백업 스크립트 구성과 흐름 설명
🧩 전체 흐름
1. Primary Pod 탐색
2. pg_basebackup 수행
3. 압축 파일 생성
4. 로컬로 다운로드
5. 임시 파일 정리
📜 실제 백업 스크립트
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| NAMESPACE=runway | |
| APP_LABEL="app.kubernetes.io/component=postgresql" | |
| BACKUP_DIR="./" | |
| BASEBACKUP_FILE="pg_basebackup.tar.gz" | |
| WAL_ARCHIVE_DIR="/bitnami/postgresql/wal-archive" | |
| WAL_ARCHIVE_TAR="wal_archive_$(date +%Y%m%d_%H%M%S).tar.gz" | |
| PG_USER="mrx" | |
| PG_PORT="5432" | |
| PG_HOST="localhost" | |
| PG_BASEBACKUP_DIR="/tmp/pg_basebackup" | |
| REMOTE_BASEBACKUP_TAR="/tmp/${BASEBACKUP_FILE}" | |
| REMOTE_WAL_TAR="/tmp/${WAL_ARCHIVE_TAR}" | |
| # 1. primary pod 찾기 | |
| PODS=$(kubectl get pods -n $NAMESPACE -l $APP_LABEL -o jsonpath='{.items[*].metadata.name}') | |
| for POD in $PODS; do | |
| ROLE=$( | |
| kubectl exec -n $NAMESPACE $POD — \\ | |
| /opt/bitnami/scripts/postgresql-repmgr/entrypoint.sh repmgr \\ | |
| -f /opt/bitnami/repmgr/conf/repmgr.conf cluster show 2>/dev/null \\ | |
| | grep -w primary | |
| ) | |
| if [[ -n "$ROLE" ]]; then | |
| PRIMARY_POD=$POD | |
| echo "[*] Primary pod found: $PRIMARY_POD" | |
| break | |
| fi | |
| done | |
| if [[ -z "$PRIMARY_POD" ]]; then | |
| echo "[!] Primary pod를 찾을 수 없습니다." | |
| exit 1 | |
| fi | |
| # 2. pg_basebackup 수행 | |
| echo "[*] pg_basebackup 수행중…" | |
| kubectl exec -n $NAMESPACE $PRIMARY_POD — rm -rf $PG_BASEBACKUP_DIR $REMOTE_BASEBACKUP_TAR | |
| kubectl exec -n $NAMESPACE $PRIMARY_POD — mkdir -p $PG_BASEBACKUP_DIR | |
| kubectl exec -n $NAMESPACE $PRIMARY_POD — \\ | |
| pg_basebackup -U $PG_USER -h $PG_HOST -p $PG_PORT -D $PG_BASEBACKUP_DIR -Fp -Xs -P | |
| kubectl exec -n $NAMESPACE $PRIMARY_POD — \\ | |
| tar czf $REMOTE_BASEBACKUP_TAR -C $PG_BASEBACKUP_DIR . | |
| # 4. 로컬로 백업 파일 다운로드 | |
| LOCAL_BASEBACKUP_PATH="${BACKUP_DIR}${BASEBACKUP_FILE}" | |
| LOCAL_WAL_PATH="${BACKUP_DIR}${WAL_ARCHIVE_TAR}" | |
| echo "[*] pg_basebackup 파일 다운로드 중… ($LOCAL_BASEBACKUP_PATH)" | |
| kubectl cp $NAMESPACE/$PRIMARY_POD:$REMOTE_BASEBACKUP_TAR $LOCAL_BASEBACKUP_PATH | |
| # 5. Pod 내 임시 파일 정리 | |
| kubectl exec -n $NAMESPACE $PRIMARY_POD — rm -rf $PG_BASEBACKUP_DIR $REMOTE_BASEBACKUP_TAR $REMOTE_WAL_TAR | |
| echo "[*] 모든 백업 작업 완료!" | |
| echo " – pg_basebackup: $LOCAL_BASEBACKUP_PATH" |
🖼️ Section 4. 복구 스크립트 구성과 절차 설명
복구는 StatefulSet을 일시적으로 중단한 다음, PVC에 접근해 압축을 풀고 데이터를 복원하는 방식이다.
복구 완료 후 StatefulSet을 다시 올리면 PostgreSQL이 자동으로 재시작한다.
📜 실제 복구 스크립트
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| NAMESPACE="runway" | |
| STS_NAME="postgresql-ha-postgresql" | |
| PVC_NAME="data-postgresql-ha-postgresql-0" | |
| PG_DATA_DIR="/bitnami/postgresql/data" | |
| TMP_POD="pg-data-restore" | |
| BACKUP_FILE="./pg_basebackup.tar.gz" | |
| set -e | |
| echo "[*] 1. StatefulSet scale down(0)으로 중지" | |
| kubectl scale sts ${STS_NAME} -n ${NAMESPACE} –replicas=0 | |
| echo "[*] 2. 임시 busybox Pod 생성" | |
| cat <<EOF | kubectl apply -n ${NAMESPACE} -f – | |
| apiVersion: v1 | |
| kind: Pod | |
| metadata: | |
| name: ${TMP_POD} | |
| spec: | |
| restartPolicy: Never | |
| containers: | |
| – name: busybox | |
| image: cr.makina.rocks/external-hub/bitnami/bitnami-shell:11-debian-11-r90 | |
| command: ["sleep", "3600"] | |
| volumeMounts: | |
| – name: datadir | |
| mountPath: /bitnami/postgresql | |
| volumes: | |
| – name: datadir | |
| persistentVolumeClaim: | |
| claimName: ${PVC_NAME} | |
| EOF | |
| echo "[*] 임시 Pod Running 대기…" | |
| kubectl wait –for=condition=Ready pod/${TMP_POD} -n ${NAMESPACE} –timeout=60s | |
| echo "[*] 3. 기존 데이터 디렉토리 완전 삭제" | |
| kubectl exec -n ${NAMESPACE} ${TMP_POD} — sh -c 'rm -rf ${PG_DATA_DIR}/* ${PG_DATA_DIR}/.* 2>/dev/null || true' | |
| kubectl exec -n ${NAMESPACE} ${TMP_POD} — mkdir -p ${PG_DATA_DIR} | |
| echo "[*] 4. basebackup 파일 복사" | |
| kubectl cp ${BACKUP_FILE} ${NAMESPACE}/${TMP_POD}:/tmp/pg_basebackup.tar.gz | |
| echo "[*] 5. 압축 해제" | |
| kubectl exec -n ${NAMESPACE} ${TMP_POD} — tar xvfz /tmp/pg_basebackup.tar.gz -C ${PG_DATA_DIR} | |
| kubectl exec -n ${NAMESPACE} ${TMP_POD} — rm /tmp/pg_basebackup.tar.gz | |
| echo "[*] 6. (필요시 권한 수정)" | |
| kubectl exec -n ${NAMESPACE} ${TMP_POD} — chown -R 1001:root ${PG_DATA_DIR} || true | |
| echo "[*] 7. 임시 Pod 삭제" | |
| kubectl delete pod -n ${NAMESPACE} ${TMP_POD} | |
| echo "[*] 8. StatefulSet 다시 1로 스케일 업" | |
| kubectl scale sts ${STS_NAME} -n ${NAMESPACE} –replicas=1 | |
| kubectl rollout status sts/${STS_NAME} -n ${NAMESPACE} | |
| echo "[*] 복구 후 상태/로그 확인:" | |
| echo " kubectl get pod -n ${NAMESPACE}" | |
| echo " kubectl logs -n ${NAMESPACE} ${STS_NAME}-0 -c postgresql –tail=100" | |
| echo " kubectl exec -it -n ${NAMESPACE} ${STS_NAME}-0 -c postgresql — psql -U mrx -d mrx" |
🖼️ Section 5. 운영 환경에서의 실전 팁
- Kubernetes의 특성상 PVC가 유지되더라도 내부 데이터는 깨질 수 있다. 이럴 때 etcd로 클러스터를 복구하고 나면, PostgreSQL 데이터도 수동 복구가 필수다.
- 이 스크립트를 정기적으로 실행하면 DB 상태를 최신으로 보존할 수 있고, 장애 발생 시 즉시 복구가 가능하다.
- CronJob으로 정기 백업 구성 + 복구 스크립트를 Wiki에 정리해두면 베스트.
🖼️ Section 6. 실무에서 바로 써먹는 요약
pg_basebackup은 PostgreSQL 운영 환경에 가장 안정적인 백업 방식- Kubernetes에서는 Pod가 아니라 PVC 단위로 백업/복구를 구성해야 한다.
- StatefulSet은 복구 시 일시적으로 중지하고 복원 후 다시 올리는 방식이 안전
- etcd로 클러스터 복원 후 DB 동기화를 위해 반드시 DB 백업도 별도로 구성하자