Skip to content

5) Traffic Management with NGINX Ingress Controller

Alex, Lee edited this page Apr 21, 2022 · 2 revisions

2022.04. 이장재 📧 [email protected] 📂 https://github.com/jangjaelee 📒 http://www.awx.kr


 

Overview

Argo Rollouts의 트래픽 관리(Traffic Management) 기능을 사용하면 Ingress Object를 통해 Pod에 직접 라우팅을 할 수 있으며, Ingress Controller에서 지원하는 기능에 따라 다음의 트래픽 관리 기술을 구현 할 수 있습니다.

  • Weight-based routing (가중치 기반)
  • Header-based routing (헤더 기반)
  • Mirrored traffic (트래픽 복제)

본 문서에서는 NGINX Ingress Controller를 사용할 때 트래픽 관리 기능이 어떻게 동작 하는지 알아봅니다.


Prerequisites


Step 1. using NGINX Ingress Controller with Argo Rollouts

트래픽 관리 기능을 사용하면 Service Mesh와 Ingress를 사용하여 트래픽 라우팅을 조작 할 수 있습니다. 즉, Servie Mesh와 Ingress의 Controller에서 제공하는 기능으로 Data Plane을 제어하게 됩니다.

NGINX Ingress Controller를 사용하여 두 개의 Ingress Object를 사용하여 가중치 기반(weight-based)으로 트래픽을 라우팅 하도록 하는 아키텍처 입니다.

TrafficManagement_with_NGINX-Ingress-Controller.png

NGINX Ingerss Controller는 몇 가지 annotations을 사용하여 두 개의 Ingress Object 간에 트래픽을 분할하는 기능을 제공하며 이를 사용 하여 Canary 배포 전략을 구현 할 수 있습니다. Canary annotations의 자세한 설명은 아래 링크를 참조하시기 바랍니다.

Argo Rollouts을 NGINX Ingress Controller와 함께 사용했을때 트래픽에 대해 Canary Strategy이 어떻게 구현되는지 Demo Application을 배포하면서 알아보겠습니다.

$ git clone https://github.com/jangjaelee/tutorials-argo-rollouts.git
$ cd tutorials-argo-rollouts/demo/nginx
$ kubectl apply -f canary-rollout.yaml -f canary-service.yaml -f canary-ingress.yaml
rollout.argoproj.io/nginx-demo created
service/nginx-demo-stable created
service/nginx-demo-canary created
ingress.networking.k8s.io/nginx-demo-stable created

$ kubectl argo rollouts get rollout nginx-demo -w
Name:            nginx-demo
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          6/6
  SetWeight:     100
  ActualWeight:  100
Images:          argoproj/rollouts-demo:green (stable)
Replicas:
  Desired:       3
  Current:       3
  Updated:       3
  Ready:         3
  Available:     3

NAME                                     KIND        STATUS     AGE    INFO
⟳ nginx-demo                            Rollout     ✔ Healthy  3m34s
└──# revision:1
   └──⧉ nginx-demo-56c5b564df           ReplicaSet  ✔ Healthy  180s   stable
      ├──□ nginx-demo-56c5b564df-nznsq   Pod         ✔ Running  180s   ready:1/1
      ├──□ nginx-demo-56c5b564df-r995z   Pod         ✔ Running  180s   ready:1/1
      └──□ nginx-demo-56c5b564df-sgj22   Pod         ✔ Running  180s   ready:1/1

컨테이너 이미지 tag가 greeen으로 된 애플리케이션을 배포 했습니다.

$ kubectl get all,rollout,ingress
NAME                              READY   STATUS              RESTARTS   AGE
pod/nginx-demo-56c5b564df-nznsq   1/1     Running             0          180s
pod/nginx-demo-56c5b564df-r995z   1/1     Running             0          180s
pod/nginx-demo-56c5b564df-sgj22   1/1     Running             0          180s

NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP   37d
service/nginx-demo-canary   ClusterIP   10.98.207.120   <none>        80/TCP    210s
service/nginx-demo-stable   ClusterIP   10.106.210.33   <none>        80/TCP    210s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-demo-56c5b564df   3         3         3       193s

NAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
rollout.argoproj.io/nginx-demo   3         3         3            3           214s

NAME                                                            CLASS   HOSTS                ADDRESS   PORTS   AGE
ingress.networking.k8s.io/nginx-demo-nginx-demo-stable-canary   nginx   canary-demo.awx.kr             80      193s
ingress.networking.k8s.io/nginx-demo-stable                     nginx   canary-demo.awx.kr             80      210s

생성된 리소스들을 중에 ingress를 보면 nginx-demo-stable Ingress Obejct 한개가 아닌 nginx-demo-nginx-demo-stable-canary Ingress Object가 추가로 생성 되었습니다.

canary-ingress.yaml 파일의 내용을 확인하면 분명히 ingress를 한 개만 생성하게 명시되어 있는데 왜 두 개가 생성 되었을까요?

Roullout object spec 보면 안에 해답이 있습니다.

$ kubectl get rollouts nginx-demo -o=jsonpath='{.spec.strategy.canary.trafficRouting}' | jq
{
  "nginx": {
    "additionalIngressAnnotations": {
      "nginx.ingress.kubernetes.io/backend-protocol": "HTTP"
    },
    "stableIngress": "nginx-demo-stable"
  }
}

Rollout은 .spec.strategy.canary.trafficRouting.nginx.stableIngress에 명시한 nginx-demo-stable와 일치하는 ingress를 찾아 동일한 namespace에 ingress를 자동으로 복제하게 되며, Ingress Suffix는 <rollout name>-<ingress name>-canary의 이름으로 생성됩니다.

이렇게 복제되어 생성된 ingress는 Canary Traffic Split을 위해 사용되며, NGINX Ingress Controller의 annotations에 canary 사용 활성화를 명시 합니다.

$ kubectl get ingress/nginx-demo-nginx-demo-stable-canary -o=jsonpath='{.metadata.annotations}' | jq
{
  "nginx.ingress.kubernetes.io/backend-protocol": "HTTP",
  "nginx.ingress.kubernetes.io/canary": "true",      ## canary 활성화
  "nginx.ingress.kubernetes.io/canary-weight": "0"   ## canary-weight "0 to 100"
}

Canary Update를 하지 않으면 nginx.ingress.kubernetes.io/canary-weight는 기본값인 0을 유지하며 해당 ingress로는 트래픽을 라우팅 하지 않습니다.

이제 새 버전의 애플리케이션으로 Canary Update를 해보고 트래픽 라우팅의 변화가 어떻게 되는지 확인 해보겠습니다.

그전에 Rollout에서 새 애플리케이션에 트래픽 라우팅 비율은 어떻게 되는지 확인하면 다음과 같습니다.

$ kubectl get rollouts nginx-demo -o=jsonpath='{.spec.strategy.canary.steps}' | jq
[
  {
    "setWeight": 30
  },
  {
    "pause": {
      "duration": 3
    }
  },
  {
    "setWeight": 60
  },
  {
    "pause": {
      "duration": 3
    }
  },
  {
    "setWeight": 90
  },
  {
    "pause": {
      "duration": 3
    }
  }
]

canary strategy는 총 3단계로 분류되며,

  • 첫번째로 새 애플리케이션을 새성하고 가중치 30%의 트래픽 비율로 전달하고, 업데이트를 10초 정지
  • 두번째 애플리케이션을 생성하고 새 애플리케이션들에 가중치 60%의 트래픽 비율로 전달하고, 업데이트를 10초 정지
  • 마지막 새 애플리케이션을 생성하고 가중치 90%의 트래픽 비율로 전달 및 업에티르를 10초 정지 후
  • 나머지 10% 트래픽을 모든 새 애플리케이션에 전달하고 업데이트를 완료하게 됩니다.
$ kubectl argo rollouts set image nginx-demo "*=argoproj/rollouts-demo:orange"
rollout "nginx-demo" image updated

canary ingress가 앞서 명시한 트래픽 비율로 라우팅이 되고 있는지 확인하겠습니다.

$ for i in {1..4}; do kubectl get ing/nginx-demo-nginx-demo-stable-canary -o yaml | grep ' nginx.ingress.kubernetes.io/canary' | sed 's/ //g'; echo -e ""; sleep 3; done

nginx.ingress.kubernetes.io/canary:"true"
nginx.ingress.kubernetes.io/canary-weight:"0"

nginx.ingress.kubernetes.io/canary:"true"
nginx.ingress.kubernetes.io/canary-weight:"30"

nginx.ingress.kubernetes.io/canary:"true"
nginx.ingress.kubernetes.io/canary-weight:"60"

nginx.ingress.kubernetes.io/canary:"true"
nginx.ingress.kubernetes.io/canary-weight:"60"

nginx.ingress.kubernetes.io/canary:"true"
nginx.ingress.kubernetes.io/canary-weight:"90"
$ kubectl argo rollouts get rollout nginx-demo -w
Name:            nginx-demo
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          6/6
  SetWeight:     100
  ActualWeight:  100
Images:          argoproj/rollouts-demo:orange (stable)
Replicas:
  Desired:       3
  Current:       3
  Updated:       3
  Ready:         3
  Available:     3

NAME                                    KIND        STATUS        AGE  INFO
⟳ nginx-demo                            Rollout     ✔ Healthy     46m
├──# revision:2
│  └──⧉ nginx-demo-78f444847d           ReplicaSet  ✔ Healthy     72s  stable
│     ├──□ nginx-demo-78f444847d-q2nss  Pod         ✔ Running     72s  ready:1/1
│     ├──□ nginx-demo-78f444847d-p472x  Pod         ✔ Running     65s  ready:1/1
│     └──□ nginx-demo-78f444847d-jg2m2  Pod         ✔ Running     59s  ready:1/1
└──# revision:1
   └──⧉ nginx-demo-56c5b564df           ReplicaSet  • ScaledDown  45m

Step 2. Source Code로 보는 Canary Ingress Name Suffix

위 단계에서 이미 언급을 하였듯이 Ingress Suffix는 <rollout name>-<ingress name>-canary의 이름으로 생성됩니다.

그렇다면 왜 접미사로 -canary가 붙고 이름 규칙이 <rollout name>-<ingress name>가 되는지 소스파일 분석을 통해 알아보겠습니다.

 

Official Website

 

Reference

 

END