infra/apisix: K3s 내부 etcd 복귀 + destructive sync 가이드 + CRD 전환 기록
apisix.md: - 서울 APISIX etcd: 외부 통합 → K3s 내부 apisix-etcd StatefulSet (2026-04-08) - routes/ssls는 ApisixRoute/ApisixTls CRD로 전환 (etcd 직접 PUT 금지) - destructive sync 동작과 객체별 관리 방법 정리 - helm values nesting 버그 회귀 방지 노트 - plugin_metadata, global_rules는 GatewayProxy CR로 관리 - ApisixRoute 예시 추가 postgresql-ha.md: - APISIX 서울이 외부 통합 etcd 사용 안 함을 반영 - 통합 etcd는 Patroni DCS + osaka APISIX 전용 - /apisix/seoul stale prefix 삭제 절차 추가
This commit is contained in:
@@ -52,31 +52,32 @@ 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 (id=1): `http-logger` (CrowdSec 로그 전송) + `limit-req` (rate 20, burst 10). **`chaitin-waf`는 global_rules에 없음** — 라우트별 적용 (2026-03-15 git push 500 사건 이후)
|
||||
- global_rules: `http-logger` (CrowdSec 로그 전송) + `limit-req` (rate 20, burst 10). **`chaitin-waf`는 global_rule에 없음** — 라우트별 적용 (2026-03-15 git push 500 사건 이후). 두 global_rule 모두 GatewayProxy CR(`spec.plugins`)로 선언되어 ingress controller가 관리.
|
||||
- 서비스: apisix-gateway LoadBalancer 192.168.9.50 (80→9080, 443→9443)
|
||||
- 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`)
|
||||
- etcd: **K3s 내부 apisix-etcd StatefulSet 3 replicas** (Bitnami etcd 차트, Longhorn PVC 5Gi × 3), prefix `/apisix`. ClusterIP `apisix-etcd.apisix.svc.cluster.local:2379`. 외부 통합 etcd로 잠시 이전했다가(2026-04-06) Patroni와의 장애 격리 + 네트워크 단순화를 위해 K3s 내부로 복귀(2026-04-08).
|
||||
- Admin API: `apisix-admin` ClusterIP :9180 (`adminKey: edd1c9f034335f136f87ad84b625c8f1`). admin allow IPs: `127.0.0.1/24`, `10.42.0.0/16`(pod), `10.43.0.0/16`(svc), `192.168.9.0/24`(LAN), `100.64.0.0/10`(Tailscale)
|
||||
- HAProxy: OpenWrt에서 :9080→192.168.9.50:80, :9443→192.168.9.50:443 (MetalLB)
|
||||
- 2026-03-25 메인 라우팅 역할을 Traefik으로 이전, APISIX는 SafeLine WAF 전용으로 축소
|
||||
- 2026-04-08 ApisixRoute CRD 사용을 위해 ingress controller 복구
|
||||
- 2026-04-08 ApisixRoute CRD 사용을 위해 ingress controller 복구 + K3s 내부 etcd 복귀
|
||||
|
||||
#### plugin_metadata (etcd 직접 등록)
|
||||
#### plugin_metadata (GatewayProxy CR로 관리)
|
||||
|
||||
chaitin-waf 플러그인은 `plugin_attr`(config.yaml)이 아닌 **`plugin_metadata`(etcd)**에서 detector 노드를 읽음. 반드시 etcd에 등록해야 함.
|
||||
chaitin-waf 플러그인은 `plugin_attr`(config.yaml)이 아닌 **`plugin_metadata`(etcd)**에서 detector 노드를 읽음. 옛날에는 etcd에 직접 PUT했으나, 2026-04-08부터 ingress controller가 destructive sync로 미관리 객체를 1분마다 삭제하므로 **반드시 GatewayProxy CR의 `spec.pluginMetadata`로 선언**해야 함. helm values의 `gatewayProxy.pluginMetadata` 항목 참고.
|
||||
|
||||
```
|
||||
etcdctl put /apisix/plugin_metadata/chaitin-waf '{"id":"chaitin-waf","nodes":[{"host":"10.43.253.244","port":8000}],"config":{"connect_timeout":1000,"send_timeout":1000,"read_timeout":1000,"req_body_size":1024,"real_client_ip":true}}'
|
||||
```
|
||||
#### 등록된 라우트 / TLS (ApisixRoute / ApisixTls CRD)
|
||||
|
||||
#### 등록된 라우트 (etcd 직접 등록)
|
||||
모든 라우트와 SSL은 K8s CRD로 선언됨. ingress controller가 watch하여 APISIX admin API로 push.
|
||||
|
||||
| Route ID | 호스트 | upstream | chaitin-waf | 비고 |
|
||||
|----------|--------|----------|-------------|------|
|
||||
| juiceshop | juiceshop.keepanker.cv | juiceshop:3000 (juiceshop ns) | block | WAF 테스트용 OWASP Juice Shop |
|
||||
| Kind | Name | Namespace | 설명 |
|
||||
|------|------|-----------|------|
|
||||
| ApisixRoute | juiceshop | juiceshop | `juiceshop.keepanker.cv` → juiceshop:3000, plugins.chaitin-waf (block) |
|
||||
| ApisixTls | wildcard-keepanker-cv | apisix | `*.keepanker.cv` + `keepanker.cv`, secret `wildcard-keepanker-cv-tls` (cert-manager 발급) |
|
||||
|
||||
#### real_ip 설정 (ConfigMap 직접 수정)
|
||||
⚠️ **etcd 직접 등록 금지** (1분 이내 controller가 삭제). 모든 신규 객체는 CRD로 선언해야 함.
|
||||
|
||||
`real_ip_header: X-Forwarded-For`, `real_ip_from: 0.0.0.0/0` (BunnyCDN 경유이므로 전체 허용). Helm values로는 반영 안 되어 ConfigMap 직접 패치.
|
||||
#### real_ip 설정
|
||||
|
||||
helm values `apisix.nginx.http.realIpFrom` / `realIpHeader`로 관리. 차트 정상 반영됨.
|
||||
|
||||
#### 이전 사유 (2026-03-25)
|
||||
- Ingress Controller 2.0 초기 시도에서 GatewayProxy 모드 + ApisixRoute CRD 연동 실패 (당시 helm values에 v1.x 형식의 `config.apisix.serviceName` 사용 → 차트 1.x 스키마와 불일치)
|
||||
@@ -137,6 +138,48 @@ spec:
|
||||
|
||||
WAF가 문제 시 `plugins` 항목만 빼면 즉시 비활성화됨.
|
||||
|
||||
#### Destructive sync 주의사항 (v2.x controller)
|
||||
|
||||
새 controller는 **CRD/GatewayProxy로 선언되지 않은 모든 APISIX 객체를 1분마다 자동 삭제**함. 영향:
|
||||
|
||||
| 객체 | 관리 방법 |
|
||||
|------|----------|
|
||||
| routes | `ApisixRoute` CRD (또는 HTTPRoute) |
|
||||
| upstreams | `ApisixUpstream` CRD |
|
||||
| ssls | `ApisixTls` CRD |
|
||||
| consumers | `ApisixConsumer` CRD |
|
||||
| plugin_metadata | `GatewayProxy.spec.pluginMetadata` (helm values) |
|
||||
| global_rules | `GatewayProxy.spec.plugins` (helm values) |
|
||||
|
||||
⚠️ **etcd 직접 PUT은 임시 디버깅 외에는 금지.** 1분 안에 삭제됨. 옛 운영 메모에 있는 `etcdctl put` 예제는 모두 deprecated.
|
||||
|
||||
#### K3s 내부 etcd 복귀 (2026-04-08)
|
||||
|
||||
기존: 외부 통합 etcd 클러스터(192.168.9.100/10.100.2.214/10.253.101.233, prefix `/apisix/seoul`) — Patroni DCS와 etcd 공유.
|
||||
|
||||
복귀 후: K3s 내부 `apisix-etcd` StatefulSet 3 replicas (Bitnami etcd, Longhorn PVC 5Gi × 3, ClusterIP `apisix-etcd.apisix.svc:2379`, prefix `/apisix`).
|
||||
|
||||
이유:
|
||||
- **장애 격리**: Patroni 이슈가 APISIX 라우팅에 영향 주지 않게
|
||||
- **네트워크 단순화**: K3s 내부 통신만으로 충분
|
||||
- **운영 일관성**: helm 한 곳에서 etcd + apisix + ingress controller 관리
|
||||
|
||||
helm values 핵심:
|
||||
```yaml
|
||||
etcd:
|
||||
enabled: true
|
||||
replicaCount: 3
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 5Gi
|
||||
```
|
||||
|
||||
업그레이드 시 주의:
|
||||
- Bitnami etcd 차트의 pre-upgrade hook은 기존 etcd 멤버 list를 시도함. 멤버가 없는 상황에서는 무한 retry 실패 → `helm upgrade --no-hooks` 사용 또는 helm rollback 후 재시도
|
||||
- helm upgrade 전 release values nesting 점검 필수: `apisix.admin.allow.ipList`(O) vs `admin.allow.ipList`(X), `apisix.nginx.http.realIpFrom`(O) vs `nginx.http.realIpFrom`(X), `service.http.containerPort`(O) vs `gateway.http.containerPort`(X). 잘못된 nesting은 차트가 조용히 무시함.
|
||||
- 이전 후 ingress controller는 자동으로 모든 K8s CRD 객체를 새 etcd에 재push (rollout restart로 즉시 동기화 가능)
|
||||
- 외부 통합 etcd의 stale `/apisix/seoul/*` 키는 수동 삭제 (postgresql-ha.md의 etcd cleanup 명령 참고)
|
||||
|
||||
### BunnyCDN Pull Zone 매핑
|
||||
|
||||
| Zone | ID | Origin | 방향 | 주요 Hostnames |
|
||||
|
||||
@@ -140,18 +140,29 @@ pgcat는 풀링 전용으로만 쓰고, leader 탐지는 OpenWrt HAProxy에 위
|
||||
|
||||
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)
|
||||
## APISIX etcd 사용 현황
|
||||
|
||||
기존 각 사이트별 독립 etcd를 통합 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 내부로 복귀 |
|
||||
|
||||
| 사이트 | 기존 etcd | 이전 후 | prefix |
|
||||
|--------|----------|---------|--------|
|
||||
| osaka | Docker waf-etcd (로컬) | 통합 클러스터 (192.168.9.100) | `/apisix/osaka` |
|
||||
| sandbox-tokyo | Docker apisix-etcd (로컬) | 통합 클러스터 (10.253.101.233) | `/apisix/tokyo` (2026-04-08 NixOS 전환으로 sandbox-tokyo APISIX 자체가 미가동) |
|
||||
| 서울 K3s | StatefulSet 3노드 (K3s 내부) | 통합 클러스터 (192.168.9.100) | `/apisix/seoul` |
|
||||
### 2026-04-06 → 2026-04-08 변경 이력
|
||||
|
||||
- 데이터 이전: `etcdctl make-mirror --prefix /apisix/ --dest-prefix /apisix-{site}/`
|
||||
- K3s 내 apisix-etcd StatefulSet + PVC 삭제 완료
|
||||
1. **2026-04-06**: 서울 K3s APISIX의 K3s 내부 apisix-etcd StatefulSet을 삭제하고 외부 통합 etcd로 이전 (`/apisix/seoul` prefix). 통합 운영 + 컴포넌트 수 절감 의도.
|
||||
2. **2026-04-08**: 다시 K3s 내부로 복귀. Patroni DCS와 같은 etcd 클러스터를 공유할 때 장애 전파 위험(Patroni 이슈 → APISIX 라우팅 영향)이 비직관적이라 격리. 외부 통합 etcd의 `/apisix/seoul/*` 20개 키 삭제 완료. **현재 외부 통합 etcd는 Patroni DCS + osaka APISIX 전용.**
|
||||
|
||||
### Stale prefix 삭제 명령 (참고)
|
||||
|
||||
```bash
|
||||
# HTTP API v3 사용 (heimdall에서 직접 호출)
|
||||
KEY=$(echo -n "/apisix/seoul/" | base64)
|
||||
RANGE_END=$(echo -n "/apisix/seoul0" | base64)
|
||||
curl -s -X POST "http://192.168.9.100:2379/v3/kv/deleterange" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"key\":\"$KEY\",\"range_end\":\"$RANGE_END\"}"
|
||||
```
|
||||
|
||||
## 관련 문서
|
||||
|
||||
|
||||
Reference in New Issue
Block a user