obsidian: 정본 문서에서 히스토리/인시던트 분리 완료

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>
This commit is contained in:
kappa
2026-04-10 12:09:21 +09:00
parent 72750cfc9d
commit 2356b86d36
27 changed files with 554 additions and 514 deletions

View File

@@ -56,25 +56,9 @@ Outline MCP 서버 도입 시 헤임달이 직접 문서 CRUD 가능.
- heimdall `~/.claude.json` `/root` 프로젝트 mcpServers에 `outline` 항목 추가 (stdio, `uvx mcp-outline`, `OUTLINE_API_KEY`는 Vault `secret/apps/outline` brokkr-api-key, `OUTLINE_API_URL=https://outline.inouter.com`)
- 새 컬렉션 `agent-qna` (id `c3ab34ab-fae4-4642-8f4e-12728e293e1b`) — 에이전트 간 장문 Q&A 교환 공간 (kappa↔heimdall이 tmux로 짧게 질문 → 답변은 여기에 작성)
## 2026-04-08 사고: DATABASE_URL이 Patroni replica 직결
DB endpoint는 OpenWrt HAProxy(`192.168.9.1:5432`) 경유. 과거 Patroni failover 사고 이력: [[../history/2026-04-08-patroni-failover-incident|history]]
`outline-secrets` Secret의 `DATABASE_URL`이 Patroni 노드 IP `10.100.2.5`(postgres-1)를 직접 가리키도록 설정되어 있었음. Patroni failover로 postgres-1이 replica로 강등되자 Outline의 모든 write 쿼리가 `cannot execute UPDATE in a read-only transaction` 에러로 실패. API는 500을 반환(`apiKeys.lastActiveAt` UPDATE 실패 → 인증 자체가 깨짐).
**복구**: `DATABASE_URL`을 OpenWrt HAProxy 경유로 변경.
```bash
kubectl patch secret outline-secrets -n outline --type=json \
-p='[{"op":"replace","path":"/data/DATABASE_URL","value":"<base64 of postgresql://outline:outline@192.168.9.1:5432/outline>"}]'
kubectl rollout restart deployment/outline -n outline
# RWO PVC 때문에 old pod를 수동 삭제해야 새 pod attach 가능
kubectl delete pod -n outline <old-pod>
```
**원인**: 이 Secret은 nocodb/n8n/pgcat 변경(2026-04-08 [[postgresql-ha#2026-04-08 사고 기록]])과 함께 일괄 마이그레이션되지 않았음. **나머지 Patroni 사용자도 동일 검증 필요**`kubectl get secret -A -o json | jq -r '.items[] | select(.data.DATABASE_URL) | "\(.metadata.namespace)/\(.metadata.name)"'`로 검수 권장.
**교훈**: Patroni 사용 애플리케이션의 DB endpoint는 항상 OpenWrt HAProxy(`192.168.9.1:5432`) 또는 pgcat(`db.svc.cluster.local:6432`)을 통해야 한다. 노드 IP 직접 박지 말 것.
## Discord 통지 파이프라인 (2026-04-08 구축)
## Discord 통지 파이프라인
`agent-qna` 컬렉션에 새 문서가 만들어지면 heimdall Discord 채널(#heimdall, id `1488119168145555486`)에 자동 알림이 뜬다. 다른 컬렉션은 무시한다.
@@ -134,7 +118,7 @@ Outline (documents.create webhook)
- 필터를 통과해야 하는데 0 items면 payload.event 또는 payload.model.collectionId 구조 확인
3. **n8n DB connection timeout**
- n8n pod 재시작: `kubectl -n n8n delete pod -l app.kubernetes.io/name=n8n`
- pgcat → 192.168.9.1:5432 (Patroni leader) 경로 확인. 2026-04-08에 stale connection으로 15h 멈춰있던 사례 있음
- pgcat → 192.168.9.1:5432 (Patroni leader) 경로 확인
4. **Discord 401/403**
- bot token 재발급 필요 (`secret/apps/discord` 갱신, n8n Code 노드의 하드코딩도 함께 갱신)
- bot이 채널에 access 권한 있는지: `GET /channels/{channel_id}` 200이면 OK