TIL

Linkerd Canary 배포

하얀잔디 2026. 8. 17. 21:58
왜 했냐

최근 prod 쪽 채팅 읽기 관련 캐싱 로직을 손봤음. 근데 dev 환경은 Redis 샤딩 구성이 prod랑 달라서(dev는 샤딩 안 됨) 배포했을 때 사이드 이펙트가 터질지 확신이 안 섰음.

 

한 번에 100% 밀어넣긴 쫄려서 트래픽 조금만 먼저 태워보려고 canary 세팅을 해봄.

배경 파악

k3s 클러스터 보니까 dev 네임스페이스에 linkerd가 이미 떠 있길래 레포를 뒤져봄. 확인해보니 linkerd 설치랑 dev 네임스페이스 linkerd.io/inject 어노테이션이 레포엔 없고, 예전에 서버에서 수동으로 kubectl apply / annotate 때려둔 흔적이었음. GitOps 안 붙은 순수 kustomize 레포라 이런 드리프트가 종종 생김.

 

온 김에 canary 배포 환경까지 제대로 잡아둠. 참고로 Linkerd는 예전 SMI TrafficSplit 대신 요즘 Gateway API의 HTTPRoute로 트래픽 분할하는 방식을 씀. 다행히 클러스터에 Gateway API CRD가 이미 깔려있어서 별도 세팅 없이 바로 썼음.

 

보통 신규 API 추가면 클라이언트 버저닝 맞춰서 순차 오픈하면 되는데,

이번 건은

 

기존 API의 내부 캐싱/DB 처리 로직을 수정한 거라 기존 트래픽이 들어왔을 때 서버가 멀쩡히 버티는지

(서버 안정화 및 회귀 테스트) 사전 검증

 

이 필수였음.

 

한 번에 100% 밀어넣긴 쫄려서, 기존 트래픽 일부만 먼저 태워보고 Redis 커넥션이나 인프라 사이드 안정성을 확인하려고 canary 세팅을 해봄.

구성 방식


구조는 심플하게 잡음.

  • api-canary Deployment / Service 신규 생성 (기존 api는 그대로 유지)
  • api-stable Service 추가 (기존 stable pod 바라봄)
  • HTTPRoute 하나 물려서 api-stable: 90 / api-canary: 10 비율로 weight 분할

YAML

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-traffic-split
  namespace: uc-dev
spec:
  parentRefs:
    - group: ""
      kind: Service
      name: api
      port: 3000
  rules:
    - backendRefs:
        - name: api-stable
          port: 3000
          weight: 90
        - name: api-canary
          port: 3000
          weight: 10

 

클라이언트 코드는 수정할 필요 없이 기존처럼 http://api:3000 호출하면 됨. Mesh에 붙은 Linkerd proxy가 알아서 라우팅 규칙 보고 트래픽을 갈라줌.

 

이미지 태그 관리도 안 꼬이게 overlays/dev/api-canary 쪽 kustomization.yaml에서 canary 태그만 따로 관리하도록 분리해둠. 이러면 CI에서 stable 태그 자동 갱신할 때 canary가 덮어씌워질 일 없음.

 

 

써보고 느낀 점

  • linkerd-viz 대시보드 띄워놓고 stable / canary 성공률이랑 레이턴시 실시간 비교 가능.
  • 문제 없으면 weight 50 -> 100 올리고, 삐끗하면 canary Deployment만 바로 날려버리면 끝.
  • HTTPRoute의 matches.headers 쓰면 사내망 IP나 특정 헤더 달고 들어오는 요청만 canary로 먼저 태우는 A/B 테스트 형태도 가능함. 이건 다음 작업 때 써먹을 예정.