튜토리얼: Calico Ingress Gateway로 카나리아 배포 시작하기
Calico Ingress Gateway를 사용해 카나리아 배포를 만드는 방법을 단계별로 안내합니다. HTTPRoute 트래픽 분할로 안정 버전과 새 버전 사이에서 트래픽을 배분하는 방식으로, 실습 중심으로 따라 하며 배울 수 있는 튜토리얼입니다. kind 클러스터를 직접 만들어 끝까지 검증해 볼 수 있습니다.
출처: 문서
본문
이 튜토리얼은 Calico Ingress Gateway를 사용해 카나리아 배포를 만드는 방법을 보여 줍니다.
개요
카나리아 배포는 애플리케이션의 새 버전을 완전히 배포하기 전에 소수의 사용자에게 점진적으로 롤아웃하는 점진적 릴리스 전략입니다. 이 접근 방식을 사용하면 팀이 문제를 조기에 발견하고, 새 기능을 검증하고, 필요하면 빠르게 롤백해 대다수 사용자에게 미치는 영향을 최소화할 수 있습니다.
Calico에서는 카나리아 배포를 인그레스 게이트웨이와 연결된 라우팅 리소스에 정의된 트래픽 분할 방식으로 구현합니다. 라우팅 규칙을 정의해 들어오는 트래픽의 일부만 워크로드의 카나리아 버전으로 보내 테스트할 수 있으며, 나머지 대부분의 트래픽은 안정 버전으로 계속 흘러갑니다.
카나리아 버전에 대한 확신이 커지면 그 버전으로 향하는 트래픽 비중을 점진적으로 늘려, 결국 새 안정 버전이 되도록 합니다.
사용 사례
- 기능 롤아웃: 완전 배포 전에 새 기능을 소수의 사용자에게 안전하게 공개해 기능을 검증하고 피드백을 모읍니다.
- 성능 테스트: 모든 사용자에게 영향을 주지 않으면서 새 버전이 실제 트래픽과 리소스 사용을 어떻게 감당하는지 평가합니다.
- 버그 탐지: 사용자 영향을 최소화하면서 프로덕션의 치명적인 버그나 예기치 않은 동작을 잡아냅니다.
- A/B 테스트: 하나를 최종 선택하기 전에 서로 다른 버전을 비교해 성능, 사용자 참여, 전환율을 확인합니다.
- 컴플라이언스와 리스크 관리: 규제가 엄격하거나 미션 크리티컬한 환경에서 업데이트를 점진적으로 롤아웃해 광범위한 장애 가능성을 줄입니다.
카나리아 배포는 통제된 저위험 릴리스를 원할 때 이상적이며, 전면 롤아웃 전에 팀이 메트릭을 모니터링하고 가정을 검증하고 안정성을 확보할 수 있게 해 줍니다.
시작하기 전에
이 튜토리얼을 완료하려면 몇 가지 도구를 설치해야 합니다:
kind. 워크스테이션에 클러스터를 만들 때 사용합니다. 설치 지침은kind문서를 참고하세요.- Docker Engine 또는 Docker Desktop.
kind유틸리티의 컨테이너를 실행하는 데 필요합니다. 설치 지침은 Docker 문서를 참고하세요. kubectl. 클러스터와 상호작용할 때 사용하는 도구입니다. 설치 지침은 Kubernetes 문서를 참고하세요.
1단계: 환경 준비하기
이 튜토리얼에서는 Calico Open Source 3.33 이상이 설치된 클러스터에 접근할 수 있어야 합니다.
여기서는 kind로 이 환경을 만들지만, 호환되는 버전의 Calico를 사용하는 다른 지원 Kubernetes 배포판도 사용할 수 있습니다. 이미 적절한 환경이 있다면 2단계: 인그레스 게이트웨이 만들기부터 튜토리얼을 시작하세요.
-
컨트롤 플레인 노드 1개와 워커 노드 2개로
kind클러스터를 만듭니다.cat > config.yaml <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: worker networking: disableDefaultCNI: true podSubnet: 192.168.0.0/16 EOF kind create cluster --config config.yaml --name calico-clusterkind가 구성 파일을 읽어 몇 분 안에 클러스터를 만들어 줍니다.예상 출력
Creating cluster "calico-cluster" ... ✓ Ensuring node image (kindest/node:v1.33.1) 🖼 ✓ Preparing nodes 📦 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-calico-cluster" You can now use your cluster with: kubectl cluster-info --context kind-calico-cluster Thanks for using kind! 😊 -
클러스터가 잘 동작하는지 확인하려면 다음 명령을 실행합니다:
kubectl get nodes클러스터 이름이 붙은 세 개의 노드가 보여야 합니다.
예상 출력
NAME STATUS ROLES AGE VERSION calico-cluster-control-plane NotReady control-plane 5m46s v1.33.1 calico-cluster-worker NotReady <none> 5m23s v1.33.1 calico-cluster-worker2 NotReady <none> 5m22s v1.33.1다음 단계에서 네트워킹을 구성하기 전까지 노드는
NotReady상태로 남아 있습니다. -
커스텀 리소스 정의, Tigera Operator, 커스텀 리소스를 추가해 Calico Open Source를 설치합니다.
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.33.0/manifests/v1_crd_projectcalico_org.yaml kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.33.0/manifests/tigera-operator.yaml kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.33.0/manifests/custom-resources.yaml -
다음 명령으로 배포 상태를 모니터링합니다:
watch kubectl get tigerastatus몇 분 후 모든 Calico 컴포넌트가
AVAILABLE열에True로 표시됩니다.예상 출력
NAME AVAILABLE PROGRESSING DEGRADED SINCE apiserver True False False 4m9s calico True False False 3m29s goldmane True False False 3m39s ippools True False False 6m4s whisker True False False 3m19s
2단계. 인그레스 게이트웨이 만들기
GatewayAPI 리소스를 만들어 Gateway API를 활성화합니다. 이 리소스를 만들면 Tigera Operator가 Envoy Gateway 이미지를 가져와 환경을 구성합니다. 준비가 끝나면 Gateway와 라우팅 리소스 같은 지원되는 Gateway API 리소스를 만들 수 있습니다.
-
Gateway API 지원을 활성화하려면 이름이
default인GatewayAPI리소스를 만듭니다:kubectl apply -f - <<EOF apiVersion: operator.tigera.io/v1 kind: GatewayAPI metadata: name: default EOF잠시 후 Gateway API 리소스를 사용할 수 있게 된 것을 확인할 수 있습니다:
kubectl api-resources | grep gateway.networking.k8s.io예상 출력
backendlbpolicies blbpolicy gateway.networking.k8s.io/v1alpha2 true BackendLBPolicy backendtlspolicies btlspolicy gateway.networking.k8s.io/v1alpha3 true BackendTLSPolicy gatewayclasses gc gateway.networking.k8s.io/v1 false GatewayClass gateways gtw gateway.networking.k8s.io/v1 true Gateway grpcroutes gateway.networking.k8s.io/v1 true GRPCRoute httproutes gateway.networking.k8s.io/v1 true HTTPRoute referencegrants refgrant gateway.networking.k8s.io/v1beta1 true ReferenceGrant tcproutes gateway.networking.k8s.io/v1alpha2 true TCPRoute tlsroutes gateway.networking.k8s.io/v1alpha2 true TLSRoute udproutes gateway.networking.k8s.io/v1alpha2 true UDPRoute그리고 Calico에 포함된 Envoy Gateway 구현에 대응하는 GatewayClass 리소스도 존재하는지 확인할 수 있습니다:
kubectl get gatewayclass -o=jsonpath='{.items[0].spec}' | jq예상 출력
{ "controllerName": "gateway.envoyproxy.io/gatewayclass-controller", "parametersRef": { "group": "gateway.envoyproxy.io", "kind": "EnvoyProxy", "name": "tigera-gateway-class", "namespace": "calico-system" } } -
게이트웨이와 애플리케이션을 담을 네임스페이스를 만듭니다:
kubectl create namespace ingress-gateway-demo -
그 네임스페이스에서
tigera-gateway-class에 연결된Gateway리소스를 만듭니다. 프록시는Gateway와 같은 네임스페이스에서 실행됩니다.kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: canary-deployment-gateway namespace: ingress-gateway-demo spec: gatewayClassName: tigera-gateway-class listeners: - name: http protocol: HTTP port: 80 EOF게이트웨이를 사용하려는 모든 서비스에서 이 게이트웨이 이름을 참조하게 됩니다.
3단계. 애플리케이션의 v1(안정)과 v2(카나리아) 배포하기
트래픽 분할을 시연하려면 두 개의 서비스가 필요합니다. ingress-gateway-demo 애플리케이션의 두 버전, 즉 v1(안정)과 v2(카나리아 빌드)를 만듭니다. 앱은 한 줄짜리 HTML을 서빙하는 간단한 웹 서버입니다.
-
ingress-gateway-demo앱의 안정 버전을 배포합니다. 이 매니페스트 세트에는 다음이 포함됩니다:- ConfigMap(app-v1-html): 정적 index.html 파일(앱의 내용)을 저장합니다.
- Deployment(app-v1): BusyBox 컨테이너 레플리카 1개를 실행해 ConfigMap에 저장된 HTML 내용을 서빙합니다.
- Service(app-v1): 클러스터 안에서 접근할 수 있도록 BusyBox pod을 안정적인 내부 IP로 노출합니다.
cat << EOF | kubectl apply -f - apiVersion: v1 kind: ConfigMap metadata: name: app-v1-html namespace: ingress-gateway-demo data: index.html: | <html><body><h1>App Version 1</h1></body></html> --- apiVersion: apps/v1 kind: Deployment metadata: name: app-v1 namespace: ingress-gateway-demo spec: replicas: 1 selector: matchLabels: app: ingress-gateway-demo version: v1 template: metadata: labels: app: ingress-gateway-demo version: v1 spec: containers: - name: busybox image: busybox:latest command: ["sh", "-c", "httpd -f -p 80 -h /var/www/html"] ports: - containerPort: 80 volumeMounts: - name: html mountPath: /var/www/html volumes: - name: html configMap: name: app-v1-html --- apiVersion: v1 kind: Service metadata: name: app-v1 namespace: ingress-gateway-demo spec: selector: app: ingress-gateway-demo version: v1 ports: - port: 80 targetPort: 80 EOF예상 출력
configmap/app-v1-html created deployment.apps/app-v1 created service/app-v1 created -
이제 카나리아 빌드인 ingress-gateway-demo v2에 대해 동일한 리소스를 배포합니다:
cat << EOF | kubectl apply -f - apiVersion: v1 kind: ConfigMap metadata: name: app-v2-html namespace: ingress-gateway-demo data: index.html: | <html><body><h1>App Version 2</h1></body></html> --- apiVersion: apps/v1 kind: Deployment metadata: name: app-v2 namespace: ingress-gateway-demo spec: replicas: 1 selector: matchLabels: app: ingress-gateway-demo version: v2 template: metadata: labels: app: ingress-gateway-demo version: v2 spec: containers: - name: busybox image: busybox:latest command: ["sh", "-c", "httpd -f -p 80 -h /var/www/html"] ports: - containerPort: 80 volumeMounts: - name: html mountPath: /var/www/html volumes: - name: html configMap: name: app-v2-html --- apiVersion: v1 kind: Service metadata: name: app-v2 namespace: ingress-gateway-demo spec: selector: app: ingress-gateway-demo version: v2 ports: - port: 80 targetPort: 80 EOF예상 출력
configmap/app-v2-html created deployment.apps/app-v2 created service/app-v2 created
4단계: app-v1과 app-v2 사이에서 트래픽을 분할하는 HTTPRoute 리소스 정의하기
아래 HTTPRoute는 요청의 80%를 app-v1로, 20%를 app-v2로 라우팅합니다.
cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: traffic-splitting
namespace: ingress-gateway-demo
spec:
parentRefs:
- name: canary-deployment-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-v1
port: 80
weight: 80
- name: app-v2
port: 80
weight: 20
EOF
5단계. 카나리아 배포 테스트하기
이 튜토리얼에서는 로컬 워크스테이션으로 포트 포워딩해 게이트웨이를 통해 앱에 접근해 봅니다. 실제 환경에서는 로드 밸런서를 설정해 외부 트래픽을 전달하게 됩니다.
-
ingress-gateway-demo네임스페이스에서 실행되는 게이트웨이의 서비스로 포트 포워딩을 설정합니다:kubectl port-forward -n ingress-gateway-demo svc/canary-deployment-gateway 30135:80이제 웹 브라우저에서 http://localhost:30135로 앱에 접근할 수 있습니다.
-
이제 다른 터미널에서 앱에 접근해 각 버전이 얼마나 자주 사용되는지 확인하며 카나리아 빌드를 테스트할 수 있습니다:
for i in $(seq 200); do curl -s http://localhost:30135/ | grep "<h1>"; done | \ awk ' /App Version 1/ {v1++} /App Version 2/ {v2++} END { total=v1+v2 printf("Version 1: %d (%.1f%%)\nVersion 2: %d (%.1f%%)\n", v1, v1/total*100, v2, v2/total*100) }'샘플 출력
Version 1: 161 (80.5%) Version 2: 39 (19.5%)
6단계. 환경 정리하기
-
튜토리얼 환경을 정리하려면 다음 명령을 실행합니다:
kind delete cluster --name calico-cluster
더 알아보기 (Learn more)
HTTPRoute의 weight를 조절하면 트래픽 비중을 점진적으로 바꿀 수 있습니다. 이 튜토리얼의 패턴은 블루-그린 배포나 단계적 롤아웃에도 그대로 응용할 수 있습니다.