Compare commits
14 Commits
f55e1cffb4
...
pre-restru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b303243511 | ||
|
|
226b377387 | ||
|
|
33ce94a75a | ||
|
|
5f9a153d96 | ||
|
|
0d59adb95f | ||
|
|
125413d083 | ||
|
|
a7ecd4b982 | ||
|
|
ad230522be | ||
|
|
bb39d5dd54 | ||
|
|
b24d10d156 | ||
|
|
b4ddf27f95 | ||
|
|
a9d37aa37a | ||
|
|
b206348dd7 | ||
|
|
220157e948 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.obsidian/
|
||||
.trash/
|
||||
.DS_Store
|
||||
graphify-out/
|
||||
.graphify-cache/
|
||||
|
||||
4
.graphifyignore
Normal file
4
.graphifyignore
Normal file
@@ -0,0 +1,4 @@
|
||||
graphify-out/
|
||||
.graphify-cache/
|
||||
.obsidian/
|
||||
.trash/
|
||||
103
history/2026-04-15-apisix-http-logger-removal.md
Normal file
103
history/2026-04-15-apisix-http-logger-removal.md
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
date: 2026-04-15
|
||||
topic: APISIX → CrowdSec http-logger 레거시 경로 제거
|
||||
areas:
|
||||
- infra/crowdsec-safeline.md
|
||||
- infra/apisix.md
|
||||
---
|
||||
|
||||
# APISIX http-logger 레거시 경로 제거 (2026-04-15)
|
||||
|
||||
## 배경
|
||||
|
||||
서울 K3s APISIX가 CrowdSec HTTP acquisition(:8085/apisix-logs)으로 직접 push하던 레거시 경로. VictoriaLogs 파이프라인 도입(2026-04-08) 이후 병행 중이었고, 이번 정리로 레거시 완전 종료.
|
||||
|
||||
## 실측 결과: 이미 전 구간 제거 완료
|
||||
|
||||
작업 착수 후 현황 점검 결과, **모든 구간에서 http-logger 레거시는 이미 사실상 사라진 상태**였음. 본 작업은 실제 제거 변경 없이 doc 정리로 마무리.
|
||||
|
||||
### 1. 서울 K3s APISIX
|
||||
|
||||
Admin API 전수 스캔 (`global_rules`, `routes`, `services`, `plugin_configs`):
|
||||
|
||||
```bash
|
||||
$ curl -sS -H "X-API-KEY: ..." http://apisix-admin:9180/apisix/admin/global_rules
|
||||
{"list":[{"key":"/apisix/global_rules/limit-req","value":{...,"plugins":{"limit-req":{...}}}}],"total":1}
|
||||
```
|
||||
|
||||
`http-logger` 플러그인 흔적 없음. 언제 제거됐는지는 불명 — etcd 감사로그 미확보.
|
||||
|
||||
### 2. K3s Vector 싱크
|
||||
|
||||
`~/k8s/vector/values.yaml` / `kubectl -n logging get cm vector -o yaml`:
|
||||
|
||||
```yaml
|
||||
sinks:
|
||||
vlogs: # VictoriaLogs ES bulk (유일)
|
||||
type: elasticsearch
|
||||
inputs: [parse_apisix, parse_apisix_http, parse_traefik]
|
||||
endpoints: [http://vlogs-victoria-logs-single-server.logging.svc.cluster.local:9428/insert/elasticsearch/]
|
||||
```
|
||||
|
||||
과거 문서 기록(`crowdsecurity/traefik-logs` → :8086)의 HTTP 싱크는 이미 없음. **모든 로그가 VictoriaLogs로만 흐름.**
|
||||
|
||||
### 3. 오사카 APISIX
|
||||
|
||||
`/apisix/osaka/global_rules/1`에 `http-logger`가 존재하지만 target URI가 `https://vector.inouter.com/` — **신규 VictoriaLogs 파이프라인**이지 레거시 CrowdSec(:8085) 아님. 보존.
|
||||
|
||||
```json
|
||||
"http-logger": {
|
||||
"uri": "https://vector.inouter.com/",
|
||||
"concat_method": "new_line",
|
||||
"batch_max_size": 50,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### 4. CrowdSec LAPI (jp1 crowdsec 컨테이너)
|
||||
|
||||
```
|
||||
$ ls /etc/crowdsec/acquis.d/
|
||||
safeline-http.yaml # :8088 (SafeLine)
|
||||
victorialogs-apisix.yaml # VictoriaLogs tail 모드
|
||||
victorialogs-traefik.yaml # VictoriaLogs tail 모드
|
||||
|
||||
$ ss -tlnp | grep crowdsec
|
||||
LISTEN *:6060 (metrics)
|
||||
LISTEN *:8080 (LAPI)
|
||||
LISTEN *:8088 (safeline acquisition)
|
||||
# log-collector(:8087) 별도 데몬
|
||||
```
|
||||
|
||||
**:8085 listener 없음, apisix-logs HTTP acquisition 파일 없음.** 언제 제거됐는지는 불명.
|
||||
|
||||
### 5. CrowdSec 메트릭 (runtime verification)
|
||||
|
||||
`curl http://10.253.100.240:6060/metrics | grep cs_parser_hits`:
|
||||
|
||||
```
|
||||
cs_parser_hits_ok_total{acquis_type="nginx",source="https://vl.inouter.com/",type="victorialogs"} 26
|
||||
cs_parser_hits_ok_total{acquis_type="traefik",source="https://vl.inouter.com/",type="victorialogs"} 115441
|
||||
cs_parser_hits_ko_total{acquis_type="nginx",source="https://vl.inouter.com/",type="victorialogs"} 146
|
||||
```
|
||||
|
||||
**유일한 acquisition source는 `https://vl.inouter.com/` (victorialogs type).** 8085/8086 HTTP acquisition 히트 0.
|
||||
|
||||
버킷 pour:
|
||||
```
|
||||
cs_bucket_poured_total{name="custom/apisix-high-rate-per-ip",source="https://vl.inouter.com/",type="victorialogs"} 115463
|
||||
cs_bucket_poured_total{name="custom/apisix-499-burst",source="https://vl.inouter.com/",type="victorialogs"} 1
|
||||
```
|
||||
|
||||
APISIX 시나리오는 전부 VictoriaLogs 소스에서 발동 — 피드백 루프 정상.
|
||||
|
||||
## 조치 사항
|
||||
|
||||
- `infra/crowdsec-safeline.md` "APISIX → CrowdSec (http-logger, 레거시)" 섹션 삭제
|
||||
- 본 history 파일로 이력 분리
|
||||
- graphify 업데이트
|
||||
|
||||
## 남는 이슈 / 메모
|
||||
|
||||
- **parser name 불일치**: 정본 doc에 `custom/apisix-json-logs` 파서 기재돼 있으나 `victorialogs-apisix.yaml`의 `labels.type: nginx`. 실제 파싱은 nginx 계열 파서가 처리(APISIX access log가 nginx format이므로 동작). 추후 doc 정정 대상.
|
||||
- **관련 정본 경량화**: 3차 보안 구조 섹션의 "APISIX 로그: http-logger → :8085 → custom/apisix-json-logs" 문구도 현행(VictoriaLogs)로 갱신 필요.
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: Longhorn 백업 라벨 키 오타로 18볼륨 백업 전면 미동작
|
||||
date: 2026-04-15
|
||||
tags: [history, incident, longhorn, backup, k3s]
|
||||
---
|
||||
|
||||
## 사건 요약
|
||||
|
||||
2026-04-14 Longhorn 볼륨 백업 파이프라인 신규 구축. RecurringJob 4종(critical/standard × snapshot/backup) 등록 후 정상 동작으로 판단하여 종료. 다음 날(04-15) 정기 점검에서 K8s CronJob은 발화되지만 매번 "Found 0 volumes"로 noop 종료, R2 `longhorn-backup` 버킷에 e2e 테스트 99KB만 존재함을 확인.
|
||||
|
||||
## 근본 원인
|
||||
|
||||
볼륨에 부착한 라벨 키 오타.
|
||||
|
||||
- **정**: `recurring-job-group.longhorn.io/<group>` (대시 포함, 컨트롤러 셀렉터)
|
||||
- **오**: `recurringjob-group.longhorn.io/<group>` (대시 없음, 18볼륨에 부착됨)
|
||||
|
||||
RecurringJob 컨트롤러는 셀렉터 매칭 실패 시 에러나 경고 없이 "Found 0 volumes"로 조용히 Complete 처리하므로 K8s CronJob 상태만 보면 정상으로 보임. R2 객체 증가 부재나 BackupVolume CR 부재로만 감지 가능.
|
||||
|
||||
오타가 어디서 들어왔는지(ops-agents-tofu / Helm values / ArgoCD manifest)는 헤임달이 추적 중. Obsidian `infra/k3s-backup.md` 문서에도 동일 오타로 적혀 있어 향후 신규 볼륨 분류 시 재발 위험이 있었음 → 04-15 수정 완료.
|
||||
|
||||
## 영향
|
||||
|
||||
- 2026-04-14 04:27 UTC ~ 2026-04-15 라벨 수정 시각까지 production 18볼륨 정기 백업·스냅샷 0건
|
||||
- R2 longhorn-backup 버킷 사용량: e2e 테스트 잔존물 99KB (production 0)
|
||||
- 데이터 손실은 발생하지 않음 (앱 레벨 dump 백업은 정상 동작 — Gitea pg_dump 등)
|
||||
|
||||
## 조치
|
||||
|
||||
1. 헤임달이 18볼륨 라벨 재부착 (`recurringjob-group...` 제거 → `recurring-job-group...=enabled`)
|
||||
2. critical-snapshot 다음 hourly 발화에서 "Found 13 volumes" 로그 확인
|
||||
3. critical-backup 6h 경계에서 BackupVolume CR 생성 + R2 객체 증가 확인
|
||||
4. 오타 소스 (Tofu/Helm/ArgoCD) 추적 및 소스 단계에서 수정 (헤임달)
|
||||
5. Obsidian `infra/k3s-backup.md` 라벨 키 정정 + warning callout 추가 (이 문서)
|
||||
|
||||
## 교훈
|
||||
|
||||
- **초기 구축 후 최소 1주기 경과 후 실 작동 검증 필수.** 등록 직후 BackupTarget AVAILABLE/RecurringJob 등록 확인만으로는 부족 — recurring 컨트롤러가 실제로 매칭한 볼륨 수와 BackupVolume CR 생성 여부를 확인해야 함.
|
||||
- **Longhorn recurring 라벨 오류는 silent failure.** 모니터링 알림에 "최근 24h backups CR 0건" 또는 "BackupVolume 마지막 시각 > N시간" 임계값을 추가할 필요.
|
||||
- **공식 키와 문서 키 일치 검증.** Longhorn 공식 문서의 라벨 키와 운영 문서/Tofu 코드를 cross-check.
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- 운영 문서: `infra/k3s-backup.md`
|
||||
- 점검 리포트: Outline `Longhorn 백업 상태 점검 — 2026-04-15` (id `7549c8ac-eebc-4cf4-8d1d-2a5e34c27c2f`)
|
||||
67
history/2026-04-15-pgcat-ha-promotion.md
Normal file
67
history/2026-04-15-pgcat-ha-promotion.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
date: 2026-04-15
|
||||
topic: pgcat HA 승격 (Step 0)
|
||||
areas:
|
||||
- infra/postgresql-ha.md
|
||||
tags: [history, pgcat, patroni, postgresql, ha]
|
||||
---
|
||||
|
||||
Patroni multi-host 마이그레이션 Step 0 — pgcat 자체를 HA로 승격. 이후 Step 1에서 pgcat 를 Patroni REST API aware 로 전환할 때, pgcat 자체가 새 SPoF 가 되지 않도록 선행.
|
||||
|
||||
## 변경 내용
|
||||
|
||||
### helm-charts (`kaffa/helm-charts`)
|
||||
|
||||
- `charts/app` v0.3.0 → **v0.5.0**
|
||||
- `templates/deployment.yaml`: `affinity`, `topologySpreadConstraints` 블록 지원 추가
|
||||
- `templates/pdb.yaml` 신규 — `podDisruptionBudget.minAvailable` / `maxUnavailable` 지원
|
||||
- `values/pgcat.yaml`:
|
||||
- `replicaCount: 2`
|
||||
- `affinity.podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution` (`app=pgcat`, `topologyKey: kubernetes.io/hostname`)
|
||||
- `podDisruptionBudget.minAvailable: 1`
|
||||
|
||||
Commit: `421baef` (`pgcat HA: replicas=2, podAntiAffinity(hostname), PDB minAvailable=1`)
|
||||
|
||||
### ArgoCD
|
||||
|
||||
`pgcat` Application 은 `syncPolicy.automated { prune: true, selfHeal: true }` 설정. git push 직후 `argocd.argoproj.io/refresh=hard` annotate 로 즉시 sync 트리거.
|
||||
|
||||
## 롤아웃 관찰
|
||||
|
||||
- 시작: pgcat-545b8878b9-n45h8 (kr2) 단독 Running
|
||||
- 중간: 구 RS + 신 RS surge 상태 (최대 4 pod), `maxSurge=25%` / `maxUnavailable=25%` 기본 strategy 동작
|
||||
- 종료 (~55초): pgcat-549446cd6b-4hnk2 (**kr1**) + pgcat-549446cd6b-9rhk4 (**hp2**) 2/2 Running
|
||||
- PDB `pgcat`: `minAvailable=1`, `AllowedDisruptions=1` — 정상
|
||||
|
||||
### 노드 분산 검증
|
||||
|
||||
```
|
||||
pgcat-549446cd6b-4hnk2 2/2 Running incus-kr1 10.42.1.107
|
||||
pgcat-549446cd6b-9rhk4 2/2 Running incus-hp2 10.42.2.175
|
||||
```
|
||||
|
||||
kr1 + hp2 — 서로 다른 노드. PodAntiAffinity 동작 확인.
|
||||
|
||||
### 서비스 Endpoints
|
||||
|
||||
```
|
||||
pgcat 10.42.1.107:6432,10.42.2.175:6432
|
||||
```
|
||||
|
||||
두 replica 모두 Service 뒤에 등록.
|
||||
|
||||
## 다운스트림 영향
|
||||
|
||||
rollout 중 NocoDB/n8n 로그 tail. 결과:
|
||||
|
||||
- NocoDB: 단일 `Connection Error: Connection ended unexpectedly` 1회 — pod 재시작 없음, 45h 업타임 유지. knex/pg 자동 재연결 동작.
|
||||
- n8n: 에러 없음.
|
||||
|
||||
## 롤백 경로
|
||||
|
||||
- `values/pgcat.yaml` 에서 `replicaCount: 2` → `1`, `affinity`/`podDisruptionBudget` 블록 제거
|
||||
- 또는 chart 측: 구 버전 (v0.3.0) 으로 `targetRevision` 지정 불가능 (단일 리포지토리 path) — 필요 시 역커밋
|
||||
|
||||
## 후속 작업
|
||||
|
||||
- Step 1: pgcat `pgcat.toml` 에 `use_patroni_api = true` + `patroni_api_port = 8008` 추가, 각 pool `shards.0.servers` 를 Patroni 3노드 IP (`10.100.2.5`, `10.100.3.185`, `10.100.1.83`) 로 교체. 관련 Outline 문서: `07497dd8-c8f7-4027-bb27-7d2cf10623a0`
|
||||
88
history/2026-04-15-vault-mcp-duplicate-investigation.md
Normal file
88
history/2026-04-15-vault-mcp-duplicate-investigation.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: vault-mcp-server 중복 배포 의혹 조사 — 실제 단일 인스턴스
|
||||
date: 2026-04-15
|
||||
tags: [history, investigation, vault, mcp, k3s, incus]
|
||||
---
|
||||
|
||||
## 사건 발단
|
||||
|
||||
Graphify 초기 빌드(2026-04-15) 결과에서 `semantically_similar_to` 엣지로 아래 두 노드가 연결됨:
|
||||
|
||||
- `MCP vault (10.253.101.58:8080)` — `dev/claude-code-setup.md` 출처
|
||||
- `vault-mcp-server v0.2.0 (Go, port 8080)` — `infra/vault.md` 출처
|
||||
|
||||
graphify는 "놀라운 연결(Surprising Connections)"로 제시했고, 두 판이 실제로 다른 시스템인지 같은 시스템의 두 기록인지 정합성 확인이 필요했음.
|
||||
|
||||
## 조사 결과 — 중복 없음
|
||||
|
||||
실제 vault-mcp-server 프로세스는 **jp1 Incus `vault` 컨테이너 (10.253.101.58)** 단일 인스턴스만 존재. 접근 경로가 3개라서 문서상 두 시스템으로 보였을 뿐.
|
||||
|
||||
### 실 아키텍처
|
||||
|
||||
```
|
||||
┌──── hcv.inouter.com (Host) ──────────────> Traefik@K3s:443 ──> 10.253.101.58:8200 (Vault UI/API)
|
||||
│
|
||||
사용자 ───┼──── vault-mcp.inouter.com ────────────────> Traefik@K3s:443 ──> 10.253.101.58:8080 (Vault MCP)
|
||||
│
|
||||
kappa ────┴──── http://10.253.101.58:8080/mcp ─────────────────────────────> 같은 프로세스 (Tailscale 직결)
|
||||
|
||||
10.253.101.58 = jp1 Incus `vault` 컨테이너 (Vault 본체 + vault-mcp-server + systemd)
|
||||
```
|
||||
|
||||
### K3s `tools/vault-mcp` 의 정체
|
||||
|
||||
- ArgoCD 앱 `argocd/vault-mcp` Synced/Healthy 상태지만
|
||||
- 렌더링 리소스는 **Service 1개 + IngressRoute 2개** 뿐 (Deployment/Pod/StatefulSet/HPA 전무)
|
||||
- Service selector 비어 있고 수동 EndpointSlice 가 10.253.101.58 로 고정
|
||||
- 즉 K3s는 **Pod 없는 리버스 프록시 파사드**. 실 처리는 Tailscale로 jp1 컨테이너까지 직접 전달
|
||||
- Helm chart: `gitea.inouter.com/kaffa/helm-charts charts/app` + `values/vault-mcp.yaml` (deployment 블록 없는 ingress-only 렌더링)
|
||||
|
||||
### K3s에 Vault ns 자체가 없음
|
||||
|
||||
- `kubectl get ns | grep vault` → 없음
|
||||
- `vault-active.vault.svc.cluster.local:8200` 경로는 **존재하지 않는 경로** (이전 문서에 이 DNS 이름이 적혀 있었으나 오류)
|
||||
- Vault 본체도 jp1 컨테이너 단일 운영 (`hcv.inouter.com/v1/sys/health` 200 active 확인)
|
||||
|
||||
### 실 트래픽
|
||||
|
||||
24h Traefik 액세스 로그 집계:
|
||||
|
||||
| Host | 총 요청 | 비고 |
|
||||
|---|---|---|
|
||||
| `vault-mcp.inouter.com` | 4 | 전부 조사 중 kappa가 쏜 curl |
|
||||
| `hcv.inouter.com` (`/mcp*` 경로) | 1 | 내부 LAN HEAD 307 (UI 리다이렉트) |
|
||||
|
||||
**실 운영 트래픽 0건.** kappa의 Claude Code는 `http://10.253.101.58:8080/mcp` (Tailscale)로 직접 호출 → Traefik 거치지 않음 → K3s 로그에 흔적 없음.
|
||||
|
||||
- BunnyCDN / Cloudflare 비경유 (응답 헤더에 `cf-ray`, `server: cloudflare`, BunnyCDN 시그니처 없음)
|
||||
- Traefik wildcard cert `wildcard-inouter-tls` 로 직접 TLS 종단
|
||||
- K3s MetalLB 192.168.9.53 (내부 LAN/Tailscale 전용)
|
||||
|
||||
## 확정된 사실
|
||||
|
||||
1. **중복 인스턴스 아님.** 하나의 vault-mcp-server 프로세스 + 세 접근 경로
|
||||
2. **`hcv.inouter.com/mcp` 는 MCP 엔드포인트가 아님.** Vault가 `/mcp` → `/ui/` 307 리다이렉트. MCP 외부 접근은 `vault-mcp.inouter.com/mcp`
|
||||
3. **kappa 현행 사용 경로**: `http://10.253.101.58:8080/mcp` (Tailscale 직결, 평문 HTTP)
|
||||
4. **외부 공개 경로는 현재 실 사용 0건** — CDN 비경유, LAN 전용
|
||||
|
||||
## 조치
|
||||
|
||||
- Obsidian `infra/vault.md` MCP 서버 섹션 전체 재작성 — 실 아키텍처 반영, 잘못된 문서화 정정 callout 추가
|
||||
- Graphify 그래프는 다음 `graphify update` 시 정정된 Obsidian 원문 기반으로 재추출 예정 (노드 관계 정리)
|
||||
|
||||
## 선택적 후속 과제
|
||||
|
||||
- **kappa MCP URL 전환 검토**: `http://10.253.101.58:8080/mcp` → `https://vault-mcp.inouter.com/mcp`. Traefik TLS + wildcard cert 혜택. 단, Tailscale 종속성 유지라 큰 이득 아님
|
||||
- **K3s 파사드 유지 여부**: 24h 트래픽 0건 + CDN 비경유인데 K3s 파사드를 유지할 실용 이유가 크지 않음. 외부 공개 의도가 없다면 ArgoCD 앱 제거 검토. 외부 공개할 거면 Cloudflare Zone + DNAT 추가
|
||||
- **jp1 systemd 로그 접근 권한**: Heimdall 컨테이너에서 jp1 호스트 SSH 거부됨 (공개키 미등록). heimdall 라인에서 vault-mcp 상태를 직접 확인하려면 키 등록 필요
|
||||
|
||||
## 교훈
|
||||
|
||||
- **Graphify `semantically_similar_to` 는 "같은 실체"가 아니라 "비슷한 것"만 뜻함.** 동일 프로세스에 대한 서로 다른 관점(접근 경로별 명명)이 두 노드로 분리되어 기록되어 있었음. 향후 정본 작성 시 접근 경로가 여러 개면 같은 노드 하위에 묶는 서술이 그래프 정합성에 유리
|
||||
- **ArgoCD Healthy 상태만 보고 "Deployment 돌아가는 중"이라 추정하지 말 것.** `kubectl get all -n <ns>` 로 실 리소스 타입 확인 필수. Pod 없는 파사드를 Deployment로 문서화한 게 이번 오류의 원인
|
||||
- **문서에 DNS/FQDN 적을 때 실제 존재하는지 검증하는 습관.** `vault-active.vault.svc.cluster.local:8200`은 실존하지 않는 경로였으나 문서에 들어가 있었음
|
||||
|
||||
## 참조
|
||||
|
||||
- Outline 조사 리포트: `vault-mcp-server 중복 배포 조사 — 2026-04-15` (id `5b6ddffa-de07-401e-8a3b-3edfcd68a1a9`)
|
||||
- 정정된 정본: `infra/vault.md` MCP 서버 섹션
|
||||
58
history/2026-04-16-kine-multihost-migration.md
Normal file
58
history/2026-04-16-kine-multihost-migration.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
date: 2026-04-16
|
||||
topic: kine pgx multi-host 직결 (HAProxy 의존 제거)
|
||||
areas:
|
||||
- infra/postgresql-ha.md
|
||||
tags: [history, k3s, kine, pgx, patroni, postgresql, migration]
|
||||
---
|
||||
|
||||
K3s kine 의 `datastore-endpoint` 를 HAProxy `192.168.9.1:5432` 에서 Patroni 3노드 pgx multi-host 로 전환. API 다운타임 <1초.
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### K3s config (`/etc/rancher/k3s/config.yaml`, kr1 + kr2)
|
||||
|
||||
before:
|
||||
```yaml
|
||||
datastore-endpoint: "postgres://kine:kine@192.168.9.1:5432/kine"
|
||||
```
|
||||
|
||||
after:
|
||||
```yaml
|
||||
datastore-endpoint: "postgres://kine:kine@10.100.2.5:5432,10.100.3.185:5432,10.100.1.83:5432/kine?target_session_attrs=read-write&sslmode=disable"
|
||||
```
|
||||
|
||||
### 실행 순서
|
||||
|
||||
1. **kr2** (init server): config backup → sed 치환 → `systemctl restart k3s` → kubectl get nodes 확인 (5초 내 Ready)
|
||||
2. **kr1** (secondary server): 동일 → 10초 내 Ready
|
||||
3. 4노드 전체 Ready 확인 (hp1, hp2, kr1, kr2), API 응답 시간 ~200ms
|
||||
|
||||
### Patroni switchover 테스트
|
||||
|
||||
`patronictl switchover --leader postgres-1 --candidate postgres-3 --force` (TL12→13):
|
||||
|
||||
- switchover 커맨드 반환: 4.8초
|
||||
- kubectl get nodes 첫 응답: **t+2ms** (즉시) — `incus-hp1 Ready`
|
||||
- API 정상 응답 시간: 231ms
|
||||
- **API 다운타임: <1초**
|
||||
|
||||
kine 의 pgx `target_session_attrs=read-write` 가 자동으로 새 primary (postgres-3, 10.100.1.83) 에 재연결.
|
||||
|
||||
비교: HAProxy 경유 시 health check `inter 3s fall 3` = 최대 9초 감지 지연. pgx multi-host 방식은 connection-level 에서 즉시 재시도.
|
||||
|
||||
## 롤백
|
||||
|
||||
```bash
|
||||
sudo cp /tmp/config.yaml-backup-20260416 /etc/rancher/k3s/config.yaml
|
||||
sudo systemctl restart k3s
|
||||
```
|
||||
|
||||
## HAProxy :5432 상태
|
||||
|
||||
kine + pgpool(NocoDB/n8n/Outline) 전환 완료로 HAProxy postgres 프론트엔드 (`ft_postgres` + `bk_postgres_primary`) 는 더 이상 트래픽 없음. 1주 관측 후 제거.
|
||||
|
||||
## 참조
|
||||
|
||||
- `infra/postgresql-ha.md` — 「K3s kine 연결」 갱신
|
||||
- kine pgx 지원 확인: `k3s-io/kine` go.mod `github.com/jackc/pgx/v5`
|
||||
93
history/2026-04-16-pgcat-patroni-tcp-keepalive.md
Normal file
93
history/2026-04-16-pgcat-patroni-tcp-keepalive.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
date: 2026-04-16
|
||||
topic: pgcat + Patroni TCP keepalive 적용 (Step 1 옵션 B)
|
||||
areas:
|
||||
- infra/postgresql-ha.md
|
||||
tags: [history, pgcat, patroni, postgresql, tcp-keepalive]
|
||||
---
|
||||
|
||||
Patroni multi-host 마이그레이션 원래 Step 1 계획(pgcat Patroni REST API 연동)이 소스 재조사 결과 **pgcat 1.2.0 에 해당 기능 미존재** 판정 → kappa 결정에 따라 옵션 B(HAProxy 구조 유지 + TCP keepalive 추가)로 선회.
|
||||
|
||||
## 배경
|
||||
|
||||
2026-04-15 19:53 UTC Patroni TL5→6 재선출 후 n8n 이 24h 동안 1038건 "Database connection timed out" 에러. 조사 결과 n8n TypeORM 풀의 단일 소켓이 failover 2분 전 열린 채 7588초간 idle 유지 → pgcat 까지 요청 도달조차 못하는 좀비 상태 (`230ec530-b8a6-406c-9165-35c9eb2d8282` 조사 문서).
|
||||
|
||||
n8n rollout restart 로 즉시 정상화. 재발 방지를 위해 **pgcat 와 Patroni 양쪽에 TCP keepalive 명시 활성화**.
|
||||
|
||||
## 변경 내용
|
||||
|
||||
### helm-charts (commit `7ebd7e3`)
|
||||
|
||||
`values/pgcat.yaml` `configMaps.pgcat-config.pgcat.toml` `[general]` 섹션:
|
||||
|
||||
```toml
|
||||
tcp_keepalives_idle = 60
|
||||
tcp_keepalives_interval = 10
|
||||
tcp_keepalives_count = 3
|
||||
```
|
||||
|
||||
pgcat 1.2.0 에서 실제로 지원하는 정확한 키명 (`pgcat.toml` 예제 파일 및 `src/config.rs` 확인). 서버 소켓에 적용.
|
||||
|
||||
### Patroni (DCS)
|
||||
|
||||
```bash
|
||||
patronictl -c /etc/patroni.yml edit-config \
|
||||
-p tcp_keepalives_idle=60 \
|
||||
-p tcp_keepalives_interval=10 \
|
||||
-p tcp_keepalives_count=3 --force
|
||||
patronictl reload nocodb-cluster --force
|
||||
```
|
||||
|
||||
3노드 전체 postgresql.conf 에 반영, SIGHUP 으로 적용 (재시작 불필요). 새 TCP 연결부터 keepalive 옵션 적용.
|
||||
|
||||
**주의**: `SHOW tcp_keepalives_idle` 을 unix socket (psql local) 에서 실행하면 0으로 출력. TCP 세션 확인 필수:
|
||||
```bash
|
||||
PGPASSWORD=... psql -h 192.168.9.1 -p 5432 -U n8n -d n8n -c "SHOW tcp_keepalives_idle"
|
||||
# → 60
|
||||
```
|
||||
|
||||
## 검증 — Patroni switchover 재현 테스트
|
||||
|
||||
**before**: TL6 leader postgres-3 (10.100.1.83)
|
||||
**action**: `patronictl switchover --leader postgres-3 --candidate postgres-2 --force`
|
||||
**after**: TL7 leader postgres-2 (10.100.3.185)
|
||||
|
||||
### pgcat → 새 leader 도달 시간
|
||||
|
||||
```
|
||||
T1=22:24:37.696 UTC switchover 커맨드 반환
|
||||
t+0002ms pgcat 경유 SELECT → "connection lost" (HAProxy 아직 구 leader 마크)
|
||||
t+5175ms 여전히 connection lost
|
||||
t+7331ms 10.100.1.83 응답 (구 leader, 이제 replica — SELECT 는 성공)
|
||||
t+8461ms 10.100.3.185 응답 (새 leader)
|
||||
```
|
||||
|
||||
**write 가능 복구 시간: ~8.5초.** HAProxy `inter 3s fall 3` (9초 감지) 이론치와 일치. keepalive 와 독립 — HAProxy 헬스체크 파라미터가 결정.
|
||||
|
||||
### 애플리케이션 영향 (switchover 전후 ~150초 창)
|
||||
|
||||
| 서비스 | 에러 수 | 타입 |
|
||||
|---|---|---|
|
||||
| NocoDB | 1 | "unexpected EOF" 1회 |
|
||||
| n8n | 9 건 (7초 윈도우) | SocketError/UnexpectedEof, Connection terminated, AllServersDown, Database connection timed out |
|
||||
|
||||
**이전 2026-04-15 failover (1038건, 2시간 지속) 대비 극적 대비.** 좀비 소켓 없음.
|
||||
|
||||
## 롤백
|
||||
|
||||
- `values/pgcat.yaml` 에서 `tcp_keepalives_*` 3줄 제거 → ArgoCD sync → pgcat rolling restart
|
||||
- Patroni: `patronictl edit-config` 에서 동일 3개 파라미터 제거 → reload
|
||||
|
||||
## 관측 기간
|
||||
|
||||
7일 (2026-04-23까지). 다음 Patroni failover 발생 시 app 에러 윈도우 < 10초 지속 여부 확인. 지속 시 원인 재조사.
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- `infra/postgresql-ha.md` — 「좀비 소켓 방지 — TCP keepalive」 섹션 신설
|
||||
- `history/2026-04-16-pgcat-patroni-api-audit-correction.md` — (별도 예정) pgcat Patroni API 미지원 정정, 원 감사 07497dd8 의 PR #944 cite 오류
|
||||
- helm-charts commit: https://gitea.inouter.com/kaffa/helm-charts/commit/7ebd7e3
|
||||
|
||||
## 후속
|
||||
|
||||
- kappa 지시: **PgPool-II PoC** (이 작업 안정화 후 별도 지시 예정)
|
||||
64
history/2026-04-16-pgpool-full-migration.md
Normal file
64
history/2026-04-16-pgpool-full-migration.md
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
date: 2026-04-16
|
||||
topic: pgpool-II 전면 전환 + pgcat 퇴역
|
||||
areas:
|
||||
- infra/postgresql-ha.md
|
||||
tags: [history, pgpool, pgcat, patroni, postgresql, migration]
|
||||
---
|
||||
|
||||
n8n PoC 성공 확인 후 NocoDB·Outline 도 pgpool 경유로 전환. pgcat ArgoCD App + 리소스 삭제.
|
||||
|
||||
## 전환 순서 + 결과
|
||||
|
||||
### NocoDB (tools/nocodb)
|
||||
|
||||
`kubectl -n tools set env deploy/nocodb NC_DB="pg://pgpool.db.svc.cluster.local:9999?u=nocodb&p=nocodb&d=nocodb"` → rollout restart → 200 OK. Baseline 2분 에러 0건.
|
||||
|
||||
### Outline (outline/outline)
|
||||
|
||||
`outline-secrets` DATABASE_URL 호스트를 `pgpool.db.svc.cluster.local:9999` 로 변경 → rollout restart → 200 OK. PVC multi-attach 이슈로 old pod 수동 삭제 필요 (RWO volume Longhorn). Sequelize 호환 문제 없음.
|
||||
|
||||
**주의**: outline-secrets 는 ExternalSecret (Vault `secret/apps/outline`) 관리. K8s Secret 직접 패치는 refreshInterval(1h) 후 Vault 값으로 덮어씌워짐 → **kappa 가 Vault 의 DATABASE_URL 을 갱신해야 영속**.
|
||||
|
||||
### pgpool 설정 변경
|
||||
|
||||
`pool_passwd = ''` 추가 — 이전 entrypoint 가 생성한 pool_passwd 파일이 남아 nocodb/outline 유저를 찾지 못하는 에러 해결. `allow_clear_text_frontend_auth=on` + pool_hba `password` 방식으로 pool_passwd 불필요.
|
||||
|
||||
### 통합 switchover 테스트
|
||||
|
||||
`patronictl switchover --leader postgres-2 --candidate postgres-1 --force` (TL10→11):
|
||||
|
||||
| 서비스 | 에러 수 | HTTP |
|
||||
|---|---|---|
|
||||
| n8n | 3 (transient) | 200 |
|
||||
| NocoDB | 0 | 200 |
|
||||
| Outline | 0 | 200 |
|
||||
|
||||
write 복구 **t+3ms** (즉시). pgpool `SHOW POOL_NODES` 에서 primary 자동 갱신.
|
||||
|
||||
### pgcat 퇴역
|
||||
|
||||
1. `kubectl -n argocd delete application pgcat` (cascade 삭제)
|
||||
2. 잔존 리소스 수동 정리: Deployment, Service, ConfigMap (pgcat-config, pgcat-monitor), PDB
|
||||
3. `helm-charts/values/pgcat.yaml` git rm + push (commit `534118e`)
|
||||
|
||||
## 최종 상태
|
||||
|
||||
```
|
||||
n8n → pgpool.db.svc.cluster.local:9999 ✓ 200
|
||||
NocoDB → pgpool.db.svc.cluster.local:9999 ✓ 200
|
||||
Outline → pgpool.db.svc.cluster.local:9999 ✓ 200
|
||||
pgcat → 삭제 (ArgoCD App + K8s resources + helm values)
|
||||
```
|
||||
|
||||
## 미해결
|
||||
|
||||
- Outline ExternalSecret → Vault 에서 DATABASE_URL 갱신 필요 (1h 이내 kappa 처리)
|
||||
- pgpool `pool_passwd` 비활성 (clear-text frontend) → 장기 AES 암호화 하드닝
|
||||
- retry_timeout=70/ttl=30 상향 작업 중단 상태 — 별도 재개
|
||||
|
||||
## 참조
|
||||
|
||||
- helm-charts: a6bb681(pool_passwd 비활성) → **534118e**(pgcat 퇴역)
|
||||
- PoC history: `history/2026-04-16-pgpool-n8n-poc.md`
|
||||
- `infra/postgresql-ha.md` — 「pgcat」 섹션 삭제, 「pgpool-II」 로 교체
|
||||
156
history/2026-04-16-pgpool-n8n-poc.md
Normal file
156
history/2026-04-16-pgpool-n8n-poc.md
Normal file
@@ -0,0 +1,156 @@
|
||||
---
|
||||
date: 2026-04-16
|
||||
topic: pgpool-II PoC (n8n 전용 전환)
|
||||
areas:
|
||||
- infra/postgresql-ha.md
|
||||
tags: [history, pgpool, pgcat, patroni, postgresql, poc]
|
||||
---
|
||||
|
||||
n8n 이 Patroni failover 와 etcd 순단에 풀 좀비로 취약 — pgcat 의 클라이언트-측 연결 관리로는 해소 불가. pgpool-II streaming_replication 모드 PoC 로 n8n 만 전환, 검증 결과 양쪽 시나리오에서 `무에러 또는 <2초 자가복구` 달성.
|
||||
|
||||
## 전환 경로
|
||||
|
||||
- 전환 전: n8n → pgcat.db.svc:6432 → OpenWrt HAProxy 192.168.9.1:5432 → Patroni leader
|
||||
- 전환 후: n8n → pgpool.db.svc:9999 → Patroni 3노드 직결
|
||||
|
||||
NocoDB·Outline 은 pgcat 유지. 7일 관측 후 확대 여부 판단.
|
||||
|
||||
## 이미지 선택
|
||||
|
||||
- kappa 원 스펙: `pgpool/pgpool:4.6.3 (공식)` — 존재하지 않음. `pgpool/pgpool` 리포지토리 최대 태그 **4.4.3** (2024 이후 방치), 이후 버전은 `bitnamilegacy/pgpool` 에만 존재
|
||||
- 1차 시도: Bitnami 4.6.3 — env 기반 설정 자동화가 scram-sha-256 패스워드를 pgpool 내부 포맷으로 재해시해서 백엔드 인증 실패. 디버깅 폐기 (kappa 지시)
|
||||
- 2차 채택: **`pgpool/pgpool:4.4.3`** (공식) + 최소 ConfigMap 마운트
|
||||
|
||||
## 최종 설정 (`helm-charts/pgpool/`)
|
||||
|
||||
ArgoCD 관리 대상. `kaffa/helm-charts` 리포 `pgpool/` 디렉토리 raw manifest. Application 매니페스트 `kubectl apply` 로 1회 부트스트랩.
|
||||
|
||||
### 핵심 구성
|
||||
|
||||
`pgpool.conf` (~30 라인):
|
||||
|
||||
```
|
||||
listen_addresses = '*'
|
||||
port = 9999
|
||||
backend_clustering_mode = 'streaming_replication'
|
||||
|
||||
backend_hostname0 = '10.100.2.5' # postgres-1
|
||||
backend_port0 = 5432
|
||||
backend_weight0 = 1
|
||||
backend_flag0 = 'ALLOW_TO_FAILOVER'
|
||||
# ... backend1=postgres-2, backend2=postgres-3 동일 패턴
|
||||
|
||||
sr_check_user = 'sr_check'
|
||||
sr_check_password = '<plaintext>'
|
||||
sr_check_database = 'postgres'
|
||||
sr_check_period = 10
|
||||
|
||||
health_check_user = 'sr_check'
|
||||
health_check_password = '<plaintext>'
|
||||
health_check_period = 10
|
||||
health_check_timeout = 5
|
||||
|
||||
failover_on_backend_error = off # Patroni 가 promotion 수행
|
||||
failover_command = ''
|
||||
follow_primary_command = ''
|
||||
use_watchdog = off
|
||||
enable_pool_hba = on
|
||||
allow_clear_text_frontend_auth = on
|
||||
|
||||
load_balance_mode = off # 모든 쿼리 primary
|
||||
num_init_children = 32
|
||||
max_pool = 4
|
||||
connection_cache = on
|
||||
```
|
||||
|
||||
`pool_hba.conf`:
|
||||
```
|
||||
local all all trust
|
||||
host all all 0.0.0.0/0 password
|
||||
host all all ::/0 password
|
||||
```
|
||||
|
||||
### 인증 설계 핵심
|
||||
|
||||
Postgres 가 cluster-wide `password_encryption = scram-sha-256` 이라 모든 역할 비밀번호는 SCRAM 해시로 저장. pgpool 이 백엔드에 scram-sha-256 auth 하려면 plaintext 필요.
|
||||
|
||||
- `pool_passwd` **미사용** — pgpool 이 plaintext 엔트리를 자동 md5 로 변환하면 backend SCRAM 거절되어 `failed to authenticate with backend using SCRAM` 발생
|
||||
- `allow_clear_text_frontend_auth=on` + pool_hba `password` 메소드 → 클라이언트가 plaintext 로 전송 → pgpool 이 그 값을 backend SCRAM challenge-response 에 그대로 사용
|
||||
- K8s Service 내부 트래픽이므로 clear-text 는 클러스터 내 허용
|
||||
- 장기: pgpool PGPOOLKEYFILE + AES 암호화 password 도입 검토 (Bitnami 가 하는 방식)
|
||||
|
||||
### Secret 처리
|
||||
|
||||
`pgpool-secrets` K8s Secret (수동 `kubectl create`, git 미추적):
|
||||
- `sr_check_password` — 16-byte hex 랜덤
|
||||
- `n8n_password` — `n8n` (pgcat 와 동일)
|
||||
|
||||
entrypoint.sh 가 env 에서 sed 로 `pgpool.conf.tmpl` 의 `__SR_CHECK_PASSWORD__` 를 치환하여 emptyDir 에 `pgpool.conf` 렌더. 정규 운영 승격 시 ExternalSecret + Vault 로 이관.
|
||||
|
||||
### Patroni 에 sr_check role 생성
|
||||
|
||||
```sql
|
||||
CREATE ROLE sr_check WITH LOGIN REPLICATION PASSWORD '<hex>';
|
||||
GRANT pg_monitor TO sr_check;
|
||||
```
|
||||
|
||||
postgres-2(당시 leader) 에서 실행, async streaming 으로 postgres-1/postgres-3 에 자동 전파. pg_hba 는 `host all all 0.0.0.0/0 md5` 이미 설정되어 있어 추가 변경 불필요.
|
||||
|
||||
## 검증 시나리오
|
||||
|
||||
### 1. Patroni switchover (postgres-3 → postgres-2)
|
||||
|
||||
```
|
||||
T0 T1(+4.0s) T1+2s
|
||||
switchover → done new primary 라우팅 확립
|
||||
```
|
||||
|
||||
- n8n 로그: `failed to create a backend 2 connection` × 1 → `Database connection recovered`
|
||||
- pgpool `SHOW POOL_NODES`: `last_status_change` 가 switchover 시점에 갱신, `role=primary` 가 새 노드로 이동
|
||||
- n8n.inouter.com 200 유지
|
||||
- **자동 복구 ~2초**
|
||||
|
||||
비교: 같은 시나리오 pgcat 에서는 client 측 pg 풀이 idle 소켓 재사용으로 좀비 → pod restart 필요 (2026-04-15 19:53 UTC 사고 1038 에러).
|
||||
|
||||
### 2. mbp etcd 60초 stop
|
||||
|
||||
```
|
||||
T0 T+30s 중간 쓰기 T+60s T+70s
|
||||
mbp stop → SELECT OK, write OK → mbp start → 확인: 계속 쓰기 OK
|
||||
```
|
||||
|
||||
- n8n 에러 **0건**, HTTP 200 유지
|
||||
- pgpool 이 backend Patroni 자체를 직접 봄 — etcd 쿼럼은 2노드(NAS + jp1) 로 유지되어 Patroni leader 변경 없음, pgpool 경로 영향 없음
|
||||
|
||||
비교: pgcat 경로에서는 mbp etcd 56초 다운 시 n8n `Database connection timed out` 캐스케이드 → 503 → pod restart 필수 (오늘 오후 인시던트).
|
||||
|
||||
## 배포 아티팩트
|
||||
|
||||
- helm-charts 디렉토리: `pgpool/` — `configmap.yaml`, `deployment.yaml`, `service.yaml`, `pdb.yaml`
|
||||
- ArgoCD Application: `pgpool` (namespace `argocd`, source path `pgpool`, selfHeal + prune)
|
||||
- K8s 리소스: namespace `db` (pgcat 와 공존)
|
||||
|
||||
## 롤백
|
||||
|
||||
n8n ConfigMap `n8n-app-config` 에서 `DB_POSTGRESDB_HOST` 를 `pgpool.db.svc.cluster.local:9999` 에서 `pgcat.db.svc.cluster.local:6432` 로 되돌리고 rollout restart. 소요 시간 ~30초.
|
||||
|
||||
## 7일 관측 계획 (만료 2026-04-23)
|
||||
|
||||
- 자연 Patroni failover 발생 시 n8n 에러 창 <5초 유지 여부
|
||||
- pgpool `SHOW STATS` / `SHOW POOL_NODES` 주간 샘플링
|
||||
- n8n 일별 DB 에러 카운트 (목표 <10/day 비-failover 시)
|
||||
- pgpool 리소스 사용량 (num_init_children=32 × max_pool=4 = 최대 128 backend connections per pod × 2 pod = 256 total. 현재 n8n 평균 idle 수준 확인 필요)
|
||||
|
||||
긍정 관측이면 NocoDB → pgpool, Outline → pgpool 단계 전환. 부정이면 pgpool 해체 + pgcat 복귀.
|
||||
|
||||
## 참조
|
||||
|
||||
- helm-charts commit 시리즈: a6f5991(초기) → e1dcd6d(bitnami 전환) → 213babb(scram) → 13dfae1(port 수정) → d3dde47(detach_false_primary) → bc6faae(공식 이미지 피봇) → 74ca477(pool_passwd 제거) → **9bc3a24(clear-text auth, 최종)**
|
||||
- 선행 조사: n8n 풀 좀비 `230ec530-b8a6-406c-9165-35c9eb2d8282`
|
||||
- pgcat 후속: TCP keepalive `129fbf50-e69b-47fd-ad55-3f5ff9066caf`
|
||||
- retry_timeout 상향 → mbp etcd hiccup 시 n8n 503 사고 (오늘 오후) → pgpool PoC 의 직접 동기
|
||||
|
||||
## 미해결 / Syn 공유
|
||||
|
||||
- `pgpool/pgpool` 4.4.3 이후 방치 — pgpool 공식 이미지의 미래 불확실. 대안: Bitnami legacy 계속 사용하거나 우리가 커스텀 빌드
|
||||
- plaintext pool_passwd 우회 — scram-sha-256 백엔드 + pgpool 백엔드 auth 에 권고 방식은 AES 암호화. 1주 관측 후 하드닝 필요
|
||||
@@ -6,7 +6,7 @@ tags: [infra, backup]
|
||||
|
||||
## Longhorn PVC 백업 (K3s)
|
||||
|
||||
BackupTarget `default` → R2 버킷 `longhorn-backup` (시크릿 `longhorn-backup-r2`). RecurringJob 4종 (critical-snapshot 매시, critical-backup 6h, standard-snapshot 일 1회 03:00 UTC, standard-backup 일 1회 04:00 UTC).
|
||||
BackupTarget `default` → R2 버킷 `longhorn-backup` (시크릿 `longhorn-backup-r2`). RecurringJob 4종 (critical-snapshot 매시 UTC, critical-backup 6h UTC, standard-snapshot `0 18 * * *` UTC = KST 03:00, standard-backup `0 19 * * *` UTC = KST 04:00).
|
||||
|
||||
### RecurringJob 그룹 볼륨 라벨 — **정확한 키 주의**
|
||||
|
||||
|
||||
@@ -50,16 +50,6 @@ Traefik DaemonSet (stdout JSON accessLog)
|
||||
| 오사카 Vector | Docker `timberio/vector:0.45.0-debian`, `/etc/vector/vector.yaml`, `docker_logs` source → `parse_apisix` → `vlogs` ES sink. `location: osaka` 필드 추가 |
|
||||
| 파서 | `custom/apisix-json-logs` (로컬) |
|
||||
|
||||
### APISIX → CrowdSec (http-logger, 레거시 — 병행 중)
|
||||
|
||||
서울 APISIX가 CrowdSec HTTP acquisition으로 직접 push하는 기존 경로. VictoriaLogs 경로와 이중 수신 중이며 추후 제거 예정.
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| 설정 | K3s APISIX GatewayProxy `global_rules/http-logger` (`uri: http://10.253.100.240:8085/apisix-logs`) |
|
||||
| CrowdSec 포트 | 8085 |
|
||||
| 인증 | `Authorization: apisix-crowdsec-log-2024` |
|
||||
|
||||
### APISIX → log-collector → CrowdSec (sandbox-tokyo)
|
||||
|
||||
```
|
||||
@@ -172,7 +162,7 @@ ddos-detect AI 분석기 폐기 후 deterministic 패턴 매칭으로 대체.
|
||||
- 현재 모두 `remediation: true` (즉시 ban). dry-run으로 시작 안 함 — false positive 발생 시 임계값 또는 ban duration 조정.
|
||||
|
||||
|
||||
과거 인시던트 및 변경 이력은 `history/` 참조. 예: `history/2026-04-10-edge-cleanup.md` (cf-audit-cleanup-2 3-incident chain, Turnstile sitekey 교체, 미들웨어 64811 `/__captcha/verify` 버그 수정 등).
|
||||
과거 인시던트 및 변경 이력은 `history/` 참조. 예: `history/2026-04-10-edge-cleanup.md` (cf-audit-cleanup-2 3-incident chain, Turnstile sitekey 교체, 미들웨어 64811 `/__captcha/verify` 버그 수정 등), [[../history/2026-04-15-apisix-http-logger-removal|2026-04-15 APISIX http-logger 레거시 제거]].
|
||||
|
||||
### 발견 사항: K3s APISIX 글로벌 limit-req
|
||||
|
||||
@@ -285,8 +275,9 @@ Kappa 계정용 `cs-cf-worker-bouncer`와 별도 컨테이너로 분리 운영.
|
||||
- tengine 미사용, APISIX 직접 연동
|
||||
|
||||
### 3차: CrowdSec 로그 분석
|
||||
- Traefik 로그: Vector DaemonSet → `:8086` → `crowdsecurity/traefik-logs`
|
||||
- APISIX 로그: http-logger → `:8085` → `custom/apisix-json-logs`
|
||||
- Traefik / APISIX 로그: Vector → VictoriaLogs(`vl.inouter.com`) → CrowdSec `victorialogs` acquisition (tail 모드)
|
||||
- SafeLine 차단: PG NOTIFY → safeline-listener → CrowdSec HTTP acquisition(`:8088`)
|
||||
- sandbox-tokyo APISIX: http-logger → log-collector(`:8087`) → CrowdSec
|
||||
- HTTP 시나리오 매칭 → decision → bouncer 피드백
|
||||
|
||||
## iron-kr-waf BunnyCDN Pull Zone (구 waf-kr)
|
||||
|
||||
58
infra/hosts/incus-hp1.md
Normal file
58
infra/hosts/incus-hp1.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: incus-hp1
|
||||
updated: 2026-04-16
|
||||
tags: [infra, host, incus, k3s, seoul]
|
||||
type: host
|
||||
host_kind: server
|
||||
location: seoul
|
||||
provider: self-hosted
|
||||
status: active
|
||||
ssh_host: incus-hp1
|
||||
public_ip: null
|
||||
tailscale_ip: null
|
||||
lan_ip: 192.168.9.227
|
||||
os: Debian 13
|
||||
cpu_model: Xeon E5-2670
|
||||
cpu_cores: 32
|
||||
ram_gb: 188
|
||||
k3s_role: worker
|
||||
critical: false
|
||||
monthly_cost_usd: 0
|
||||
---
|
||||
|
||||
## 역할
|
||||
|
||||
Incus + K3s 워커 호스트 (서울존). HP ProLiant DL360p Gen8 베어메탈. K3s 클러스터에서 worker(k3s-agent)로 참여.
|
||||
|
||||
## 네트워크
|
||||
|
||||
- LAN: 192.168.9.227 (eno1, 1GbE — 2.5G 어댑터 없음)
|
||||
- iLO: 192.168.9.140 (hp1-ilo.lan)
|
||||
- Tailscale: 미설치
|
||||
|
||||
## 스토리지
|
||||
|
||||
- sda 273G: 시스템 (/ ext4 259G + swap 14G)
|
||||
- nvme0n1 954G: Incus btrfs storage pool `default`
|
||||
|
||||
## Incus
|
||||
|
||||
- 버전: 6.0.4 (Debian 패키지)
|
||||
- storage pool: `default` (btrfs, /dev/nvme0n1)
|
||||
- network: `incusbr0` (10.100.4.1/24, NAT)
|
||||
- profile: default (incusbr0 + root on default pool)
|
||||
|
||||
## K3s
|
||||
|
||||
- 버전: v1.34.5+k3s1
|
||||
- 역할: worker (k3s-agent)
|
||||
- server: https://192.168.9.135:6443 (incus-kr2)
|
||||
- config: /etc/rancher/k3s/config.yaml
|
||||
|
||||
## 상세
|
||||
|
||||
- 2026-04-16 신규 셋업 (Incus + K3s agent)
|
||||
- hp2와 동일 Gen8 스펙이나 2.5G LAN 미탑재 (1G only)
|
||||
- Longhorn replica 참여 시 nvme에 별도 마운트 필요
|
||||
|
||||
상세 인프라 컨텍스트: [[../infra-hosts]]
|
||||
@@ -16,6 +16,7 @@ tags: [infra, network, kr-zone, openwrt]
|
||||
| incus-jp1 | 100.109.123.1 | Incus 호스트 (도쿄) | agents, db, default, monitoring 프로젝트 |
|
||||
| incus-kr1 | 100.84.111.28 | Incus+K3s 호스트 (서울) | GTX 1080 Ti, K3s control-plane (LAN 192.168.9.214), default 프로젝트 |
|
||||
| incus-kr2 | 100.119.109.41 | Incus+K3s 호스트 (서울) | K3s control-plane (LAN 192.168.9.135), default, inbest 프로젝트 |
|
||||
| incus-hp1 | — | Incus+K3s 호스트 (서울) | **HP ProLiant DL360p Gen8** 베어메탈, Xeon E5-2670 32코어, 188GB RAM, K3s worker/k3s-agent (LAN 192.168.9.227), 1GbE only (2.5G 미탑재), Tailscale 미설치, default 프로젝트, 2026-04-16 신규 |
|
||||
| incus-hp2 | 100.100.52.34 | Incus+K3s 호스트 (서울) | **HP ProLiant DL360p Gen8** 베어메탈, Xeon E5-2670 32코어, 188GB RAM, 커널 6.12.74+deb13+1 (2026-04-14 업데이트), K3s worker/k3s-agent (LAN 192.168.9.134), default, inbest 프로젝트 |
|
||||
| openwrt-gw | 100.66.60.66 | **OpenWrt 라우터 (서울, critical)** | HAProxy: 80/443 → MetalLB Traefik(192.168.9.53:80/443), 9080/9443 → MetalLB APISIX(192.168.9.50:80/443), **5432 → Patroni PostgreSQL Leader (K3s kine 데이터스토어 진입점, [[postgresql-ha]] 참조)**. 이 노드 다운 시 K3s API/HTTP 진입 모두 중단 |
|
||||
| zlambda (구 sandbox-tokyo) | 100.78.51.18 | [[zlambda|NixOS 베이스 호스트]] (도쿄, Linode `zlambda`) | NixOS 25.05 (Warbler), 공인 139.162.71.52, sshd+tailscale+docker, 2026-04-08 Debian→NixOS 전환 (이전 APISIX/etcd/microsocks/tlsproxy/vault-prod/wg-easy 모두 제거됨), Linode 프로필 kernel=`linode/direct-disk`, BBR+fq+sysctl 튜닝, configuration: Gitea [`kaffa/nixos-infra`](https://gitea.inouter.com/kaffa/nixos-infra) (kaffa-macmini `~/nixos-infra/`, zlambda `/root/nixos-infra/`) |
|
||||
@@ -24,10 +25,11 @@ tags: [infra, network, kr-zone, openwrt]
|
||||
|
||||
## 서울 K3s 클러스터
|
||||
|
||||
서울존 3대(kr1, kr2, hp2)를 K3s v1.34.5+k3s1 클러스터로 구성. **kr1/kr2는 control-plane, hp2는 worker(k3s-agent)**.
|
||||
서울존 4대(kr1, kr2, hp1, hp2)를 K3s v1.34.5+k3s1 클러스터로 구성. **kr1/kr2는 control-plane, hp1/hp2는 worker(k3s-agent)**.
|
||||
|
||||
| 노드 | LAN IP | OS |
|
||||
|------|--------|----|
|
||||
| incus-hp1 | 192.168.9.227 | Debian 13 (trixie) |
|
||||
| incus-hp2 | 192.168.9.134 | Debian 13 (trixie) |
|
||||
| incus-kr1 | 192.168.9.214 | Debian 13 (trixie) |
|
||||
| incus-kr2 | 192.168.9.135 | Debian 13 (trixie) |
|
||||
@@ -264,6 +266,7 @@ Docker: `--runtime=nvidia` 또는 `--gpus all`로 GPU 사용. Podman: CDI 방식
|
||||
└── OpenWrt 라우터 (공인 IP: 220.120.65.245, 내부: 192.168.9.1)
|
||||
├── incus-kr1 (192.168.9.214) ← K3s control-plane
|
||||
├── incus-kr2 (192.168.9.135, br-uplink 고정) ← K3s control-plane
|
||||
├── incus-hp1 (192.168.9.227, 1GbE) ← K3s worker (k3s-agent)
|
||||
└── incus-hp2 (192.168.9.134) ← K3s worker (k3s-agent)
|
||||
|
||||
외부 트래픽 흐름 (TCP):
|
||||
@@ -332,6 +335,7 @@ USB autosuspend/NFS hang 인시던트 이력: [[../history/2026-04-04-usb-25g-ha
|
||||
|--------|----------------|------|------------|
|
||||
| incus-kr1 | 192.168.9.214 | control-plane | 서울 |
|
||||
| incus-kr2 | 192.168.9.135 | control-plane | 서울 |
|
||||
| incus-hp1 | 192.168.9.227 | worker (k3s-agent) | 서울 |
|
||||
| incus-hp2 | 192.168.9.134 | worker (k3s-agent) | 서울 |
|
||||
|
||||
## IPv6 prefix
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: K3s 백업 파이프라인
|
||||
updated: 2026-04-15 Longhorn 라벨 키 오타 수정 (recurring-job-group, 대시 포함). 자세히는 history/2026-04-15-longhorn-label-typo.md 참조
|
||||
updated: 2026-04-15 Longhorn 라벨 키 오타 수정 (recurring-job-group, 대시 포함). 자세히는 history/2026-04-15-longhorn-backup-label-typo.md 참조
|
||||
tags: [infra, backup, k3s, r2, longhorn, synology]
|
||||
---
|
||||
|
||||
@@ -102,10 +102,12 @@ sudo /usr/local/bin/docker run --rm \
|
||||
|
||||
| 이름 | 그룹 | Task | Cron | 보존 | Concurrency |
|
||||
|------|------|------|------|------|-------------|
|
||||
| critical-snapshot | critical | snapshot | `0 * * * *` (매시간) | 24 (1일치) | 2 |
|
||||
| critical-backup | critical | backup | `0 */6 * * *` (6시간마다) | 28 (7일치) | 1 |
|
||||
| standard-snapshot | standard | snapshot | `0 3 * * *` (매일 03:00) | 7 (7일치) | 2 |
|
||||
| standard-backup | standard | backup | `0 4 * * *` (매일 04:00) | 7 (7일치) | 1 |
|
||||
| critical-snapshot | critical | snapshot | `0 * * * *` UTC (매시간) | 24 (1일치) | 2 |
|
||||
| critical-backup | critical | backup | `0 */6 * * *` UTC (6h 간격, KST 03/09/15/21시 포함) | 28 (7일치) | 1 |
|
||||
| standard-snapshot | standard | snapshot | `0 18 * * *` UTC (= KST 03:00) | 7 (7일치) | 2 |
|
||||
| standard-backup | standard | backup | `0 19 * * *` UTC (= KST 04:00) | 7 (7일치) | 1 |
|
||||
|
||||
> cron 은 UTC 기준. standard 그룹은 KST 새벽 트래픽 저점에 실행되도록 설정 (2026-04-15 조정).
|
||||
|
||||
> [!info] 보존 정책 통일 (2026-04-14)
|
||||
> 백업 보존을 일관적으로 **7일 기준**으로 통일. snapshot은 CoW 체인이라 개수보다 보존 기간이 중요 — critical은 1일치 시간 단위, standard는 7일치 일단위로 유지.
|
||||
|
||||
@@ -83,61 +83,98 @@ incus exec postgres-1 -- etcdctl --endpoints=http://192.168.9.100:2379,http://10
|
||||
|
||||
## K3s kine 연결
|
||||
|
||||
K3s → HAProxy(OpenWrt 192.168.9.1:5432) → Patroni Leader PostgreSQL
|
||||
K3s → **pgx multi-host** → Patroni 3노드 직결 (HAProxy 미경유).
|
||||
|
||||
kine 은 `github.com/jackc/pgx/v5` 드라이버 사용 — libpq 호환 multi-host + `target_session_attrs=read-write` 지원. Patroni failover 시 pgx 가 자동으로 새 primary 에 재연결 (API 다운타임 <1초).
|
||||
|
||||
### K3s config
|
||||
|
||||
```yaml
|
||||
# /etc/rancher/k3s/config.yaml (kr1, kr2)
|
||||
datastore-endpoint: "postgres://kine:kine@192.168.9.1:5432/kine"
|
||||
datastore-endpoint: "postgres://kine:kine@10.100.2.5:5432,10.100.3.185:5432,10.100.1.83:5432/kine?target_session_attrs=read-write&sslmode=disable"
|
||||
```
|
||||
|
||||
### HAProxy (OpenWrt)
|
||||
이전 구성 (HAProxy 경유, 2026-04-16 폐기): `postgres://kine:kine@192.168.9.1:5432/kine`
|
||||
|
||||
`/etc/haproxy.cfg`에 PostgreSQL backend 설정. Patroni REST API(`/primary` 엔드포인트)로 Leader를 자동 감지.
|
||||
### 검증 (2026-04-16)
|
||||
|
||||
kr2 → kr1 순서로 rolling restart. switchover (postgres-1→postgres-3, TL12→13) 시 kine API 다운타임 **<1초** (t+2ms 에 정상 응답). [[../history/2026-04-16-kine-multihost-migration|history]]
|
||||
|
||||
### OpenWrt HAProxy :5432 프론트엔드
|
||||
|
||||
kine + pgpool 전환 완료로 HAProxy postgres 프론트엔드는 **더 이상 트래픽 없음**. 1주 관측 후 제거 예정.
|
||||
|
||||
## 애플리케이션 접속 경로 — pgpool-II
|
||||
|
||||
모든 K3s 내부 애플리케이션(NocoDB, n8n, Outline)은 **pgpool-II**를 통해 Patroni 3노드에 직접 접속. HAProxy 미경유.
|
||||
|
||||
```
|
||||
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
|
||||
NocoDB/n8n/Outline → pgpool.db.svc.cluster.local:9999 → Patroni 3노드 직결
|
||||
```
|
||||
|
||||
- Patroni failover 시 HAProxy가 자동으로 새 Leader를 감지 (~3초)
|
||||
- K3s config 변경 없이 Leader 전환 대응
|
||||
이전 pgcat+HAProxy 구조는 2026-04-16 폐기. [[../history/2026-04-16-pgpool-full-migration|history]]
|
||||
|
||||
## 애플리케이션 접속 경로
|
||||
### pgpool 구성
|
||||
|
||||
NocoDB, n8n 등 K3s 내부 애플리케이션은 **pgcat**(연결 풀링)을 통해 PostgreSQL에 접속.
|
||||
- 이미지: `pgpool/pgpool:4.4.3` (공식, DockerHub 최신 태그)
|
||||
- K8s 매니페스트: `kaffa/helm-charts` repo `pgpool/` 디렉토리 (ArgoCD `pgpool` Application, selfHeal+prune)
|
||||
- replicas=2, `podAntiAffinity` (topologyKey `kubernetes.io/hostname`)
|
||||
- `PodDisruptionBudget` `minAvailable: 1`
|
||||
- Service: ClusterIP `pgpool.db.svc.cluster.local:9999`
|
||||
|
||||
### pgpool.conf 핵심
|
||||
|
||||
```
|
||||
nocodb/n8n → pgcat (db.svc.cluster.local:6432) → HAProxy 192.168.9.1:5432 → Patroni Leader
|
||||
backend_clustering_mode = 'streaming_replication'
|
||||
|
||||
backend_hostname0/1/2 = 10.100.2.5 / 10.100.3.185 / 10.100.1.83
|
||||
backend_weight = 1, backend_flag = ALLOW_TO_FAILOVER
|
||||
|
||||
sr_check_user = 'sr_check' (REPLICATION + pg_monitor 역할, pg에 생성 필요)
|
||||
sr_check_period = 10
|
||||
health_check_period = 10
|
||||
|
||||
failover_on_backend_error = off (Patroni가 promotion 수행)
|
||||
failover_command = ''
|
||||
follow_primary_command = ''
|
||||
use_watchdog = off
|
||||
|
||||
load_balance_mode = off (모든 쿼리 primary — read-your-write 일관성)
|
||||
num_init_children = 32
|
||||
max_pool = 4
|
||||
connection_cache = on
|
||||
pool_passwd = '' (미사용 — 아래 인증 참조)
|
||||
```
|
||||
|
||||
`db/pgcat-config` ConfigMap의 각 풀의 `shards.0.servers`는 **HAProxy 단일 백엔드만 가리켜야 함**:
|
||||
### 인증
|
||||
|
||||
```toml
|
||||
[pools.nocodb.shards.0]
|
||||
database = "nocodb"
|
||||
servers = [["192.168.9.1", 5432, "primary"]]
|
||||
Postgres `password_encryption = scram-sha-256` cluster-wide.
|
||||
|
||||
[pools.n8n.shards.0]
|
||||
database = "n8n"
|
||||
servers = [["192.168.9.1", 5432, "primary"]]
|
||||
- `allow_clear_text_frontend_auth = on` + pool_hba method `password` → 클라이언트 plaintext 전송 → pgpool 이 backend scram-sha-256 challenge-response 에 직접 사용
|
||||
- `pool_passwd = ''` — 비활성. pgpool 이 plaintext pool_passwd 엔트리를 자동 md5 해시하여 backend scram 거절되는 문제 회피
|
||||
- K8s Service 내부 트래픽이라 clear-text 는 클러스터 내에서만 노출
|
||||
|
||||
### Patroni TCP keepalive (유지)
|
||||
|
||||
```
|
||||
tcp_keepalives_idle = 60
|
||||
tcp_keepalives_interval = 10
|
||||
tcp_keepalives_count = 3
|
||||
```
|
||||
|
||||
⚠️ **하지 말 것**: pgcat에 Patroni 노드 IP(10.100.2.5/3.185/1.83)를 직접 박지 말 것. Patroni failover가 발생하면 pgcat는 옛 primary를 계속 가리키게 되어 nocodb/n8n이 read-only 에러 발생.
|
||||
pgpool 은 자체 연결 관리가 있어 클라이언트 좀비 문제 없지만, Postgres → pgpool 역방향 dead socket 감지용으로 Patroni 파라미터 유지.
|
||||
|
||||
pgcat는 풀링 전용으로만 쓰고, leader 탐지는 OpenWrt HAProxy에 위임. `query_parser_enabled = false` 설정 (read/write splitting 비활성).
|
||||
### Patroni switchover 통합 테스트 (2026-04-16)
|
||||
|
||||
Patroni failover 인시던트 이력: [[../history/2026-04-08-patroni-failover-incident|2026-04-08 pgcat/nocodb/outline read-only 사고]]
|
||||
3 서비스 전체 pgpool 경유 상태에서 `patronictl switchover --force`:
|
||||
|
||||
- write 복구: **즉시** (t+3ms)
|
||||
- n8n: 3건 transient error · NocoDB: 0건 · Outline: 0건
|
||||
- 전 서비스 HTTP 200 유지
|
||||
|
||||
이전 pgcat 대비: 동일 시나리오에서 n8n 1038건 / NocoDB 13건 / pod restart 필요
|
||||
|
||||
마이그레이션 이력: [[../history/2026-04-16-pgpool-n8n-poc|PoC]] · [[../history/2026-04-16-pgpool-full-migration|전면 전환]]
|
||||
|
||||
## APISIX etcd 사용 현황
|
||||
|
||||
|
||||
@@ -76,7 +76,35 @@ CA 등록 완료 서버:
|
||||
|
||||
## MCP 서버
|
||||
|
||||
vault-mcp-server v0.2.0 (hashicorp/vault-mcp-server:0.2.0 Docker 이미지). K3s vault namespace에 Deployment로 배포. streamable-http 모드, 엔드포인트: https://hcv.inouter.com/mcp. 내부 통신: vault-active.vault.svc.cluster.local:8200. token은 Secret vault-mcp-token에 저장. Claude Code MCP 설정: type http, url https://hcv.inouter.com/mcp. K3s Ingress vault-mcp가 /mcp 경로를 vault-mcp-server Service(8080)로 라우팅. 로컬 바이너리도 /usr/local/bin/vault-mcp-server에 설치됨.
|
||||
### 실 배포 (2026-04-15 정정)
|
||||
|
||||
vault-mcp-server v0.2.0 은 **jp1 Incus `vault` 컨테이너 (10.253.101.58) 단일 인스턴스**. systemd 유닛 `vault-mcp-server.service`로 streamable-http 모드 가동 (`--transport-host=0.0.0.0 --transport-port=8080 --mcp-endpoint=/mcp`). 같은 컨테이너에 HashiCorp Vault 본체(포트 8200)도 동일 프로세스 공간에 존재 → vault 백엔드는 `http://127.0.0.1:8200`.
|
||||
|
||||
> [!warning] 과거 문서 오류 정정 (2026-04-15)
|
||||
> 이전 기록에 "K3s vault namespace Deployment 배포", "vault-active.vault.svc.cluster.local:8200" 이라 적혀 있었으나 실제와 다름. K3s 안에는 vault 파드/Deployment 없음. 상세: `history/2026-04-15-vault-mcp-duplicate-investigation.md`
|
||||
|
||||
### 접근 경로 (3가지, 모두 같은 jp1 프로세스로 수렴)
|
||||
|
||||
```
|
||||
hcv.inouter.com → Traefik@K3s:443 → 10.253.101.58:8200 (Vault UI/API)
|
||||
vault-mcp.inouter.com → Traefik@K3s:443 → 10.253.101.58:8080 (MCP)
|
||||
http://10.253.101.58:8080/mcp (Tailscale 직결, kappa Claude 현행)
|
||||
```
|
||||
|
||||
K3s `tools` 네임스페이스의 `vault-mcp` 는 **Pod 없는 리버스 프록시 파사드**: Service(selector 비움) + 수동 EndpointSlice가 10.253.101.58 로 고정 + IngressRoute 2개(hcv, vault-mcp). ArgoCD 앱 `argocd/vault-mcp`, Helm chart `kaffa/helm-charts charts/app` + `values/vault-mcp.yaml` (deployment 없는 ingress-only 렌더링).
|
||||
|
||||
### 주의
|
||||
|
||||
- **`hcv.inouter.com/mcp` 는 MCP 엔드포인트 아님** — Vault가 /mcp 경로를 UI(/ui/)로 307 리다이렉트. 외부 MCP hostname 필요하면 `vault-mcp.inouter.com/mcp` 사용.
|
||||
- 외부 공개 경로는 BunnyCDN/Cloudflare 비경유 (Traefik wildcard cert 직접 TLS 종단). 내부 LAN/Tailscale 전용.
|
||||
- kappa Claude MCP는 현재 `http://10.253.101.58:8080/mcp` (Tailscale 암호화 의존). 장기적으로 `https://vault-mcp.inouter.com/mcp` 로 이전 검토 가능 (Traefik TLS + wildcard cert 혜택).
|
||||
|
||||
### 재배포 자료
|
||||
|
||||
- Helm chart: `gitea.inouter.com/kaffa/helm-charts.git charts/app`
|
||||
- values: `kaffa/helm-charts values/vault-mcp.yaml`
|
||||
- jp1 컨테이너 내부 바이너리: `/usr/local/bin/vault-mcp-server`
|
||||
- systemd: `/etc/systemd/system/vault-mcp-server.service`
|
||||
|
||||
## 관련 서비스
|
||||
|
||||
|
||||
67
services/n8n.md
Normal file
67
services/n8n.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: n8n
|
||||
updated: 2026-04-16
|
||||
tags: [services, n8n, oidc, gitea]
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
워크플로 자동화. K3s `n8n` 네임스페이스.
|
||||
|
||||
- URL: https://n8n.inouter.com
|
||||
- 이미지: `n8nio/n8n:latest`
|
||||
- DB: `pgpool.db.svc.cluster.local:9999` (Patroni 직결, [[../infra/postgresql-ha|postgresql-ha]] 참조)
|
||||
|
||||
## Gitea OIDC SSO
|
||||
|
||||
[n8n-oidc](https://github.com/cweagans/n8n-oidc) 사용 — n8n external hooks 방식, enterprise 불필요.
|
||||
|
||||
### 구성 요소
|
||||
|
||||
| 리소스 | 내용 |
|
||||
|---|---|
|
||||
| ConfigMap `n8n-oidc-hooks` | `hooks.js` (n8n-oidc 프로젝트 원본) |
|
||||
| Secret `n8n-oidc-secret` | `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET` |
|
||||
| ConfigMap `n8n-app-config` | OIDC 관련 env vars |
|
||||
|
||||
### 환경변수 (`n8n-app-config`)
|
||||
|
||||
```
|
||||
EXTERNAL_HOOK_FILES=/opt/n8n-oidc/hooks.js
|
||||
OIDC_ISSUER_URL=https://gitea.inouter.com
|
||||
OIDC_REDIRECT_URI=https://n8n.inouter.com/auth/oidc/callback
|
||||
OIDC_SCOPES=openid profile email
|
||||
N8N_ADDITIONAL_NON_UI_ROUTES=auth
|
||||
EXTERNAL_FRONTEND_HOOKS_URLS=/assets/oidc-frontend-hook.js
|
||||
```
|
||||
|
||||
### Gitea OAuth2 앱
|
||||
|
||||
- name: `n8n`
|
||||
- redirect URI: `https://n8n.inouter.com/auth/oidc/callback`
|
||||
- confidential client: yes
|
||||
- Gitea admin → Settings → Applications 에서 관리
|
||||
|
||||
### 동작
|
||||
|
||||
1. n8n 로그인 페이지에 "Sign in with SSO" 버튼 표시
|
||||
2. 클릭 → Gitea authorize → 콜백 → JIT user provisioning (첫 유저 = owner)
|
||||
3. SSO 우회: `https://n8n.inouter.com/signin?showLogin=true` 로 로컬 로그인
|
||||
|
||||
### 볼륨 마운트
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- name: oidc-hooks
|
||||
configMap:
|
||||
name: n8n-oidc-hooks
|
||||
volumeMounts:
|
||||
- name: oidc-hooks
|
||||
mountPath: /opt/n8n-oidc/hooks.js
|
||||
subPath: hooks.js
|
||||
readOnly: true
|
||||
```
|
||||
|
||||
## 관련
|
||||
|
||||
- [[../infra/postgresql-ha]] — pgpool-II 접속 경로
|
||||
Reference in New Issue
Block a user