Cilium Service Mesh 트래픽 관리
검토 기준: Cilium 1.20.1, Gateway API 1.6.1, 2026년 9월 11일. Kubernetes/EKS 테스트 범위와 플랫폼 요건은 개요를 참고하세요.
개요
Cilium Service Mesh의 트래픽 관리는 eBPF 기반 L4 로드 밸런싱과 Envoy 기반 L7 라우팅을 결합하여 제공됩니다. 이 장에서는 CiliumEnvoyConfig, CiliumNetworkPolicy의 L7 규칙, Gateway API 통합 등을 통한 고급 트래픽 관리 기능을 설명합니다.
트래픽 관리 아키텍처
이 그림은 계층별 기능을 묶은 논리도이며 필수 패킷 처리 순서가 아닙니다. L3/L4만 필요한 트래픽은 Envoy를 거치지 않을 수 있고 실제 egress·ingress·Service 경로는 설정에 따라 달라집니다.
CiliumEnvoyConfig
다음은 서로 독립적인 설정 예시이며 한꺼번에 설치하는 리소스 모음이 아닙니다. 여러 예시가 같은 프런트엔드 Service를 대상으로 하므로 Listener 충돌을 피하도록 하나의 설정 소유자를 선택하세요. 준비된 Cilium 설치에 l7Proxy: true, envoyConfig.enabled: true, 적절한 kube-proxy 대체·라우팅 설정과 CRD가 있어야 합니다.
이름으로 참조하는 프런트엔드·백엔드 Service는 default에 포트 8080, 올바른 selector와 준비된 HTTP 엔드포인트를 갖고 있어야 합니다. Kafka와 gRPC 절은 별도 네임스페이스·포트를 지정합니다. CEC 예시는 워크로드, Service나 인증서를 생성하지 않습니다.
services는 리다이렉트할 프런트엔드를 선택하고 백엔드를 동기화합니다. backendServices는 다른 Service의 프런트엔드를 리다이렉트하지 않고 백엔드만 동기화합니다. EDS Cluster 리소스는 여전히 필요합니다. 생략한 Listener 주소와 xDS 소스는 Cilium이 보완합니다. Kubernetes 수락만으로 충분하지 않으므로 Agent·Envoy 오류와 실제 요청을 확인하세요. 소유권과 검증 범위는 아키텍처를 참고하세요.
기본 구조
CiliumEnvoyConfig는 특정 서비스에 대한 Envoy 설정을 정의합니다:
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: my-service-config
namespace: default
spec:
services:
- name: my-service
namespace: default
ports:
- 8080
backendServices:
- name: backend-v1
namespace: default
- name: backend-v2
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: my-service-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: my-service-listener
route_config:
name: my-service-listener-routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
route:
weighted_clusters:
clusters:
- name: default/backend-v1
weight: 50
- name: default/backend-v2
weight: 50
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/backend-v1
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/backend-v2
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN이 완전한 예시는 명시된 두 백엔드로 요청을 분산합니다. Listener, HTTP 경로와 EDS Cluster는 별도 구성 요소이며, 백엔드 Service 목록만 작성해도 Cluster가 정의되는 것은 아닙니다.
HTTP 라우팅
경로 기반 라우팅
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: path-routing
namespace: default
spec:
services:
- name: api-gateway
namespace: default
ports:
- 8080
backendServices:
- name: users-service
namespace: default
- name: orders-service
namespace: default
- name: products-service
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: api-gateway-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-gateway
codec_type: AUTO
route_config:
name: api_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
path_separated_prefix: /users
route:
cluster: default/users-service
- match:
path_separated_prefix: /orders
route:
cluster: default/orders-service
- match:
path_separated_prefix: /products
route:
cluster: default/products-service
- match:
prefix: /
direct_response:
status: 404
body:
inline_string: Not Found
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/orders-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/products-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/users-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBINEnvoy는 이 경로들을 순서대로 평가합니다. path_separated_prefix는 /users와 /users/123에는 일치하지만 /users-old에는 일치하지 않습니다. 마지막 / 규칙이 기본 경로이며, 임의 문자열 prefix와 구분해야 합니다.
헤더 기반 라우팅
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: header-routing
namespace: default
spec:
services:
- name: api-service
namespace: default
ports:
- 8080
backendServices:
- name: api-v1
namespace: default
- name: api-v2
namespace: default
- name: api-beta
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: header-routing-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-service
route_config:
name: header_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
headers:
- name: X-API-Version
string_match:
exact: v2
route:
cluster: default/api-v2
- match:
prefix: /
headers:
- name: X-Beta-User
string_match:
exact: 'true'
route:
cluster: default/api-beta
- match:
prefix: /
route:
cluster: default/api-v1
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-beta
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-v1
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-v2
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN먼저 일치한 규칙을 사용하므로 두 헤더를 모두 가진 요청은 v2를 선택합니다. 클라이언트가 보낸 버전·베타 헤더는 라우팅 힌트이며 해당 백엔드 접근 권한의 증거가 아닙니다.
메서드 기반 라우팅
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: method-routing
namespace: default
spec:
services:
- name: rest-api
namespace: default
ports:
- 8080
backendServices:
- name: read-service
namespace: default
- name: write-service
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: method-routing-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: rest-api
route_config:
name: method_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
headers:
- name: :method
string_match:
safe_regex:
google_re2: {}
regex: ^(GET|HEAD)$
route:
cluster: default/read-service
- match:
prefix: /
headers:
- name: :method
string_match:
safe_regex:
google_re2: {}
regex: ^(POST|PUT|DELETE|PATCH)$
route:
cluster: default/write-service
- match:
prefix: /
direct_response:
status: 405
response_headers_to_add:
- header:
key: allow
value: GET, HEAD, POST, PUT, DELETE, PATCH
append_action: OVERWRITE_IF_EXISTS_OR_ADD
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/read-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/write-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBINGET/HEAD는 읽기 Service, POST/PUT/DELETE/PATCH는 쓰기 Service로 보냅니다. 다른 메서드는 405를 반환하므로 필요한 OPTIONS/CORS나 애플리케이션별 동작을 별도로 설계하세요. 쓰기를 전용 백엔드로 보내는 것만으로 인가·멱등성이 구현되지는 않습니다.
L7 트래픽 정책
CiliumNetworkPolicy L7 규칙
CiliumNetworkPolicy를 통해 L7 레벨의 세밀한 트래픽 제어가 가능합니다:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-http-policy
namespace: default
spec:
endpointSelector:
matchLabels:
k8s:app: backend-api
ingress:
- fromEndpoints:
- matchLabels:
k8s:app: frontend
k8s:io.kubernetes.pod.namespace: default
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
- method: ^GET$
path: ^/api/users/.*$
- method: ^GET$
path: ^/api/products/.*$
- method: ^POST$
path: ^/api/orders$
- method: ^GET$
path: ^/api/admin/.*$
headerMatches:
- name: X-API-Version
value: v1규칙은 OR 관계이며 헤더 조건은 admin 경로 규칙에만 적용됩니다. X-API-Version: v1은 정확한 버전 조건이지 관리자 자격 증명이 아닙니다. 사용자 인증·인가는 애플리케이션에서 처리하세요. 명시한 네임스페이스의 ingress 트래픽을 선택하되 다른 적용 정책의 허용 규칙이 접근 범위를 넓힐 수 있습니다.
다양한 프로토콜 지원
Kafka: 네트워크 경계와 브로커 ACL
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: kafka-l4-policy
namespace: kafka
spec:
endpointSelector:
matchLabels:
k8s:app: kafka-broker
ingress:
- fromEndpoints:
- matchLabels:
k8s:app: kafka-producer
k8s:io.kubernetes.pod.namespace: kafka
toPorts:
- ports:
- port: '9092'
protocol: TCP
- fromEndpoints:
- matchLabels:
k8s:app: kafka-consumer
k8s:io.kubernetes.pod.namespace: kafka
toPorts:
- ports:
- port: '9092'
protocol: TCPCilium 1.20.1 L7 정책 API에는 HTTP와 DNS가 있고 기존 rules.kafka API는 없습니다. 해당 릴리스의 CRD는 이 Kafka 규칙 객체를 거부합니다. L7 규칙만 제거하면 토픽 권한 제어가 아니라 L4 허용만 남습니다. 대체 예시는 지정 클라이언트의 미리 구성된 브로커 TCP 9092 접근만 허용합니다. 토픽·컨슈머 그룹·작업 권한은 Kafka TLS/SASL과 브로커 ACL로 별도 구성하세요. 여기의 네트워크 정책은 produce와 fetch를 구분하지 못합니다.
DNS L7 정책
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: dns-l7-policy
namespace: default
spec:
endpointSelector:
matchLabels:
k8s:app: web-app
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s:k8s-app: kube-dns
toPorts:
- ports:
- port: '53'
protocol: UDP
- port: '53'
protocol: TCP
rules:
dns:
- matchPattern: '*.example.com'
- matchPattern: api.external-service.io
- matchName: database.internal.svc.cluster.local이 예시는 선택한 클러스터 resolver로 보내는 UDP·TCP DNS 질의만 허용합니다. 반환된 주소의 HTTPS·데이터베이스 연결을 허용하지 않으므로 필요한 목적지에 toFQDNs·엔드포인트와 포트 규칙을 따로 추가하세요. *.example.com에는 루트 example.com이나 임의 깊이의 하위 도메인이 포함되지 않습니다. Resolver 검색 목록에 따른 질의도 고려하고, NodeLocal DNS에는 별도로 검증한 목적지 규칙을 사용해야 합니다. 이름 제한만으로 데이터 유출·DoH·허용 도메인 악용을 방지한다고 보장할 수 없습니다.
gRPC L7 정책
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: grpc-l7-policy
namespace: default
spec:
endpointSelector:
matchLabels:
k8s:app: grpc-server
ingress:
- fromEndpoints:
- matchLabels:
k8s:app: grpc-client
k8s:io.kubernetes.pod.namespace: default
toPorts:
- ports:
- port: '50051'
protocol: TCP
rules:
http:
- method: ^POST$
path: ^/myapp\.UserService/GetUser$
- method: ^POST$
path: ^/myapp\.UserService/ListUsers$
- method: ^POST$
path: ^/myapp\.OrderService/.*$이 HTTP/2 규칙은 gRPC의 POST /package.Service/Method 경로를 검사합니다. 패키지 이름의 점을 이스케이프하고 표현식의 경계를 고정했습니다. 지원되는 검사 가능한 HTTP/2 경로를 전제로 하며, 애플리케이션 암호화 트래픽에는 해당 TLS 설정이 필요합니다. Health/reflection 등 다른 메서드는 자동 허용되지 않고, HTTP 정책으로 protobuf 메시지 내부 필드를 인가할 수는 없습니다.
로드 밸런싱
L4 로드 밸런싱 (eBPF)
eBPF 기반 L4 로드 밸런싱은 kube-proxy를 대체합니다:
kubeProxyReplacement: true
k8sServiceHost: <reachable-api-server-host>
k8sServicePort: 6443
loadBalancer:
algorithm: maglev
mode: snat
nodePort:
enableHealthCheck: trueAPI 엔드포인트는 bootstrap 중에도 접근할 수 있어야 하며 실제 포트를 사용하세요. EKS는 일반적으로 443입니다. 플랫폼별 IPAM·라우팅 설정도 유지해야 합니다. Chart 키는 nodePort.enableHealthCheck이며 기존 loadBalancer.healthCheckNodePort로는 설정되지 않았습니다. loadBalancer.serviceTopology는 topology-aware routing용이며 ClientIP 세션 어피니티가 아닙니다. DSR dispatch·라우팅 조합은 별도로 설계해야 하고, 문서화된 dispatch 선택지는 opt·geneve이며 ipip가 아닙니다. 아키텍처 설명을 참고하세요.
Maglev 해싱
Maglev는 해당 외부 트래픽의 흐름 키를 조회 테이블을 통해 백엔드에 매핑합니다. 백엔드 집합 변경 시 재할당을 줄이지만, 제거된 백엔드의 세션 유지나 Service.spec.sessionAffinity: ClientIP를 대체하지 않습니다.
Cilium 1.20.1 eBPF Maglev 테이블의 기본 크기는 16,381입니다. 지원 크기에는 65,521이 있으며, 65,537은 아래의 별도 Envoy MAGLEV 예시 값으로 Cilium maglev.tableSize 지원값이 아닙니다. 노드 전체에서 설정이 일관되어야 합니다. 소켓 수준 east–west Service 변환에는 이 Maglev 경로가 적용되지 않습니다.
L7 로드 밸런싱 (Envoy)
L7 로드 밸런싱은 Envoy를 통해 제공됩니다:
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: l7-load-balancing
namespace: default
spec:
services:
- name: api-service
namespace: default
ports:
- 8080
backendServices:
- name: api-backend
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: l7-load-balancer
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: l7-load-balancer
route_config:
name: l7-load-balancer-routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
route:
cluster: default/api-backend
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-backend
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
outlier_detection:
consecutive_5xx: 5
interval: 10s
base_ejection_time: 30s
max_ejection_percent: 50
health_checks:
- timeout: 5s
interval: 10s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check:
path: /health
expected_statuses:
- start: 200
end: 300
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 1000
max_pending_requests: 1000
max_requests: 1000
max_retries: 3능동 /health probe, 수동 outlier detection과 circuit breaker 용량 제한은 별개입니다. HTTP 상태 범위는 [200, 300)이므로 299도 포함합니다. 백엔드가 health 엔드포인트를 구현하고 정책이 probe 경로를 허용해야 합니다. Outlier ejection이 모든 요청의 실패 백엔드 회피를 보장하지는 않습니다. circuit_breakers.thresholds의 max_retries는 동시 재시도 리소스 제한이며 요청당 재시도 횟수가 아닙니다.
로드 밸런싱 알고리즘 옵션
다음 Cluster 설정 조각 중 하나만 선택하세요. lb_policy 키를 반복한 하나의 YAML 매핑이 아니라 서로 다른 대안입니다. RING_HASH/MAGLEV에서 애플리케이션 키로 일관된 요청 분배를 하려면 적절한 경로 hash_policy도 필요합니다. 해시가 주어지지 않으면 임의 키로 선택할 수 있습니다. Envoy의 L7 MAGLEV 테이블과 Cilium eBPF Maglev 테이블은 별개입니다.
lb_policy: ROUND_ROBINlb_policy: LEAST_REQUEST
least_request_lb_config:
choice_count: 2lb_policy: RANDOMlb_policy: RING_HASH
ring_hash_lb_config:
hash_function: XX_HASH
minimum_ring_size: 1024
maximum_ring_size: 8388608lb_policy: MAGLEV
maglev_lb_config:
table_size: 65537트래픽 분할 (카나리 배포)
가중치 기반 트래픽 분할
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: canary-deployment
namespace: default
spec:
services:
- name: frontend
namespace: default
ports:
- 8080
backendServices:
- name: frontend-stable
namespace: default
- name: frontend-canary
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: canary-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: frontend
route_config:
name: canary_routes
virtual_hosts:
- name: frontend
domains:
- '*'
routes:
- match:
prefix: /
route:
weighted_clusters:
clusters:
- name: default/frontend-stable
weight: 90
- name: default/frontend-canary
weight: 10
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/frontend-canary
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/frontend-stable
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN90과 10은 상대적 선택 확률이며, 요청 10개마다 정확한 비율이나 사용자·세션 고정을 보장하지 않습니다. 현재 Envoy는 가중치 합계를 사용하므로 폐기된 total_weight 필드를 생략했습니다. 이는 트래픽 선택 설정일 뿐 자동 분석·승격·롤백 루프가 아닙니다.
헤더 기반 카나리
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: header-canary
namespace: default
spec:
services:
- name: api
namespace: default
ports:
- 8080
backendServices:
- name: api-stable
namespace: default
- name: api-canary
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: header-canary-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api
route_config:
name: header_canary_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
headers:
- name: X-Canary
string_match:
exact: 'true'
route:
cluster: default/api-canary
- match:
prefix: /
route:
cluster: default/api-stable
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-canary
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-stable
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN정확히 X-Canary: true인 요청만 canary를 선택하며 다른 요청은 stable로 보냅니다. 인증된 경계가 제어하지 않는다면 이 헤더는 신뢰할 수 없습니다. Stable/canary의 애플리케이션 상태와 호환성도 롤아웃 계획에서 검토하세요.
재시도 및 타임아웃
재시도 설정
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: retry-config
namespace: default
spec:
services:
- name: api-service
namespace: default
ports:
- 8080
backendServices:
- name: api-backend
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: retry-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-service
route_config:
name: retry_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
headers:
- name: :method
string_match:
exact: GET
route:
cluster: default/api-backend
timeout: 7s
retry_policy:
retry_on: 5xx,reset,connect-failure
num_retries: 2
per_try_timeout: 2s
retry_back_off:
base_interval: 0.025s
max_interval: 0.25s
retriable_request_headers:
- name: :method
string_match:
exact: GET
- match:
prefix: /
route:
cluster: default/api-backend
timeout: 7s
retry_policy:
num_retries: 0
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
early_header_mutation_extensions:
- name: envoy.http.early_header_mutation.header_mutation
typed_config:
'@type': type.googleapis.com/envoy.extensions.http.early_header_mutation.header_mutation.v3.HeaderMutation
mutations:
- remove: x-envoy-retry-on
- remove: x-envoy-retry-grpc-on
- remove: x-envoy-max-retries
- remove: x-envoy-hedge-on-per-try-timeout
- remove: x-envoy-retriable-header-names
- remove: x-envoy-retriable-status-codes
- remove: x-envoy-upstream-rq-timeout-ms
- remove: x-envoy-upstream-rq-per-try-timeout-ms
- remove: x-envoy-expected-rq-timeout-ms
- remove: x-envoy-upstream-stream-duration-ms
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-backend
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBINGET만 재시도하며 최대 2회의 추가 시도, 시도당 2초와 전체 경로 타임아웃 7초를 설정합니다. 시도당 타임아웃에는 첫 시도도 포함되며 재시도 사이의 대기 시간이 아닙니다. Backoff는 별도로 설정합니다. GET 이외의 기본 경로는 num_retries: 0을 명시합니다.
초기 헤더 변경 확장은 라우팅·타임아웃 계산 전에 Envoy 재시도·타임아웃 제어 헤더를 제거합니다. Cilium 1.20.1 프록시 이미지에는 이 확장이 포함되어 있지만 일반 HTTP header_mutation과 Lua 필터는 활성화되어 있지 않습니다. 기존 예시의 previous_priorities 재시도 우선순위 확장도 이 이미지에는 없습니다. 모든 upstream Envoy 확장을 사용할 수 있다고 가정하면 안 됩니다.
반복해도 안전한 GET을 구현한 HTTP 엔드포인트에 사용하세요. 애플리케이션·클라이언트나 다른 프록시는 독립적으로 재시도할 수 있습니다. 검토된 멱등성 메커니즘이 없다면 쓰기는 한 번만 시도하세요. retriable_headers는 upstream 응답 헤더이며 retry_on: retriable-headers와 함께 사용합니다. retriable_request_headers는 재시도할 요청을 제한하는 별도 필드입니다. retriable-4xx도 모든 4xx 응답 재시도를 뜻하지 않습니다.
타임아웃 설정
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: timeout-config
namespace: default
spec:
services:
- name: slow-service
namespace: default
ports:
- 8080
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: timeout-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: slow-service
common_http_protocol_options:
idle_timeout: 300s
headers_with_underscores_action: REJECT_REQUEST
stream_idle_timeout: 60s
request_timeout: 0s
route_config:
name: timeout_routes
virtual_hosts:
- name: slow-service
domains:
- '*'
routes:
- match:
path_separated_prefix: /long-running
route:
cluster: default/slow-service
timeout: 300s
idle_timeout: 300s
retry_policy:
num_retries: 0
- match:
path_separated_prefix: /stream
route:
cluster: default/slow-service
timeout: 0s
idle_timeout: 60s
retry_policy:
num_retries: 0
- match:
prefix: /
route:
cluster: default/slow-service
timeout: 60s
retry_policy:
num_retries: 0
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
early_header_mutation_extensions:
- name: envoy.http.early_header_mutation.header_mutation
typed_config:
'@type': type.googleapis.com/envoy.extensions.http.early_header_mutation.header_mutation.v3.HeaderMutation
mutations:
- remove: x-envoy-retry-on
- remove: x-envoy-retry-grpc-on
- remove: x-envoy-max-retries
- remove: x-envoy-hedge-on-per-try-timeout
- remove: x-envoy-retriable-header-names
- remove: x-envoy-retriable-status-codes
- remove: x-envoy-upstream-rq-timeout-ms
- remove: x-envoy-upstream-rq-per-try-timeout-ms
- remove: x-envoy-expected-rq-timeout-ms
- remove: x-envoy-upstream-stream-duration-ms
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/slow-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN구체적인 경로를 기본 경로보다 앞에 배치했습니다. /long-running에는 경로·스트림 idle 300초, /stream에는 전체 응답 타임아웃 비활성화와 idle 60초를 적용합니다. 다른 경로의 경로 타임아웃은 60초입니다. /streaming은 /stream에 일치하지 않습니다.
Upstream Cluster의 connect_timeout은 연결 수립 제한이고, common_http_protocol_options.idle_timeout은 downstream 연결의 유휴 제한입니다. HCM request_timeout은 백엔드 처리가 아니라 클라이언트 요청 수신 시간이며 스트리밍 요청을 위해 여기서는 비활성화합니다. 노출된 서비스에는 그에 맞는 edge·헤더·본문·연결 제한이 필요합니다. Stream idle 제한, 클라이언트 deadline, 인프라 제한과 연결 손실은 여전히 스트림을 종료할 수 있습니다. timeout: 0s는 무제한 연결을 보장하지 않습니다.
Rate Limiting
로컬 Rate Limiting
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: local-ratelimit
namespace: default
spec:
services:
- name: api-service
namespace: default
ports:
- 8080
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: ratelimit-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-service
route_config:
name: ratelimit_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
prefix: /
route:
cluster: default/api-service
http_filters:
- name: envoy.filters.http.local_ratelimit
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: http_local_rate_limiter
token_bucket:
max_tokens: 1000
tokens_per_fill: 100
fill_interval: 1s
status:
code: TooManyRequests
filter_enabled:
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
default_value:
numerator: 100
denominator: HUNDRED
enable_x_ratelimit_headers: DRAFT_VERSION_03
local_rate_limit_per_downstream_connection: false
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN이 버킷은 Envoy 프로세스별로 burst 1,000개와 초당 100개 토큰 보충을 제공하며 해당 프로세스 worker가 공유합니다. 클러스터 전체 쿼터가 아닙니다. 활성화·강제 적용 비율을 모두 명시했습니다. enable_x_ratelimit_headers: DRAFT_VERSION_03으로 필터의 실제 limit·remaining·reset 헤더를 사용하며, 임의의 dynamic-metadata 키로 정확한 잔여 토큰 수를 얻을 수 있다고 가정하지 않습니다.
경로별 Rate Limiting
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: per-route-ratelimit
namespace: default
spec:
services:
- name: api-service
namespace: default
ports:
- 8080
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: per-route-ratelimit-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-service
route_config:
name: ratelimit_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
path_separated_prefix: /auth
route:
cluster: default/api-service
typed_per_filter_config:
envoy.filters.http.local_ratelimit:
'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: auth_rate_limiter
token_bucket:
max_tokens: 10
tokens_per_fill: 5
fill_interval: 60s
filter_enabled:
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
default_value:
numerator: 100
denominator: HUNDRED
local_rate_limit_per_downstream_connection: false
enable_x_ratelimit_headers: DRAFT_VERSION_03
- match:
path_separated_prefix: /search
route:
cluster: default/api-service
typed_per_filter_config:
envoy.filters.http.local_ratelimit:
'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: search_rate_limiter
token_bucket:
max_tokens: 100
tokens_per_fill: 50
fill_interval: 1s
filter_enabled:
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
default_value:
numerator: 100
denominator: HUNDRED
local_rate_limit_per_downstream_connection: false
enable_x_ratelimit_headers: DRAFT_VERSION_03
- match:
prefix: /
route:
cluster: default/api-service
typed_per_filter_config:
envoy.filters.http.local_ratelimit:
'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: default_rate_limiter
token_bucket:
max_tokens: 1000
tokens_per_fill: 100
fill_interval: 1s
filter_enabled:
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
default_value:
numerator: 100
denominator: HUNDRED
local_rate_limit_per_downstream_connection: false
enable_x_ratelimit_headers: DRAFT_VERSION_03
http_filters:
- name: envoy.filters.http.local_ratelimit
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: http_local_rate_limiter
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN경로마다 활성화·강제 적용 비율까지 포함한 완전한 로컬 rate-limit 오버라이드를 제공합니다. Auth는 burst 10개와 60초당 5개 보충, search는 burst 100개와 초당 50개 보충, 기본 경로는 burst 1,000개와 초당 100개 보충입니다. 사용자별 제한이 아니라 프로세스별 버킷입니다. Enabled/enforced 비율이 없으면 실질적인 제한이 기본적으로 적용되지 않습니다.
URL 재작성 및 헤더 조작
URL 재작성
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: url-rewrite
namespace: default
spec:
services:
- name: api-gateway
namespace: default
ports:
- 8080
backendServices:
- name: users-service
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: rewrite-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-gateway
route_config:
name: rewrite_routes
virtual_hosts:
- name: api
domains:
- '*'
routes:
- match:
path_separated_prefix: /api/v1/users
route:
cluster: default/users-service
prefix_rewrite: /users
- match:
safe_regex:
google_re2: {}
regex: ^/v([0-9]+)/(.*)$
route:
cluster: default/users-service
regex_rewrite:
pattern:
google_re2: {}
regex: ^/v([0-9]+)/([^?]*)(\?.*)?$
substitution: /api/v\1/\2\3
- match:
path: /legacy
route:
cluster: default/users-service
host_rewrite_literal: legacy.internal.svc.cluster.local
prefix_rewrite: /
- match:
prefix: /legacy/
route:
cluster: default/users-service
host_rewrite_literal: legacy.internal.svc.cluster.local
prefix_rewrite: /
- match:
prefix: /
direct_response:
status: 404
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/users-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN/api/v1/users/123은 /users/123으로, /v2/users?active=1은 기존 쿼리를 유지한 /api/v2/users?active=1로 바뀝니다. Legacy 루트와 하위 경로를 따로 매칭해 이중 슬래시를 피합니다. Host rewrite는 선택한 Cluster에 보내는 HTTP authority를 변경하며, 다른 백엔드 Service를 자동으로 조회하는 기능이 아닙니다.
헤더 조작
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: header-manipulation
namespace: default
spec:
services:
- name: api-service
namespace: default
ports:
- 8080
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: header-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-service
route_config:
name: header_routes
virtual_hosts:
- name: api
domains:
- '*'
request_headers_to_add:
- header:
key: X-Forwarded-By
value: cilium-envoy
append_action: OVERWRITE_IF_EXISTS_OR_ADD
response_headers_to_add:
- header:
key: X-Served-By
value: cilium-service-mesh
append_action: OVERWRITE_IF_EXISTS_OR_ADD
response_headers_to_remove:
- server
- x-powered-by
routes:
- match:
prefix: /
route:
cluster: default/api-service
request_headers_to_add:
- header:
key: X-Request-Start
value: '%START_TIME(%s.%3f)%'
append_action: OVERWRITE_IF_EXISTS_OR_ADD
- header:
key: X-Envoy-Original-Path
value: '%REQ(:PATH)%'
append_action: OVERWRITE_IF_EXISTS_OR_ADD
response_headers_to_add:
- header:
key: X-Response-Time
value: '%RESPONSE_DURATION%ms'
append_action: OVERWRITE_IF_EXISTS_OR_ADD
- header:
key: X-Upstream-Host
value: '%UPSTREAM_HOST%'
append_action: OVERWRITE_IF_EXISTS_OR_ADD
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/api-service
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN경로별 헤더 변경은 RouteAction 내부가 아니라 route 액션과 같은 레벨에 둡니다. 응답 시간 formatter는 응답 헤더 생성 시 평가하므로 아직 전송하지 않은 본문의 완료 시간을 보고할 수 없습니다. Upstream-host 진단값은 내부 라우팅 정보를 노출하므로 이러한 헤더는 적절한 테스트·내부 인터페이스에서 사용하세요.
Gateway API 통합
GatewayClass 및 Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: cilium
spec:
controllerName: io.cilium/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: api-gateway
namespace: default
spec:
gatewayClassName: cilium
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: api-gateway-tls
allowedRoutes:
namespaces:
from: SameGateway API 1.6.1 CRD와 Cilium의 gatewayAPI.enabled: true, kubeProxyReplacement: true, l7Proxy: true가 필요합니다. GatewayClass는 컨트롤러 연결을 설명합니다. 설치 도구가 이미 cilium을 소유한다면 별도 소유자를 만들지 말고 재사용하세요. default에 호스트 이름에 맞는 인증서가 담긴 유효한 TLS Secret api-gateway-tls를 준비해야 합니다. LoadBalancer 노출·주소 할당은 플랫폼별로 다릅니다. GatewayClass/Gateway의 Accepted·Programmed 조건과 Listener 참조를 확인하세요. 이 매니페스트가 완전한 EKS 노출 구성을 제공하지는 않습니다.
HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-routes
namespace: default
spec:
parentRefs:
- name: api-gateway
namespace: default
sectionName: https
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /users
backendRefs:
- name: users-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /orders
backendRefs:
- name: orders-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /
headers:
- name: X-API-Version
value: v2
backendRefs:
- name: api-v2
port: 8080
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: api-stable
port: 8080
weight: 90
- name: api-canary
port: 8080
weight: 10이 경로는 https Listener에만 연결합니다. 외부 Listener 포트 80/443과 백엔드 Service 포트 8080은 별개입니다. HTTP Listener가 자동 HTTPS 리다이렉트가 되는 것은 아니므로 필요하면 별도 HTTP 경로를 구성하세요. Gateway API는 경로 구체성·헤더 조건 등의 명세상 우선순위를 사용하며, 모든 규칙을 단순 YAML 순서대로 평가한다고 가정하면 안 됩니다. Accepted·ResolvedRefs와 실제 Listener 상태를 확인하세요.
HTTPRoute 고급 기능
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: advanced-routes
namespace: default
spec:
parentRefs:
- name: api-gateway
sectionName: https
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Doc-Route
value: api-v1
remove:
- X-Internal-Header
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: X-Frame-Options
value: DENY
- name: X-Content-Type-Options
value: nosniff
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /v1
backendRefs:
- name: api-service
port: 8080
- matches:
- path:
type: Exact
value: /old-endpoint
method: GET
filters:
- type: RequestRedirect
requestRedirect:
scheme: https
hostname: new.example.com
path:
type: ReplaceFullPath
replaceFullPath: /new-endpoint
statusCode: 301
hostnames:
- api.example.com여기의 헤더 값은 이식 가능한 Gateway API의 리터럴 설정입니다. API는 Envoy %REQ(...)% 템플릿 확장을 정의하지 않습니다. 요청 ID는 적절한 애플리케이션·프록시 계층에서 유지하거나 생성하세요. 실제 전송 방식과 무관하게 X-Forwarded-Proto: https를 강제하면 안 됩니다. URLRewrite는 클라이언트 리다이렉트 없이 upstream 경로를 바꿉니다. Legacy 리다이렉트는 GET에만 적용합니다. 301은 클라이언트에서 메서드를 바꿀 수 있으므로 임의의 쓰기를 그대로 리다이렉트하면 안 됩니다.
트래픽 미러링
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: traffic-mirror
namespace: default
spec:
services:
- name: production-service
namespace: default
ports:
- 8080
backendServices:
- name: production-backend
namespace: default
- name: shadow-backend
namespace: default
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: mirror-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: production-service
route_config:
name: mirror_routes
virtual_hosts:
- name: production
domains:
- '*'
routes:
- match:
prefix: /
headers:
- name: :method
string_match:
safe_regex:
google_re2: {}
regex: ^(GET|HEAD)$
route:
cluster: default/production-backend
request_mirror_policies:
- cluster: default/shadow-backend
runtime_fraction:
default_value:
numerator: 100
denominator: HUNDRED
trace_sampled: false
- match:
prefix: /
route:
cluster: default/production-backend
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/production-backend
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
name: default/shadow-backend
connect_timeout: 5s
type: EDS
lb_policy: ROUND_ROBIN미러는 **선택한 GET/HEAD 요청의 100%**를 받고, 다른 메서드의 기본 경로에는 미러 정책이 없습니다. 합성 또는 승인된 읽기 전용 트래픽으로 시험하고, shadow 백엔드가 프로덕션 상태를 변경하거나 외부 부수 효과를 만들지 못하도록 격리하세요. 미러링은 리소스를 소비하고 요청 데이터를 복사하며, 별도 설정이 없으면 authority에 -shadow를 붙일 수 있습니다. 미러 응답을 호출자에게 반환하지 않는다는 사실이 사용자 영향 0을 보장하지는 않습니다.
다음 단계
- 보안: 인증·암호화와 L7 네트워크 정책 검토
- 관측성: Hubble을 통한 트래픽 모니터링
- 인그레스 & 게이트웨이: 외부 트래픽 관리
참고 자료
- Cilium 1.20.1 L7 policy
- Cilium L3/FQDN policy
- Cilium CEC example
- Cilium Envoy parser
- Cilium kube-proxy replacement
- Cilium Gateway API installation
- Cilium 1.20.1 chart values
- Cilium proxy image extension list
- Envoy 1.37.5 routing API
- Envoy retry implementation
- Envoy router timing and header processing
- Envoy early header mutation
- Envoy local rate limiting
- Envoy timeout definitions
- Gateway API 1.6.1 HTTPRoute specification
- Kafka broker ACLs
