Kubernetes 클러스터에서 Canary Release 결정 자동화하기

Chao Zhang

Chao Zhang

December 30, 2022

Technology

배경

오늘날, 마이크로서비스는 전형적이고 널리 사용되는 소프트웨어 아키텍처 패턴이 되었습니다. 서비스는 느슨하게 결합되어 있으며 API를 통해 협력합니다. 마이크로서비스 패턴은 각 애플리케이션을 독립적으로 배포하고 유지보수할 수 있게 하여 릴리스가 더 빈번해집니다. 우리 모두 알고 있듯이, 릴리스는 위험합니다. 새 버전에 버그가 있는지 알 수 없기 때문입니다. 그래서 사람들은 카나리 릴리스와 블루-그린 배포와 같은 전략을 사용하여 최신 버전을 점진적으로 출시하고 위험을 줄입니다.

카나리 릴리스는 트래픽을 안정 그룹과 카나리 그룹 두 가지 대상 서비스로 분할합니다. Apache APISIX와 같은 API 게이트웨이는 마이크로서비스 아키텍처를 API로 효율적이고 안전하게 노출시킵니다. 이는 카나리 릴리스 기능을 갖추고 있습니다. 일반적으로 트래픽을 분할하는 방법에는 두 가지가 있습니다: 가중치 기반 방식과 조건식 기반 방식입니다.

가중치 기반 방식

가중치 기반 방식

사용자는 카나리 그룹에 도달할 트래픽의 비율을 지정해야 합니다. 위 이미지에서 95%의 트래픽은 안정 서비스로 전달되고, 나머지 5%는 카나리 서비스로 전달됩니다.

조건식 기반 방식

조건식 기반 방식

요청 조건식 방식은 지정된 특성에 맞는 트래픽만 카나리 그룹에 도달하도록 합니다. 예를 들어, 요청 헤더 X-Debug와 그 실제 값을 가진 HTTP 요청만 카나리 서비스에 도달합니다.

카나리 릴리스 자동화

API 게이트웨이를 API 호출이나 대시보드를 통해 운영할 때, 트래픽 비율(가중치 기반 방식)이나 조건식(조건식 기반 방식)을 조정하는 데 시간 차이가 발생할 수 있습니다. 오늘날, 점점 더 많은 사용자가 Kubernetes를 사용하여 마이크로서비스를 오케스트레이션합니다. 새로운 서비스 버전이 생성되면 카나리 릴리스를 시작할 수 있을까요? 이 글에서는 API7 Cloud를 사용하여 Kubernetes 클러스터에서 카나리 릴리스를 자동화하는 방법을 보여드리겠습니다.

API7 Cloud란?

API7 Cloud는 어느 클라우드에서나 다중 위치에서 API를 대규모로 배포, 제어, 시각화 및 모니터링할 수 있는 SaaS 플랫폼입니다. API를 어디서나 실행하되 한 곳에서 관리하세요. API7 Cloud는 Apache APISIX를 API 게이트웨이로 사용하여 API를 효율적이고 안전하게 노출시킵니다.

API7 Cloud

API7 Cloud를 사용하려면 Docker 및 Kubernetes와 같은 인프라에 Apache APISIX를 배포해야 합니다. Cloud CLI를 사용하여 배포를 쉽게 할 수 있습니다.

# API7 Cloud 콘솔에서 액세스 토큰을 구성합니다.
cloud-cli configure --token {YOUR TOKEN}

# Apache APISIX(버전 2.15.1)를 apisix 네임스페이스에 1개의 복제본으로 배포합니다.
cloud-cli deploy kubernetes \
  --name my-apisix \
  --namespace apisix \
  --replica-count 1 \
  --apisix-image apache/apisix:2.15.1-centos

카나리 릴리스는 API7 Cloud의 내장 기능 중 하나입니다. 사용자는 콘솔을 통해 카나리 릴리스 규칙을 구성하거나 API7 Cloud Open API를 호출할 수 있습니다. 우리는 카나리 릴리스 결정을 자동화하는 것을 목표로 하므로 후자의 방법을 사용할 것입니다.

시나리오

Kubernetes 클러스터에 항상 오류 메시지를 반환하는 간단한 error-page 애플리케이션이 있다고 가정해 보겠습니다. 우리는 버전 2.0을 출시하고 카나리 릴리스 전략을 사용하여 릴리스 위험을 줄이고자 합니다. 더 나아가, 전체 프로세스를 자동화하고자 합니다. 따라서 Kubernetes 서비스 리소스의 변경을 모니터링한 다음 API7 Cloud Go SDK를 통해 API7 Cloud에 카나리 릴리스를 생성/수정하는 카나리 릴리스 컨트롤러를 생성합니다. 우리는 트래픽을 분할하기 위해 가중치 기반 방식만 사용합니다. Apache APISIX API 게이트웨이를 포함한 모든 컴포넌트는 Kubernetes에 배포되므로 다이어그램은 다음과 같습니다:

다이어그램

카나리 릴리스 컨트롤러는 서비스 변경을 감시하고 일부 주석에 따라 반응합니다. 구체적으로:

  • 서비스에 api7.cloud/published-service 주석이 포함되어 있으면, 카나리 릴리스 컨트롤러는 API7 Cloud에 애플리케이션을 생성하려고 시도합니다.
  • 서비스에 api7.cloud/published-canary-service 주석이 있으면, 카나리 릴리스 컨트롤러는 API7 Cloud에 카나리 릴리스 규칙을 설정하려고 시도하며, api7.cloud/published-service-canary-percentage 주석이 비율을 결정합니다.

