Apache APISIX Ingress Controller의 Traffic Split

Fei Han

March 27, 2021

Products

트래픽 분할(Traffic Split)은 트래픽을 여러 백엔드 서비스로 분할하여 전달하는 기능입니다. API 게이트웨이(예: Apache APISIXTraefik), 서비스 메시(예: IstioLinkerd)와 같은 솔루션은 트래픽 분할을 수행하고 Canary ReleaseBlue-Green Deployment와 같은 기능을 구현할 수 있습니다.

트래픽 분할은 Ingress Controller에서도 중요한 기능입니다. Kubernetes 클러스터의 인그레스 레이어로서, 인그레스 컨트롤러에 일부 트래픽 분할 규칙을 설정하여 새로운 버전의 애플리케이션을 출시할 때 발생할 수 있는 위험을 줄이는 것이 바람직합니다. 이렇게 하면 새로 출시된 인스턴스로 라우팅되는 트래픽의 양을 제어할 수 있습니다. 이 글에서는 Ingress NginxKong Ingress Controller에서의 트래픽 분할(또는 Canary Release)을 소개하고, 최종적으로 Apache APISIX Ingress Controller에서의 트래픽 분할을 설명합니다.

(참고: 더 간결한 설명을 위해, "canary app"이라는 용어를 Canary 규칙이 적용된 후 라우팅되는 백엔드 서비스를 설명하는 데 사용하고, "stable app"이라는 용어를 Canary 규칙이 적용되지 않은 경우 라우팅되는 백엔드 서비스를 설명하는 데 사용합니다. 예를 들어, 아래 다이어그램에서 canary와 stable app은 각각 "foo-canary"와 "foo"입니다.)

1.png

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 APISIXtraffic-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의 트래픽 분할은 유연하고 구성이 쉽습니다. 가중치 기반 및 규칙 기반 트래픽 분할 방식 모두에 잘 작동합니다.

Tags: