kappa 피드백 + kubectl 실측 기반 정정. 이전 기록의 "SafeLine WAF 전용 리버스 프록시" 또는 "SafeLine WAF 전용" 표현은 오해의 소지가 있음. 실측 사실 (2026-04-10 kubectl get svc + ApisixRoute + HTTPRoute): - APISIX (svc apisix-gateway): MetalLB VIP 192.168.9.50, gateway 80/443 + admin 9180. 독립 LoadBalancer. Deployment replica 2. ApisixRoute 1건: juiceshop/juiceshop → juiceshop.keepanker.cv → juiceshop svc (chaitin-waf plugin 으로 SafeLine 통합 테스트) - Traefik (svc traefik): MetalLB VIP 192.168.9.53, 80/443. HTTPRoute 14건 (argocd/gitea/grafana/n8n/nocodb/sftpgo/openmemory/searxng/ kroki/safeline-mgt/vault-ui + api/namecheap + api/vultr + bunnycdn-mcp) + 5 legacy IngressRoute (vlogs/outline/vault-mcp/vault-mcp-http/bunnycdn-mcp) → **두 gateway 는 동등한 병렬 독립 LoadBalancer**. APISIX 는 Traefik 뒤의 리버스 프록시가 아니라 자체 MetalLB VIP 를 가진 별개 외부 인입 채널. "SafeLine WAF 전용" 이 아니라, 2026-03-25 메인 라우팅이 Traefik 으로 이전된 이후 현재 APISIX route 가 SafeLine 테스트용 1건만 남은 상태일 뿐 — 범용 gateway 로 언제든 새 route 추가 가능. 정정 대상: - infra/apisix.md — 서울 섹션 헤더/용도/축소 문구 - infra/infra-hosts.md — 게이트웨이 한 줄 요약 - infra/k3s-migration.md — 게이트웨이 열 + Phase 0 + Namespace 표 - infra/gateway-api.md — 전환 이력 2026-03-25 줄 - infra/crowdsec-safeline.md — waf-kr BunnyCDN Pull Zone 섹션 머리말 부수적으로 2026-04-10 에 발견된 heimdall kubectl 부재 문제 해결 (kubectl + helm + kubeconfig 복원) + tofu cloud-init 자동화 추가 — commit bd5e4cb (ops-agents-tofu).
5.4 KiB
5.4 KiB
title, updated, tags
| title | updated | tags | |||
|---|---|---|---|---|---|
| K3s Gateway API — Traefik 메인 라우팅 | 2026-03-25 |
|
개요
K3s 메인 라우팅을 Traefik이 담당 (2026-03-25 APISIX에서 전환).
전환 이력
- 2026-03-21: K3s Ingress → Gateway API 전환 (기존 클러스터, Traefik v3.6.9)
- 2026-03-24: 새 클러스터(kr2)에서 APISIX + Ingress Controller 2.0으로 구성
- 2026-03-25: APISIX Ingress Controller의 Gateway API 플러그인 제한으로 메인 HTTP 라우팅을 Traefik 으로 교체
- APISIX 는 여전히 독립 LoadBalancer (MetalLB VIP 192.168.9.50) 로 운영 중, 다만 route 는
juiceshop.keepanker.cv1건만 남아 SafeLine chaitin-waf 플러그인 통합 테스트 용도. Traefik 과 동등한 병렬 gateway 로 언제든 새 route 추가 가능.
- APISIX 는 여전히 독립 LoadBalancer (MetalLB VIP 192.168.9.50) 로 운영 중, 다만 route 는
Traefik 배포 (새 클러스터)
- DaemonSet (kube-system 네임스페이스)
- LoadBalancer 192.168.9.53 (MetalLB, 이전 hostPort 80/443에서 전환)
- Gateway API provider 활성화
- TLSStore CRD로 와일드카드 인증서 기본 로드
- 와일드카드 인증서: *.inouter.com, *.inouter.com, *.actions.it.com, *.api.inouter.com, *.mcp.inouter.com
Gateway
- GatewayClass:
traefik(traefik.io/gateway-controller) - Gateway:
traefik-gateway(kube-system) - Listeners: web (HTTP 80) + websecure (HTTPS 443)
- TLS: TLSStore로 기본 인증서, Gateway listener에서 추가 인증서 참조
- ReferenceGrant: cert-manager → kube-system (Secret 참조 허용)
서비스 상태 (2026-03-25 전환 완료)
| 서비스 | 도메인 | 상태 |
|---|---|---|
| NocoDB | nocodb.inouter.com | 200 ✅ |
| Gitea | gitea.inouter.com | 200 ✅ |
| n8n | n8n.inouter.com | 200 ✅ |
| ArgoCD | argocd.inouter.com | 200 ✅ |
| Grafana | grafana.inouter.com | 302 ✅ |
| SearXNG | searxng.inouter.com | 200 ✅ |
| SafeLine | safeline.inouter.com | 200 ✅ |
| Namecheap API | namecheap.api.inouter.com | 403 ✅ |
| Vultr API | vultr.api.inouter.com | 403 ✅ |
| OpenMemory | mem0.inouter.com | MCP 서버 (웹 응답 없음) |
| BunnyCDN MCP | bunny.inouter.com | MCP 서버 (웹 응답 없음) |
| Gitea Runner | declare successfully ✅ | Tailscale 직접 접속, 와일드카드 인증서 정상 |
HTTPRoute 목록
| Namespace | Name | Hosts | Port |
|---|---|---|---|
| anvil | nginx-anvil | anvil.local, gnu.inouter.com | 80 |
| argocd | argocd-server | argocd.inouter.com | 80 (insecure 모드) |
| ironclad | nginx-ironclad | ironclad.local | 80 |
| openmemory | openmemory-mcp | mem0.inouter.com | 8765 |
| searxng | searxng | searxng.inouter.com | 8080 |
| tools | cloud-api-emulator | emul.actions.it.com | 3000 |
| tools | cloud-api-linode | linode.actions.it.com | 3001 |
| tools | cloud-api-vultr | vultr.actions.it.com | 3002 |
| tools | n8n | n8n.inouter.com | 5678 |
| tools | namecheap-api | namecheap.api.inouter.com | 80 |
| tools | nocodb | nocodb.inouter.com | 8080 |
| tools | vultr-api | vultr.api.inouter.com | 80 |
| vault | vault-mcp | hcv.inouter.com (/mcp) | 8080 |
| vault | vault-ui | hcv.inouter.com (/) | 8200 |
ArgoCD 변경사항
argocd-server를 insecure 모드로 변경 (configmap argocd-cmd-params-cm에 server.insecure: "true"). TLS 종료를 Gateway에서 처리.
클러스터 내부 DNS (헤어핀 방지)
Pod에서 외부 도메인(gitea.inouter.com 등)에 접근할 때 트래픽이 외부로 나갔다 돌아오는 헤어핀 NAT 문제를 방지하기 위해, CoreDNS rewrite로 서비스 도메인을 Traefik ClusterIP로 직접 해석.
설정
ConfigMap coredns-custom (kube-system)의 hairpin.override:
rewrite name gitea.inouter.com traefik.kube-system.svc.cluster.local
rewrite name argocd.inouter.com traefik.kube-system.svc.cluster.local
rewrite name searxng.inouter.com traefik.kube-system.svc.cluster.local
rewrite name mem0.inouter.com traefik.kube-system.svc.cluster.local
rewrite name nocodb.inouter.com traefik.kube-system.svc.cluster.local
rewrite name n8n.inouter.com traefik.kube-system.svc.cluster.local
rewrite name hcv.inouter.com traefik.kube-system.svc.cluster.local
...
동작
- Pod이
gitea.inouter.comDNS 조회 - CoreDNS가
traefik.kube-system.svc.cluster.local로 rewrite - Traefik ClusterIP 반환 → 클러스터 내부에서 처리
- Traefik이 HTTPRoute 호스트 매칭으로 백엔드 라우팅
이전 방식과 차이
| 방식 | 장점 | 단점 |
|---|---|---|
| NodeHosts (IP 직접 등록) | 단순 | ClusterIP 변경 시 수동 갱신 필요, stale 엔트리 위험 |
| rewrite (현재) | ClusterIP 자동 추종 | HTTPRoute 추가 시 rewrite 규칙도 추가 필요 |
장애 사례 (2026-03-22)
NodeHosts에 gitea.inouter.com → 10.43.205.207(stale ClusterIP)이 남아있어서 ArgoCD 전체가 Gitea 싱크 실패(Unknown 상태). CoreDNS rewrite 방식으로 교체하여 해결.
유지보수
새 HTTPRoute 추가 시 coredns-custom ConfigMap에 rewrite 규칙 추가 후 CoreDNS 재시작:
kubectl edit configmap coredns-custom -n kube-system
kubectl rollout restart deployment coredns -n kube-system
주의사항
- Gateway/GatewayClass를 수동 생성하면 Helm upgrade 실패 (ownership metadata 충돌)
- HelmChartConfig로만 설정할 것
namespacePolicy.from: All필수 (기본값은 Same)- ArgoCD가 관리하는 Ingress를 삭제하면 재생성될 수 있으니 Application 확인 필요
- HTTPRoute 추가 시
coredns-customhairpin rewrite도 함께 추가할 것