이 컨트롤러는 자체적으로 완전하지는 않습니다(서비스가 삭제되면 애플리케이션을 삭제하지 않음), 하지만 자동화된 카나리 릴리스 프로세스를 보여주기에는 충분합니다.

시작해 봅시다!

Apache APISIX와 카나리 릴리스 컨트롤러를 배포하는 것으로 시작하겠습니다. 위에서 언급한 대로, Cloud CLI를 사용하여 Apache APISIX를 배포합니다. 또한 error-page 애플리케이션과 카나리 릴리스 컨트롤러를 배포하기 위한 두 개의 YAML 파일(error-page/manifest-v1.yaml 및 controller/manifest.yaml)이 있습니다.

  1. 다음 명령어를 실행하려면 사용 가능한 Kubernetes 클러스터를 준비하세요.
  2. 카나리 릴리스 컨트롤러는 API7 Cloud API를 호출하기 위해 액세스 토큰이 필요합니다. 이 문서에 따라 토큰을 가져와 K8s 시크릿에 저장합니다.
kubectl create namespace canary-release-demo
# error-page v1 버전을 배포합니다.
kubectl apply -f https://raw.githubusercontent.com/tokers/canary-release-automation-demo/main/error-page/manifest-v1.yaml -n canary-release-demo

# API7 Cloud 액세스 토큰을 저장할 K8s 시크릿을 생성합니다.
kubectl create secret generic api7-cloud --namespace canary-release-demo --from-literal token={Your Access Token}

# 카나리 릴리스 컨트롤러를 배포합니다.
kubectl apply -f https://raw.githubusercontent.com/tokers/canary-release-automation-demo/main/controller/manifest.yaml -n canary-release-demo

# 모든 워크로드가 정상인지 확인합니다.
kubectl get all -n canary-release-demo

프록시 확인

이 서비스를 주석을 달아 게시해 보겠습니다.

kubectl annotate service -n canary-release-demo error-page-v1 "api7.cloud/published-service=error-page"

카나리 릴리스 컨트롤러는 이 변경을 감시하고 API7 Cloud에 애플리케이션을 생성합니다. 이제 Apache APISIX에 접근하여 프록시가 정상인지 확인해 보겠습니다.

kubectl port-forward -n canary-release-demo service/apisix-gateway 10080:80
curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s

모든 것이 정상이라면 {"error": "injected by error_page service", "version": "v1"}을 볼 수 있습니다.

현재, 카나리 릴리스 컨트롤러는 애플리케이션에 "모든 것과 일치"하는 API를 생성하며, 호스트는 애플리케이션 이름(error-page)과 동일합니다.

V2 출시

error-page 애플리케이션의 버전 2를 출시하고자 합니다. 먼저, manifest-v2.yaml을 적용하여 버전 2를 배포합니다. error-page-v2 서비스에 카나리 릴리스 주석을 추가합니다.

kubectl apply -f https://raw.githubusercontent.com/tokers/canary-release-automation-demo/main/error-page/manifest-v2.yaml -n canary-release-demo

# 카나리 릴리스 컨트롤러에 error-page-v2에 대해 카나리 릴리스를 활성화하고 비율을 10%로 설정한다고 알립니다.
kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-canary-service=true" "api7.cloud/published-service-canary-percentage=10"

# 카나리를 시작합니다.
kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-service=error-page"

이제 Apache APISIX에 100개의 요청을 다시 보내고 일부 요청이 카나리 서비스 error-page-v2로 전달되었는지 확인해 보겠습니다.

kubectl port-forward -n canary-release-demo service/apisix-gateway 10080:80
for ((i=0; i<100; i++)); do
  curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
done

모든 것이 잘 되었다면 약 10%의 요청이 error-page-v2에 도달할 것입니다(Apache APISIX가 백엔드를 선택하는 내부 전략 때문에 정확히 10%는 아닐 수 있음).

롤백

버전 2가 불안정하다는 것을 발견하고 롤백하고자 합니다. 그 전에, 먼저 카나리를 중지해야 하므로 비율을 0으로 변경합니다. 그런 다음 Apache APISIX에 다시 요청을 보냅니다.

kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-service-canary-percentage=0" --overwrite
for ((i=0; i<100; i++)); do
  curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
done

이제 모든 요청이 error-page-v1로 전달되는 것을 볼 수 있습니다.

출시

오랜 시간이 지난 후, 버전 2가 충분히 안정적이라고 판단하고 모든 요청이 버전 2에 도달하도록 하고자 합니다. 그런 다음 버전 1 error-page 애플리케이션을 오프라인으로 전환할 수 있습니다. 따라서 비율을 100%로 변경합니다.

kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-service-canary-percentage=100" --overwrite
for ((i=0; i<100; i++)); do
  curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
done

이제 모든 요청이 error-page-v2로 프록시됩니다. 그리고 error-page-v1은 안전하게 오프라인으로 전환할 수 있습니다.

요약

카나리 릴리스는 릴리스에 효과적인 무기입니다. 그러나 카나리 릴리스 전략을 조정하는 것은 지연될 수 있습니다. 이 글은 카나리 릴리스를 선언적으로 운영하고 어느 정도 자동화하는 방법을 보여줍니다. 일부 사람들은 GitOps 컴포넌트를 사용하여 완전히 자동화된 카나리 릴리스를 추구할 수 있습니다. 예를 들어, Argo Rollouts를 사용하면 서비스 메트릭을 쿼리하고 인그레스 컨트롤러와 통합하여 CRD를 변경할 수 있습니다. 궁극적으로, API 게이트웨이는 요청을 올바른 비율로 카나리 버전에 전달할 것입니다.

참고 자료

error-page 및 카나리 릴리스 컨트롤러의 소스 코드: https://github.com/tokers/canary-release-automation-demo.

Tags: