15개 정본 문서에서 날짜별 변경이력, 인시던트 기록, 폐기된 구현 상세를 history/ 디렉토리로 분리. 정본은 현재 상태만 기술하는 백서 형태로 정리. 각 정본에 history 위키링크 추가. 분리된 history 파일 12건: - apisix git push 500, k3s postgresql migration, apisix→traefik 전환 - netbis DDoS 공격, gitea 이전/분리, usb 2.5g hang + NFS hard mount - supabase→patroni, apisix etcd 통합/분리, anomaly-detect 재설계 - patroni failover incident, zlambda nixos migration, ops-agents setup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.0 KiB
title, updated, tags
| title | updated | tags | |||||
|---|---|---|---|---|---|---|---|
| PostgreSQL HA (Patroni + etcd) | 2026-04-06 |
|
개요
PostgreSQL 3노드 HA 클러스터. Patroni가 자동 failover를 관리하고, etcd를 DCS(Distributed Consensus Store)로 사용.
K3s의 kine 데이터스토어로 사용 중.
PostgreSQL 클러스터
| 노드 | 호스트 | IP | 역할 |
|---|---|---|---|
| postgres-1 | incus-hp2 | 10.100.2.5 | Replica 또는 Leader |
| postgres-2 | incus-kr1 | 10.100.3.185 | Replica 또는 Leader |
| postgres-3 | incus-kr2 | 10.100.1.83 | Replica 또는 Leader |
- PostgreSQL 17.9, Patroni 4.1.0
- Patroni 설정:
/etc/patroni.yml - Patroni 서비스:
/etc/systemd/system/patroni.service(ExecStart:/opt/patroni/bin/patroni /etc/patroni.yml) - 클러스터 이름:
nocodb-cluster - 레플리케이션: async streaming
- Patroni REST API: 각 노드 8008 포트
- 컨테이너 메모리 제한: 2GiB (limits.memory)
- shared_buffers: 512MB, effective_cache_size: 1536MB, work_mem: 8MB, maintenance_work_mem: 128MB, wal_buffers: 16MB
DB 목록
| DB | 용도 |
|---|---|
| kine | K3s 데이터스토어 (kine) |
| nocodb | NocoDB |
| n8n | n8n 워크플로 |
| outline | Outline 위키 |
Patroni 명령어
# 클러스터 상태 확인
incus exec postgres-1 -- /opt/patroni/bin/patronictl -c /etc/patroni.yml list
# 수동 switchover
incus exec postgres-1 -- /opt/patroni/bin/patronictl -c /etc/patroni.yml switchover
# Replica reinitialize
incus exec postgres-1 -- /opt/patroni/bin/patronictl -c /etc/patroni.yml reinit nocodb-cluster postgres-3 --force
etcd 클러스터 (Patroni DCS)
| 노드 | 위치 | IP | 방식 |
|---|---|---|---|
| etcd-nas | Synology NAS (서울) | 192.168.9.100 | Docker (quay.io/coreos/etcd:v3.5.21) |
| etcd-mbp | kaffa-macbookpro (서울, Tailscale) | 100.115.154.78 | Docker (quay.io/coreos/etcd:v3.5.17) via colima, peer/client는 socat으로 Tailscale 노출 |
| etcd-jp1 | Incus 컨테이너 jp1 (도쿄) | 10.253.101.233 | Alpine + apk add etcd (v3.5.16) |
- NAS: 데이터
/volume1/docker/etcd/data,--restart=always - jp1: openrc 서비스 (
/etc/init.d/etcd),command_background=true - mbp: docker container
etcd(named volumeetcd-data), client/peer 모두 호스트127.0.0.1만 노출 →socat이 Tailscale IP100.115.154.78의2379/2380으로 forward (~/Library/LaunchAgents/com.kaffa.etcd-socat{,-peer}.plist) - Patroni etcd namespace:
/patroni
etcd 확인 명령어
# 클러스터 멤버 확인
incus exec postgres-1 -- etcdctl --endpoints=http://192.168.9.100:2379 member list -w table
# 엔드포인트 상태
incus exec postgres-1 -- etcdctl --endpoints=http://192.168.9.100:2379,http://100.115.154.78:2379,http://10.253.101.233:2379 endpoint status -w table
etcd에 저장된 데이터
| prefix | 용도 |
|---|---|
/patroni |
Patroni DCS (Leader election, 설정) |
/apisix/osaka |
APISIX 오사카 라우팅 설정 |
/apisix/tokyo |
APISIX sandbox-tokyo 라우팅 설정 (미사용, 데이터 보존) |
/apisix/seoul |
APISIX 서울 K3s 라우팅 설정 |
K3s kine 연결
K3s → HAProxy(OpenWrt 192.168.9.1:5432) → Patroni Leader PostgreSQL
K3s config
# /etc/rancher/k3s/config.yaml (kr1, kr2)
datastore-endpoint: "postgres://kine:kine@192.168.9.1:5432/kine"
HAProxy (OpenWrt)
/etc/haproxy.cfg에 PostgreSQL backend 설정. Patroni REST API(/primary 엔드포인트)로 Leader를 자동 감지.
frontend ft_postgres
bind :5432
default_backend bk_postgres_primary
backend bk_postgres_primary
option httpchk GET /primary
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server postgres-1 10.100.2.5:5432 check port 8008
server postgres-2 10.100.3.185:5432 check port 8008
server postgres-3 10.100.1.83:5432 check port 8008
- Patroni failover 시 HAProxy가 자동으로 새 Leader를 감지 (~3초)
- K3s config 변경 없이 Leader 전환 대응
애플리케이션 접속 경로
NocoDB, n8n 등 K3s 내부 애플리케이션은 pgcat(연결 풀링)을 통해 PostgreSQL에 접속.
nocodb/n8n → pgcat (db.svc.cluster.local:6432) → HAProxy 192.168.9.1:5432 → Patroni Leader
db/pgcat-config ConfigMap의 각 풀의 shards.0.servers는 HAProxy 단일 백엔드만 가리켜야 함:
[pools.nocodb.shards.0]
database = "nocodb"
servers = [["192.168.9.1", 5432, "primary"]]
[pools.n8n.shards.0]
database = "n8n"
servers = [["192.168.9.1", 5432, "primary"]]
⚠️ 하지 말 것: pgcat에 Patroni 노드 IP(10.100.2.5/3.185/1.83)를 직접 박지 말 것. Patroni failover가 발생하면 pgcat는 옛 primary를 계속 가리키게 되어 nocodb/n8n이 read-only 에러 발생.
pgcat는 풀링 전용으로만 쓰고, leader 탐지는 OpenWrt HAProxy에 위임. query_parser_enabled = false 설정 (read/write splitting 비활성).
Patroni failover 인시던트 이력: ../history/2026-04-08-patroni-failover-incident
APISIX etcd 사용 현황
| 사이트 | etcd | prefix | 비고 |
|---|---|---|---|
| osaka | 통합 클러스터 (192.168.9.100, ...) | /apisix/osaka |
Docker APISIX (waf-apisix), apisix#오사카-apisix-osaka |
| sandbox-tokyo | (미가동) | /apisix/tokyo |
2026-04-08 NixOS 전환으로 APISIX 자체 폐기, etcd 데이터만 보존 |
| 서울 K3s | K3s 내부 apisix-etcd StatefulSet (apisix.apisix.svc:2379) | /apisix |
2026-04-08 외부 통합에서 K3s 내부로 복귀 |
APISIX etcd 통합/분리 이력: ../history/2026-04-06-apisix-etcd-consolidation. 현재 외부 통합 etcd는 Patroni DCS + osaka APISIX 전용.
관련 문서
- nas-storage — NAS StorageClass, Jumbo Frame 설정
- storage-plan — NVMe NAS + iSCSI 기획
- backup — 백업 파이프라인
- infra-hosts — 서버 목록
- k3s-migration — K3s 마이그레이션 기록