--- title: K3s Gateway API 마이그레이션 updated: 2026-03-22 tags: [k3s, traefik, gateway-api] --- ## 개요 K3s Ingress → Gateway API 전환 완료 (2026-03-21). Traefik v3.6.9의 Gateway API provider 사용. ## Traefik 설정 HelmChartConfig로 Gateway API provider 활성화: ```yaml providers: kubernetesGateway: enabled: true gateway: listeners: web: namespacePolicy: from: All websecure: port: 8443 protocol: HTTPS certificateRefs: - name: wildcard-inouter-com-tls namespace: cert-manager namespacePolicy: from: All ``` ## Gateway - GatewayClass: `traefik` (traefik.io/gateway-controller) - Gateway: `traefik-gateway` (kube-system) - Listeners: web (HTTP 8000) + websecure (HTTPS 8443) - TLS: cert-manager의 wildcard-inouter-com-tls 참조 - ReferenceGrant: cert-manager → kube-system (Secret 참조 허용) ## HTTPRoute 목록 | Namespace | Name | Hosts | Port | |-----------|------|-------|------| | anvil | nginx-anvil | anvil.local, gnu.anvil.it.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.anvil.it.com | 80 | | tools | nocodb | nocodb.inouter.com | 8080 | | tools | vultr-api | vultr-api.anvil.it.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.anvil.it.com` 등)에 접근할 때 트래픽이 외부로 나갔다 돌아오는 헤어핀 NAT 문제를 방지하기 위해, CoreDNS rewrite로 서비스 도메인을 Traefik ClusterIP로 직접 해석. ### 설정 ConfigMap `coredns-custom` (kube-system)의 `hairpin.override`: ``` rewrite name gitea.anvil.it.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 ... ``` ### 동작 1. Pod이 `gitea.anvil.it.com` DNS 조회 2. CoreDNS가 `traefik.kube-system.svc.cluster.local`로 rewrite 3. Traefik ClusterIP 반환 → 클러스터 내부에서 처리 4. Traefik이 HTTPRoute 호스트 매칭으로 백엔드 라우팅 ### 이전 방식과 차이 | 방식 | 장점 | 단점 | |------|------|------| | NodeHosts (IP 직접 등록) | 단순 | ClusterIP 변경 시 수동 갱신 필요, stale 엔트리 위험 | | **rewrite (현재)** | ClusterIP 자동 추종 | HTTPRoute 추가 시 rewrite 규칙도 추가 필요 | ### 장애 사례 (2026-03-22) NodeHosts에 `gitea.anvil.it.com → 10.43.205.207`(stale ClusterIP)이 남아있어서 ArgoCD 전체가 Gitea 싱크 실패(Unknown 상태). CoreDNS rewrite 방식으로 교체하여 해결. ### 유지보수 새 HTTPRoute 추가 시 `coredns-custom` ConfigMap에 rewrite 규칙 추가 후 CoreDNS 재시작: ```bash 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-custom` hairpin rewrite도 함께 추가할 것