K8s Gateway API HTTPRoute란?
Kubernetes Gateway API는 Ingress의 후속 표준으로, HTTPRoute는 HTTP 트래픽 라우팅 규칙을 정의하는 핵심 리소스입니다. Ingress에서 어노테이션으로 처리하던 트래픽 분할, 헤더 기반 라우팅, URL 재작성 등을 표준 스펙으로 선언적 관리할 수 있습니다. Gateway API 1.0이 2023년 GA되었으며, Istio, Envoy, Cilium, NGINX 등 주요 구현체가 지원합니다.
Gateway + HTTPRoute 기본 구조
# 1. GatewayClass: 구현체 선택 (클러스터 관리자)
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: istio
spec:
controllerName: istio.io/gateway-controller
---
# 2. Gateway: 리스너 정의 (인프라 팀)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: api-gateway
namespace: infra
spec:
gatewayClassName: istio
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: api-tls-cert
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: "true" # 허용된 네임스페이스만
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same # 같은 네임스페이스만
---
# 3. HTTPRoute: 라우팅 규칙 (개발팀)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-routes
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
sectionName: https # 특정 리스너에 바인딩
hostnames:
- "api.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api/v1
backendRefs:
- name: api-v1-service
port: 8080
경로 매칭: PathPrefix · Exact · RegularExpression
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: path-routing
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
hostnames:
- "api.example.com"
rules:
# Exact: 정확한 경로 매칭
- matches:
- path:
type: Exact
value: /healthz
backendRefs:
- name: health-service
port: 8080
# PathPrefix: 접두어 매칭
- matches:
- path:
type: PathPrefix
value: /api/v2/orders
backendRefs:
- name: order-service-v2
port: 8080
- matches:
- path:
type: PathPrefix
value: /api/v2/users
backendRefs:
- name: user-service
port: 8080
# RegularExpression: 정규식 매칭 (구현체 지원 필요)
- matches:
- path:
type: RegularExpression
value: "/api/v[0-9]+/products"
backendRefs:
- name: product-service
port: 8080
헤더·쿼리 기반 라우팅
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-routing
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
hostnames:
- "api.example.com"
rules:
# 헤더 기반 라우팅: 모바일 전용 백엔드
- matches:
- headers:
- name: X-Client-Type
value: mobile
path:
type: PathPrefix
value: /api
backendRefs:
- name: mobile-api-service
port: 8080
# 헤더 기반: A/B 테스트 그룹
- matches:
- headers:
- name: X-Experiment-Group
value: beta
type: Exact
path:
type: PathPrefix
value: /api
backendRefs:
- name: beta-api-service
port: 8080
# 쿼리 파라미터 기반 (구현체 지원 필요)
- matches:
- queryParams:
- name: version
value: canary
type: Exact
path:
type: PathPrefix
value: /api
backendRefs:
- name: canary-service
port: 8080
# 기본 라우트 (매칭 없으면 여기로)
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: stable-api-service
port: 8080
트래픽 분할: 카나리 배포
HTTPRoute의 backendRefs.weight로 트래픽을 비율로 분할합니다:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-deploy
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
hostnames:
- "api.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
# 90% → 안정 버전
- name: api-service-stable
port: 8080
weight: 90
# 10% → 카나리 버전
- name: api-service-canary
port: 8080
weight: 10
# 점진적 카나리 롤아웃 스크립트
#!/bin/bash
# 10% → 30% → 50% → 100% 단계적 전환
for WEIGHT in 10 30 50 100; do
STABLE=$((100 - WEIGHT))
kubectl patch httproute canary-deploy -n production --type=merge -p "
spec:
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service-stable
port: 8080
weight: ${STABLE}
- name: api-service-canary
port: 8080
weight: ${WEIGHT}
"
echo "Canary weight: ${WEIGHT}%, Stable: ${STABLE}%"
echo "Monitoring error rate for 5 minutes..."
sleep 300
# 에러율 확인 (Prometheus)
ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=rate(http_errors_total{service='canary'}[5m])" | jq '.data.result[0].value[1]')
if (( $(echo "$ERROR_RATE > 0.05" | bc -l) )); then
echo "Error rate too high (${ERROR_RATE}), rolling back!"
kubectl patch httproute canary-deploy -n production --type=merge -p '
spec:
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service-stable
port: 8080
weight: 100
- name: api-service-canary
port: 8080
weight: 0
'
exit 1
fi
done
echo "Canary promotion complete!"
URL 재작성과 리다이렉트
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: url-rewrite
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
hostnames:
- "api.example.com"
rules:
# URL 재작성: /api/v1/* → 백엔드에서는 /* 로 수신
- matches:
- path:
type: PathPrefix
value: /api/v1
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: api-v1-service
port: 8080
# 호스트명 재작성
- matches:
- path:
type: PathPrefix
value: /legacy
filters:
- type: URLRewrite
urlRewrite:
hostname: legacy-internal.example.com
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: legacy-service
port: 8080
---
# HTTP → HTTPS 리다이렉트
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: https-redirect
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
sectionName: http # HTTP 리스너에 바인딩
hostnames:
- "api.example.com"
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
요청·응답 헤더 수정
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-modify
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
# 요청 헤더 수정 (백엔드로 전달)
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Forwarded-Proto
value: https
add:
- name: X-Request-Start
value: "t=${msec}"
remove:
- X-Debug-Internal
# 응답 헤더 수정 (클라이언트로 반환)
- type: ResponseHeaderModifier
responseHeaderModifier:
set:
- name: X-Content-Type-Options
value: nosniff
- name: Strict-Transport-Security
value: "max-age=31536000; includeSubDomains"
add:
- name: X-Served-By
value: gateway-api
remove:
- Server
- X-Powered-By
backendRefs:
- name: api-service
port: 8080
멀티 호스트·멀티 네임스페이스
# 여러 도메인을 하나의 Gateway에서 처리
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: multi-host
namespace: production
spec:
parentRefs:
- name: api-gateway
namespace: infra
hostnames:
- "api.example.com"
- "api.example.co.kr" # 다국어 도메인
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: api-service
port: 8080
---
# 다른 네임스페이스의 서비스 참조 (ReferenceGrant 필요)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: cross-ns-route
namespace: frontend
spec:
parentRefs:
- name: api-gateway
namespace: infra
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
namespace: backend # 다른 네임스페이스
port: 8080
---
# ReferenceGrant: 크로스 네임스페이스 참조 허용
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-frontend-to-backend
namespace: backend # 참조 대상 네임스페이스
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: frontend # 참조하는 네임스페이스
to:
- group: ""
kind: Service
HTTPRoute 상태 확인과 디버깅
# HTTPRoute 상태 확인
kubectl get httproute -A
kubectl describe httproute api-routes -n production
# 상태 조건 확인
kubectl get httproute api-routes -n production -o jsonpath='{.status.parents[*].conditions}' | jq .
# [
# { "type": "Accepted", "status": "True" },
# { "type": "ResolvedRefs", "status": "True" }
# ]
# Gateway 상태
kubectl get gateway api-gateway -n infra -o jsonpath='{.status.conditions}' | jq .
# 일반적인 에러:
# Accepted=False → parentRef가 잘못되었거나 네임스페이스 허용 안 됨
# ResolvedRefs=False → backendRef 서비스가 존재하지 않음
# BackendNotFound → 서비스 또는 포트 확인
# 이벤트 확인
kubectl get events -n production --field-selector involvedObject.kind=HTTPRoute
Ingress에서 Gateway API로 마이그레이션
| Ingress | Gateway API |
|---|---|
| IngressClass | GatewayClass |
| Ingress (단일 리소스) | Gateway + HTTPRoute (분리) |
| 어노테이션 (비표준) | filters (표준 스펙) |
| 트래픽 분할 불가 | backendRefs.weight |
| 크로스 네임스페이스 제한 | ReferenceGrant로 명시적 허용 |
핵심 정리
| 기능 | 필드/필터 |
|---|---|
| 경로 매칭 | matches.path (Exact/PathPrefix/RegularExpression) |
| 헤더 라우팅 | matches.headers |
| 트래픽 분할 | backendRefs.weight |
| URL 재작성 | filters.URLRewrite |
| 리다이렉트 | filters.RequestRedirect |
| 헤더 수정 | filters.RequestHeaderModifier |
Gateway API HTTPRoute는 Ingress의 어노테이션 지옥에서 벗어나 표준 스펙으로 트래픽 라우팅을 선언적 관리하는 K8s 차세대 표준입니다. 카나리 배포의 weight 기반 분할, 헤더 기반 A/B 테스트, ReferenceGrant를 활용한 멀티 네임스페이스 아키텍처를 적극 활용하세요. K8s Gateway API vs Ingress 비교와 K8s Ingress NGINX 심화도 함께 참고하세요.