Apache APISIX Ingress Controller의 Traffic Split
Fei Han
March 27, 2021
트래픽 분할(Traffic Split)은 트래픽을 여러 백엔드 서비스로 분할하여 전달하는 기능입니다. API 게이트웨이(예: Apache APISIX 및 Traefik), 서비스 메시(예: Istio 및 Linkerd)와 같은 솔루션은 트래픽 분할을 수행하고 Canary Release 및 Blue-Green Deployment와 같은 기능을 구현할 수 있습니다.
트래픽 분할은 Ingress Controller에서도 중요한 기능입니다. Kubernetes 클러스터의 인그레스 레이어로서, 인그레스 컨트롤러에 일부 트래픽 분할 규칙을 설정하여 새로운 버전의 애플리케이션을 출시할 때 발생할 수 있는 위험을 줄이는 것이 바람직합니다. 이렇게 하면 새로 출시된 인스턴스로 라우팅되는 트래픽의 양을 제어할 수 있습니다. 이 글에서는 Ingress Nginx와 Kong Ingress Controller에서의 트래픽 분할(또는 Canary Release)을 소개하고, 최종적으로 Apache APISIX Ingress Controller에서의 트래픽 분할을 설명합니다.
(참고: 더 간결한 설명을 위해, "canary app"이라는 용어를 Canary 규칙이 적용된 후 라우팅되는 백엔드 서비스를 설명하는 데 사용하고, "stable app"이라는 용어를 Canary 규칙이 적용되지 않은 경우 라우팅되는 백엔드 서비스를 설명하는 데 사용합니다. 예를 들어, 아래 다이어그램에서 canary와 stable app은 각각 "foo-canary"와 "foo"입니다.)
Ingress Nginx
Ingress Nginx는 Canary Release를 지원하며, 이는 "nginx.ingress.kubernetes.io/canary"라는 어노테이션으로 제어됩니다. 이 기능을 사용자 정의하기 위해 여러 어노테이션을 지원합니다.
- nginx.ingress.kubernetes.io/canary-by-header
헤더 값(nginx.ingress.kubernetes.io/canary-by-header로 지정)에 따라 목적지가 결정됩니다. 헤더 값이 "always"인 경우 Canary app으로 라우팅되고, 그렇지 않은 경우 stable app으로 라우팅됩니다(헤더 값이 "never"인 경우).
- nginx.ingress.kubernetes.io/canary-by-header-value
이 어노테이션은 nginx.ingress.kubernetes.io/canary-by-header를 확장하며, 이제 헤더 값이 "always" 또는 "never"일 필요가 없습니다.
- nginx.ingress.kubernetes.io/canary-by-header-pattern
nginx.ingress.kubernetes.io/canary-by-header와 유사하지만, 값은 PCRE 호환 정규 표현식입니다.
- nginx.ingress.kubernetes.io/canary-by-cookie
Cookie 헤더의 데이터 필드를 사용하여 백엔드 서비스를 결정합니다.
- nginx.ingress.kubernetes.io/canary-weight
0에서 100 사이의 가중치 값을 할당하면, 이 가중치에 따라 트래픽이 전달됩니다. 가중치가 0이면 모든 트래픽이 canary app으로 라우팅되고, 100이면 모든 트래픽이 stable app으로 라우팅됩니다.
다음 YAML 스니펫은 URI 경로가 "/get"로 시작하고 User-Agent가 ".Mozilla." 패턴과 일치하는 요청을 canary app "foo-canary"로 프록시합니다.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "User-Agent"
nginx.ingress.kubernetes.io/canary-by-header-pattern:
".*Mozilla.*"
name: ingress-v1beta1
Kong
Kong Gateway는 Canary Release 플러그인을 가지고 있으며, 이 플러그인을 KongPlugin 리소스를 통해 인그레스 컨트롤러에 노출합니다. 관리자/사용자는 KongPlugin 객체를 생성하고 Canary Release 규칙을 채워야 하며, 대상 Kubernetes Service에 "konghq.com/plugins" 어노테이션을 주입해야 합니다. 또는 KongClusterPlugin 객체를 생성하여 이 Canary 규칙을 전체 클러스터에 적용할 수 있습니다.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: foo-canary
config:
percentage: 30
upstream_host: foo.com
upstream_fallback: false
upstream_port: 80
plugin: canary
---
apiVersion: v1
kind: Service
metadata:
name: foo-canary
labels:
app: foo
annotations:
konghq.com/plugins: foo-canary
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: foo
canary: true
위의 예제는 "foo-canary" 서비스를 "canary"로 표시하고, 이 서비스로 30%의 트래픽을 프록시하는 Canary Release 규칙을 생성합니다.
Apache APISIX
Apache APISIX는 traffic-split 플러그인을 통해 사용자 정의 규칙으로 트래픽을 분할하며, Apache APISIX Ingress Controller는 이 플러그인과 ApisixRoute의 유연한 라우트 매칭 기능을 통해 ApisixRoute에 트래픽 분할 기능을 구현합니다(어노테이션에 의존하지 않고 일급 지원으로).
가중치 기반
여러 Kubernetes 서비스를 구성하여 가중치 기반 Canary 규칙을 다음과 같이 적용할 수 있습니다.
apiVersion: apisix.apache.org/v2alpha1
kind: ApisixRoute
metadata:
name: foo-route
spec:
http:
- name: rule1
match:
hosts:
- foo.org
paths:
- /get*
backends:
- serviceName: foo-canary
servicePort: 80
weight: 10
- serviceName: foo
servicePort: 80
weight: 5
위의 예제는 Host가 "foo.org"이고 URI 경로 접두사가 "/get"인 요청 중 ⅔를 "foo-canary" 서비스로 전달하고, 나머지를 foo로 전달합니다.
Canary 서비스의 가중치는 소규모 검증을 위해 작게 설정할 수 있으며, ApisixRoute를 수정하여 가중치를 늘려 모든 트래픽이 Canary 서비스로 라우팅되도록 하여 출시를 완료할 수 있습니다.
규칙 기반
ApisixRoute의 Exprs 필드를 통해 사용자는 사용자 정의 라우트 매칭 규칙을 구성할 수 있으며, 여러 라우트 규칙을 단일 ApisixRoute 객체로 그룹화할 수 있으므로 규칙 기반 트래픽 분할을 원활하게 구현할 수 있습니다.
apiVersion: apisix.apache.org/v2alpha1
kind: ApisixRoute
metadata:
name: foo-route
spec:
http:
- name: rule1
priority: 1
match:
hosts:
- foo.org
paths:
- /get*
backends:
- serviceName: foo
servicePort: 80
- name: rule2
priority: 2
match:
hosts:
- foo.org
paths:
- /get*
exprs:
- subject:
scope: Query
name: id
op: In
set:
- "3"
- "13"
- "23"
- "33"
backends:
- serviceName: foo-canary
servicePort: 80
Host가 "foo.org"이고 URI 경로 접두사가 "/get"인 요청은 두 부분으로 나뉩니다:
- id 매개변수 값이 3, 13, 23 또는 33인 경우 rule2에 적중하여 foo-canary로 전달됩니다;
- 그 외의 경우 rule1에 적중하여 foo로 라우팅됩니다.
요약
Ingress Nginx의 트래픽 분할(Canary Release)은 가중치 기반 및 헤더 규칙 기반 방식을 지원하지만, 어노테이션에 의존하며 의미론이 약합니다. Kong 방식은 가중치를 통한 Canary Release 구성만 지원하며, 시나리오가 다소 제한적이고 구성이 복잡합니다(여러 리소스를 구성해야 함). 반면, Apache APISIX Ingress Controller의 트래픽 분할은 유연하고 구성이 쉽습니다. 가중치 기반 및 규칙 기반 트래픽 분할 방식 모두에 잘 작동합니다.