-
Notifications
You must be signed in to change notification settings - Fork 1
5) Traffic Management with NGINX Ingress Controller
2022.04. 이장재 📧 [email protected] 📂 https://github.com/jangjaelee 📒 http://www.awx.kr
Argo Rollouts의 트래픽 관리(Traffic Management) 기능을 사용하면 Ingress Object를 통해 Pod에 직접 라우팅을 할 수 있으며, Ingress Controller에서 지원하는 기능에 따라 다음의 트래픽 관리 기술을 구현 할 수 있습니다.
- Weight-based routing (가중치 기반)
- Header-based routing (헤더 기반)
- Mirrored traffic (트래픽 복제)
본 문서에서는 NGINX Ingress Controller를 사용할 때 트래픽 관리 기능이 어떻게 동작 하는지 알아봅니다.
- kubectl command-line tool
- Argo Rollouts Kubectl Plugin
- NGINX Ingress Controller
트래픽 관리 기능을 사용하면 Service Mesh와 Ingress를 사용하여 트래픽 라우팅을 조작 할 수 있습니다. 즉, Servie Mesh와 Ingress의 Controller에서 제공하는 기능으로 Data Plane을 제어하게 됩니다.
NGINX Ingress Controller를 사용하여 두 개의 Ingress Object를 사용하여 가중치 기반(weight-based)으로 트래픽을 라우팅 하도록 하는 아키텍처 입니다.
NGINX Ingerss Controller는 몇 가지 annotations을 사용하여 두 개의 Ingress Object 간에 트래픽을 분할하는 기능을 제공하며 이를 사용 하여 Canary 배포 전략을 구현 할 수 있습니다. Canary annotations의 자세한 설명은 아래 링크를 참조하시기 바랍니다.
-
for Canary annotation of NGINX Ingress Controller
🔗 https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary
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
위 단계에서 이미 언급을 하였듯이 Ingress Suffix는 <rollout name>-<ingress name>-canary
의 이름으로 생성됩니다.
그렇다면 왜 접미사로 -canary
가 붙고 이름 규칙이 <rollout name>-<ingress name>
가 되는지 소스파일 분석을 통해 알아보겠습니다.
-
https://github.com/argoproj/argo-rollouts/blob/master/rollout/trafficrouting/nginx/nginx.go
Traffic Management의 NGINX 사용시 Ingress Suffix의 이름을 호출하는 함수로
GetCanaryIngressName
가 사용되었네요.GetCanaryIngressName
함수는 ingress.go 파일에 정의 되어 있습니다. -
https://github.com/argoproj/argo-rollouts/blob/master/utils/ingress/ingress.go
CanaryIngressSuffix
상수의 값으로-canary
를 사용하며 상수이기 때문에 접미사로 사용되는 값은 변하지 않는 것을 알 수 있습니다.GetCanaryIngressName
함수 내용을 보면<rollout name>-<ingress name>-canary
의 이름 규칙인 것이 확인됩니다.
- Website
- GitHub
- Artifact Hub
- Slack
- https://github.com/argoproj/argo-rollouts/blob/master/rollout/trafficrouting/nginx/nginx.go
- https://github.com/argoproj/argo-rollouts/blob/master/utils/ingress/ingress.go
- https://github.com/argoproj/argo-rollouts/blob/master/utils/ingress/wrapper.go
- https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary
END