쿠버네티스(k8s)

[k8s] Kubernetes Canary 배포 삽질기

curiousKidd 2025. 4. 7. 22:28
반응형

최근에 Kubernetes에서 새로운 버전을 배포하면서 canary 트래픽 테스트를 해봤다.

기존 파드를 유지한 채로, 새로운 버전의 파드를 하나만 띄우고 인그레스에서 일부 트래픽만 넘기는 구조를 목표로 했는데, 생각보다 시행착오가 많았다. 아래는 그 과정에서 겪었던 실수들과 해결했던 방법들을 정리한 내용이다.


1. Deployment의 selector와 labels가 안 맞을 때

처음엔 아래와 같이 새로운 Deployment를 구성했다.

spec:
  selector:
    matchLabels:
      app: example-app-v2
      version: canary
  template:
    metadata:
      labels:
        app: example-app
        version: canary

이 구조는 바로 에러를 발생시켰다

The Deployment "example-app-v2" is invalid: spec.template.metadata.labels: Invalid value: {"app":"example-app"}: selector does not match template labels

여기서 중요한 포인트는 spec.selector.matchLabels와 template.metadata.labels가 완전히 일치해야 한다는 것이다. Deployment 이름은 어디까지나 메타데이터일 뿐, 실제 파드 선택 기준에는 영향을 주지 않는다.

올바른 예제

spec:
  selector:
    matchLabels:
      app: example-app
      version: canary
  template:
    metadata:
      labels:
        app: example-app
        version: canary

2. Deployment는 이름만 다르면 공존 가능할까?

기존 stable 버전의 Deployment가 돌아가고 있는데, canary용 Deployment를 추가로 붙이고 싶었다. 이때 궁금했던 건, 이름만 다르면 되는 건가?

답은 그렇다. 단, 라벨 충돌은 피해야 한다.

 

Deployment 리소스 자체는 이름만 다르면 공존이 가능하지만, 만약 selector.matchLabels가 기존 Deployment와 동일하면 충돌이 발생하고 아래와 같은 에러가 난다

selector conflicts with an existing deployment

그러므로 서로 다른 Deployment가 같은 파드를 선택하지 않도록, selector 기준을 명확히 나누는 게 중요하다.


3. 하나의 Service로 여러 버전의 Pod 관리하기

canary 구조에서는 stable 버전과 canary 버전이 하나의 Service를 공유하는 경우가 많다. 그러면 Service의 selector는 어떻게 잡아야 할까?

정답은: 공통되는 라벨 기준으로 구성하면 된다.

selector:
  app: example-app

이렇게 하면 app: example-app이라는 공통 라벨을 가진 모든 파드(stable + canary)를 대상으로 트래픽이 전달된다.

그 다음, Ingress에서 canary 관련 annotation을 추가해서 일부 트래픽만 canary 파드로 보내도록 설정한다

metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "20"

이때 중요한 건 canary 파드에는 반드시 version: canary 같은 구분 가능한 라벨이 붙어 있어야 한다는 점이다. 그래야 nginx ingress가 트래픽을 올바르게 분배할 수 있다.


마무리 정리

Kubernetes에서 canary 배포를 하다 보면 예상치 못한 디테일에서 막히는 경우가 많다. 특히 라벨과 selector 쪽이 헷갈리면 아예 Deployment 자체가 되지 않거나, 트래픽이 엉뚱하게 분배될 수 있다.

이번 경험을 통해 배운 점은 다음과 같다

  • Deployment의 이름은 단순한 구분용일 뿐, 라벨과 매칭에는 영향을 주지 않는다.
  • spec.selector.matchLabels와 template.metadata.labels는 반드시 완벽히 일치해야 한다.
  • Service는 공통된 라벨 기준으로 잡고, Ingress에서 canary 조건을 추가하면 된다.

한마디로 정리하면 "이름은 자유롭게, 라벨은 철저하게." 다음에 또 비슷한 상황이 생겼을 때 이 글이 도움이 되길 바란다.

반응형