infra: APISIX ingress controller 복구 및 PostgreSQL HA 구조 명확화

- apisix.md: ingress controller 2026-04-08 복구, GatewayProxy + ApisixRoute CRD 호환 검증, 옛 helm values 문제 정정, ApisixRoute 예시 추가
- apisix.md: 외부 통합 etcd 클러스터 사용 명시 (K3s 내부 StatefulSet 아님), global_rules는 chaitin-waf 미포함 (라우트별 적용)
- postgresql-ha.md: pgcat가 HAProxy 단일 백엔드 경유로 변경 (2026-04-08 사고 기록), Patroni 노드 IP 직접 박지 말 것 경고
- gitea.md: 컨테이너 레지스트리 섹션 추가, gitea-registry secret 네임스페이스별 수동 복사 필요 명시
This commit is contained in:
Heimdall
2026-04-08 08:34:07 +00:00
parent ddf403ef99
commit ac81018695
3 changed files with 104 additions and 6 deletions

View File

@@ -52,13 +52,13 @@ BunnyCDN(inouter, ID 5316471) → apisix-osaka(172.233.93.180) → 백엔드
- 배포: K3s apisix 네임스페이스, **Deployment replica 2** (2026-04-04 HA 업그레이드)
- APISIX: 3.15.0-ubuntu
- SafeLine WAF 연동: `plugin_attr.chaitin-waf``safeline-detector:8000` (10.43.253.244)
- global_rules: `chaitin-waf` (mode: block) + `limit-req` (rate 20, burst 10)
- global_rules (id=1): `http-logger` (CrowdSec 로그 전송) + `limit-req` (rate 20, burst 10). **`chaitin-waf`는 global_rules에 없음** — 라우트별 적용 (2026-03-15 git push 500 사건 이후)
- 서비스: apisix-gateway LoadBalancer 192.168.9.50 (80→9080, 443→9443)
- etcd: apisix-etcd StatefulSet **3 replicas** (K3s 내부, 2026-04-04 HA 업그레이드)
- Admin API: `apisix-admin` ClusterIP :9180 (라우트/upstream/SSL 수동 관리)
- etcd: **외부 통합 etcd 클러스터** (192.168.9.100, 10.100.2.214, 10.253.101.233), prefix `/apisix/seoul`. K3s 내부 apisix-etcd StatefulSet은 통합 이전 시 삭제됨 (2026-04-06). 자세한 내용은 [[postgresql-ha#etcd-클러스터-patroni-dcs|postgresql-ha]] 참고
- Admin API: `apisix-admin` ClusterIP :9180 (`adminKey: edd1c9f034335f136f87ad84b625c8f1`)
- HAProxy: OpenWrt에서 :9080→192.168.9.50:80, :9443→192.168.9.50:443 (MetalLB)
- 2026-03-25 메인 라우팅 역할을 Traefik으로 이전, APISIX는 SafeLine WAF 전용으로 축소
- Ingress Controller + Gateway API CRD 제거됨 (GatewayProxy 모드에서 ApisixRoute CRD 미지원, HTTPRoute에 플러그인 개별 적용 불가 문제)
- 2026-04-08 ApisixRoute CRD 사용을 위해 ingress controller 복구
#### plugin_metadata (etcd 직접 등록)
@@ -79,11 +79,64 @@ etcdctl put /apisix/plugin_metadata/chaitin-waf '{"id":"chaitin-waf","nodes":[{"
`real_ip_header: X-Forwarded-For`, `real_ip_from: 0.0.0.0/0` (BunnyCDN 경유이므로 전체 허용). Helm values로는 반영 안 되어 ConfigMap 직접 패치.
#### 이전 사유 (2026-03-25)
- Ingress Controller 2.0 GatewayProxy 모드 ApisixRoute CRD를 sync하지 않음
- Gateway API HTTPRoute에 플러그인 개별 적용 방법이 없음
- Ingress Controller 2.0 초기 시도에서 GatewayProxy 모드 + ApisixRoute CRD 연동 실패 (당시 helm values에 v1.x 형식의 `config.apisix.serviceName` 사용 → 차트 1.x 스키마와 불일치)
- Gateway API HTTPRoute에 플러그인 개별 적용 방법이 없음 → ApisixRoute CRD 필요
- global_rules를 Ingress Controller가 덮어쓰려는 충돌 발생
- → Traefik으로 메인 라우팅 교체, APISIX는 SafeLine WAF 연동 전용으로 유지
#### Ingress Controller 복구 (2026-04-08)
`apisix-ingress-controller` Helm release는 살아있었으나 Deployment가 수동 삭제된 상태였음. helm values를 chart 1.1.2 (controller v2.0.1) 스키마에 맞게 재작성 후 `helm upgrade`로 복구.
값 수정 핵심:
```yaml
gatewayProxy:
createDefault: true # GatewayProxy CR 자동 생성
provider:
type: ControlPlane
controlPlane:
service:
name: apisix-admin
port: 9180
auth:
type: AdminKey
adminKey:
value: "edd1c9f034335f136f87ad84b625c8f1"
config:
disableGatewayAPI: false # Gateway API + ApisixRoute 양쪽 다 지원
kubernetes:
ingressClass: apisix
```
검증 결과: GatewayProxy 모드에서도 ApisixRoute CRD(v2)는 정상 동작함. 옛 메모의 "GatewayProxy 모드에서 ApisixRoute CRD 미지원"은 틀렸음 — 잘못된 helm values 때문이었음. ApisixRoute에 `ingressClassName: apisix`만 명시하면 controller가 자동으로 admin API에 push.
ApisixRoute 예시 (라우트별 chaitin-waf):
```yaml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: <name>
namespace: <ns>
spec:
ingressClassName: apisix
http:
- name: rule1
match:
hosts: [<host>]
paths: ["/*"]
backends:
- serviceName: <svc>
servicePort: <port>
plugins:
- name: chaitin-waf
enable: true
config:
mode: block
append_waf_resp_header: true
```
WAF가 문제 시 `plugins` 항목만 빼면 즉시 비활성화됨.
### BunnyCDN Pull Zone 매핑
| Zone | ID | Origin | 방향 | 주요 Hostnames |

View File

@@ -112,6 +112,34 @@ backend bk_postgres_primary
- 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 단일 백엔드만 가리켜야 함** (2026-04-08 변경):
```toml
[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 비활성).
### 2026-04-08 사고 기록
Patroni failover 발생 → pgcat가 옛 primary IP(`10.100.2.5`)를 hardcoded 참조 → nocodb 마이그레이션 시 `cannot execute UPDATE in a read-only transaction` 에러로 4시간 가량 CrashLoopBackOff. n8n은 마이그레이션이 없어서 표면화되지는 않았으나 동일한 잠재 문제 존재. 위의 단일 백엔드 구조로 변경하여 항구 해결.
## APISIX etcd 통합 (2026-04-06)
기존 각 사이트별 독립 etcd를 통합 etcd 클러스터로 이전.

View File

@@ -51,6 +51,23 @@ R2에 저장되는 데이터: packages, lfs, attachments, avatars, repo-avatars,
Gitea는 iron-kr에서 **iron-git** (ID 5584382)으로 분리. 이유: iron-kr의 `BlockNoneReferrer: true`가 git 클라이언트(Referrer 없음)를 차단하여 git push/pull 403 에러 발생. iron-git은 `BlockNoneReferrer: false`로 설정.
## 컨테이너 레지스트리
Gitea에 내장된 OCI 컨테이너 레지스트리. URL: `gitea.inouter.com`. K3s에서 이미지를 pull하려면 각 네임스페이스에 `gitea-registry` imagePullSecret이 필요.
```bash
# 네임스페이스에 gitea-registry secret 복사 (mcp 네임스페이스에서)
kubectl get secret gitea-registry -n mcp -o yaml | \
sed 's/namespace: mcp/namespace: <대상-ns>/' | \
kubectl apply -f -
```
⚠️ **흔한 사고**: 새 네임스페이스에서 `gitea.inouter.com/...` 이미지로 Deployment를 만들면 `imagePullSecrets: [gitea-registry]`만 명시해도 secret이 그 네임스페이스에 없으면 ImagePullBackOff가 발생. K8s는 namespace 경계를 넘어 secret을 공유하지 않음. 매번 secret을 복사해야 함.
자동 배포 대안: cert-manager `reflector` annotation 또는 Kyverno `generate` 정책으로 자동 동기화 가능 (현재는 수동).
기존에 `gitea-registry` secret이 배포된 네임스페이스: `mcp`, `tools`, `api`, `default` (2026-04-08 추가).
## Act Runner
Gitea Act Runner는 [[infra-hosts|incus-jp1]]의 gitea-runner 컨테이너에서 실행 (act_runner daemon, systemd 서비스).