카나리 배포란? 개발자를 위한 실전 가이드

요약

카나리 배포는 새 버전을 전체 트래픽의 1%에서 5% 정도에만 먼저 보내는 배포 방식입니다. 기존 버전과 오류율, 응답 시간을 비교해 괜찮으면 비율을 늘리고, 문제가 있으면 가중치를 0으로 되돌립니다. 나쁜 릴리스의 피해를 줄여 주지만, 버전별 지표와 충분한 트래픽이 있어야 제대로 작동합니다.

카나리아 피규어가 놓인 어두운 개발자 책상, 트래픽 그래프 대시보드가 보이는 야간 풍경

카나리 배포란 새 버전의 앱을 실제 사용자 일부에게만 먼저 공개하는 배포 방식입니다. 보통 전체 트래픽의 1%에서 5% 정도만 새 버전으로 보내고, 나머지는 기존 버전에 그대로 둡니다. 그 작은 구간에서 오류율과 응답 시간을 지켜보다가 상태가 괜찮으면 비율을 올리고, 나쁘면 트래픽을 다시 기존 버전으로 돌립니다. 대부분의 사용자는 문제가 있었는지도 모른 채 지나가게 됩니다. 이 글은 그 아이디어가 실제로 돌아가게 만드는 방법을 다룹니다.

탄광 카나리아 이름의 유래를 보여 주는, 작업대 위의 낡은 광부 랜턴과 빈 새장

왜 카나리라는 이름이 붙었을까?

탄광에서 광부들은 카나리아를 데리고 들어갔습니다. 새가 유독 가스에 사람보다 먼저 반응했기 때문입니다. 노래를 멈춘 카나리아가 나가라는 신호였죠. 배포에서도 같은 역할을 하는 작은 사용자 그룹이 가장 먼저 새 코드를 만납니다. 그들이 조기 경보 역할을 합니다. CNCF 용어집은 이를 두 개의 환경으로 설명합니다. 하나는 실시간 트래픽을 처리하고, 다른 하나는 업데이트된 코드를 돌립니다. 트래픽은 1% 같은 작은 비율에서 시작해 점진적으로 옮겨 갑니다.

실무에서 핵심은 이겁니다. 카나리 사용자는 진짜 사용자입니다. 스테이징 환경으로는 이것을 재현할 수 없어요. 운영 환경에는 이상한 브라우저, 꼬인 캐시, 40MB짜리 가져오기 파일을 올리는 고객이 있습니다. 카나리는 모든 사용자가 버그를 만나기 전에, 그 상황들을 먼저 겪어 보는 방법입니다.

카나리 배포는 실제로 어떻게 동작하나요?

구성 요소는 네 가지입니다. 특별할 것은 없어요.

전형적인 확대 순서는 1%, 5%, 25%, 50%, 100%이고, 각 단계마다 잠시 멈춥니다. Google Cloud Deploy도 같은 구조를 문서화합니다. 비율 단계를 정의하면 도구가 트래픽을 나눠 줍니다. 문서의 예시는 25%, 50%, 75% 단계를 거친 뒤 최종 stable로 넘어가는 흐름입니다. Cloud Deploy 카나리 문서에 따르면 각 단계에서 검증 작업과 분석 단계를 돌려, 다음 단계로 넘어갈지 결정할 수도 있습니다.

완벽한 구성일 필요는 없습니다. 실행 가능한 구성이면 충분해요. Kubernetes가 없어도 됩니다. nginx의 가중치 라우팅, 쿠키를 보고 트래픽을 나누는 Cloudflare Worker, 프록시 뒤에 둔 Fly.io 머신 두 대도 모두 해당됩니다.

트래픽 분할 설정은 어떻게 생겼나요?

가장 단순한 예시는 nginx upstream에 가중치를 준 설정입니다. 요청 열 번 중 아홉 번은 stable로, 한 번은 카나리로 갑니다.

upstream app {
    server 10.0.0.10:3000 weight=9;   # stable
    server 10.0.0.11:3000 weight=1;   # canary
}

여기에는 알아 둘 약점이 있습니다. 분할이 요청 단위로 이뤄지기 때문에, 한 사용자가 연속으로 클릭할 때 버전 사이를 오갈 수 있습니다. 새 버전이 API 응답 형태나 데이터베이스 컬럼을 바꿨다면 그 사용자는 곤란을 겪게 됩니다. 쿠키나 사용자 ID 기준으로 같은 버전에 고정하는 스티키 라우팅이 이 문제를 해결합니다. 기본 분할이 돌아가기 시작하면 가장 먼저 붙일 기능입니다.

안정 버전과 카나리 버전의 지표가 갈라지는 모습을 보여 주는 노트북 화면

카나리가 도는 동안 무엇을 봐야 하나요?

카나리를 지난주 지표와 비교하지 말고, 같은 시각의 stable과 비교하세요. 지난주에는 트래픽 패턴이 달랐습니다. 질문은 늘 하나입니다. 지금 나머지 95%를 처리하는 버전보다 카나리가 나쁜가요?

작은 팀에서 가장 흔한 실수는 타이머에 맞춰 올리는 것입니다. 1%에서 5분, 그다음 25%, 그래프가 뭐라고 하든 상관없이요. 트래픽이 적으면 1%에서 5분 동안 요청이 여섯 개일 수도 있습니다. 그러면 아무것도 알 수 없어요. 분 단위가 아니라 최소 요청 수를 기다리세요. 트래픽이 실제로 생긴 뒤에는 이런 모니터링을 자동화 도구로 보완하는 것도 고려할 만합니다.

카나리와 블루-그린 중 무엇을 고를까요?

블루-그린은 환경을 두 벌 두고 트래픽을 한 번에 전환합니다. 롤백은 다시 전환하는 것이라 빠르고 깔끔합니다. 대신 전환 순간에는 모든 사용자가 새 버전을 쓰게 되고, 전환하는 동안 인프라 비용이 두 배가 됩니다.

카나리는 일부에게만 노출하므로 영향 범위가 작습니다. 대신 트래픽 가중치, 버전별 지표, 판단 기준이 필요해서 복잡합니다. 롤백은 카나리 가중치를 0으로 돌리는 것인데, 연결을 비워야 하는 경우 즉시 끝나지는 않습니다. 빠르지만 순간 이동은 아니에요.

카나리를 고를 이유는 세 가지, 말리는 이유는 한 가지입니다. 운영 버그의 비용이 클 때, 작은 구간도 의미가 있을 만큼 트래픽이 충분할 때, 버전별로 지표를 비교할 수 있을 때 카나리를 쓰세요. 하루 사용자가 몇십 명뿐이라면 카나리 구간은 통계적으로 비어 있을 테니, 결국 짐작으로 판단하게 됩니다. 그 규모에서는 블루-그린이나, 빠른 롤백 스크립트를 갖춘 일반 배포가 솔직한 답입니다.

롤링 업데이트는 그 중간에 있습니다. 인스턴스를 하나씩 교체해서 부드럽지만, 통제된 실험은 아닙니다. 누가 새 버전을 보게 될지 고를 수 없고, 집단을 나눠 비교할 수도 없어요.

피처 플래그는 어디에 들어가나요?

카나리 배포는 코드 버전 사이에서 트래픽을 나누고, 피처 플래그는 한 버전 안에서 동작을 나눕니다. 둘을 헷갈리면 비용이 큽니다.

새 코드를 모두에게 배포하되, 기본값이 꺼진 플래그 뒤에 숨깁니다. 그다음 플래그를 1%, 10%, 전체 순서로 켭니다. 이것도 흔히 기능 단위의 카나리 릴리스라고 부릅니다. 장점은 롤백이 재배포 없이 플래그를 끄는 것이라는 점입니다. 단점은 쓰지 않는 코드 경로가 모든 사용자의 운영 환경에 남고, 방치된 플래그가 기술 부채가 된다는 점입니다.

1인 개발자에게는 플래그가 보통 더 저렴한 첫 단계입니다. 설정 테이블의 불리언 값 하나와 사용자 ID 해시만으로도 가치의 80%를 얻을 수 있어요. 규모가 커지면 관리형 서비스가 타깃팅, 감사 로그, 점진적 비율 롤아웃을 대신해 줍니다.

트래픽 일부를 새 버전으로 옮기는 느낌을 주는, 살짝 돌려 놓은 다이얼

실제 프로젝트에서 카나리는 어디서 깨지나요?

직접 해 보고 나서 알게 된 실패들입니다. 실제로 발목을 잡는 것들만 골랐어요.

데이터베이스 마이그레이션. 두 버전이 같은 데이터베이스에 동시에 접근합니다. 카나리가 컬럼을 삭제하거나 이름을 바꾸면 stable이 깨집니다. 해결책은 확장 후 축소(expand and contract) 패턴입니다. 새 컬럼을 먼저 추가하고, 두 형태를 모두 처리하는 코드를 배포한 뒤, 이전 컬럼은 나중 릴리스에서 제거하세요. 이를 건너뛰면 카나리가 stable을 쓰러뜨립니다.

상태를 가진 세션. 세션이 한 인스턴스의 메모리에 있다면, 버전 사이를 오간 사용자는 로그아웃됩니다. 카나리를 시도하기 전에 세션 상태를 공유 저장소로 옮기세요.

캐시 오염. 다른 형식의 캐시를 쓰는 새 버전이 구 버전이 읽는 값을 망가뜨릴 수 있습니다. 캐시 키에 버전을 넣으세요.

백그라운드 작업. 카나리도 큐 메시지를 가져갑니다. 버그가 있는 워커는 트래픽 비율과 무관하게 작업을 최고 속도로 소진할 수 있어요. 카나리에 별도 큐나 컨슈머 가중치를 주세요.

아무도 연결하지 않은 알림. 카나리는 아무도 열어 보지 않는 대시보드에서 조용히 실패할 수 있습니다. 임계값을 넘으면 자동으로 중단되는 쪽이, 사람이 지켜보는 것보다 낫습니다. 특히 새벽 2시 서울에서 깨어 있는 사람이 배포한 본인뿐일 때 그렇습니다.

1인 사이드 프로젝트에서 카나리를 어떻게 시작하나요?

생각보다 작게 시작하세요. 여러분은 플랫폼 팀이 아니라 한 명의 개발자입니다.

  1. 모든 지표에 버전 라벨을 붙이세요. 헤더와 로그에 git SHA를 넣으세요. 이게 없으면 카나리와 stable을 비교할 방법이 없습니다.

  2. 중단 기준 하나만 정하세요. 예를 들어 카나리의 오류율이 stable의 2배를 5분 넘게 유지하면 롤백합니다. 규칙은 하나면 충분하고, 글로 적어 두세요.

  3. 가중치 라우팅을 추가하세요. nginx 가중치, Cloudflare 규칙, 또는 호스팅 서비스의 트래픽 분할 기능이면 됩니다. 요즘은 대부분의 관리형 플랫폼이 추가 도구 없이 비율 기반 라우팅을 제공합니다.

  4. 평범한 변경부터 배포하세요. 가격 페이지 전면 개편이 아니라 문구 하나를 바꾸세요. 아무것도 걸려 있지 않을 때 확대와 롤백을 연습하는 겁니다.

  5. 롤백 시간을 재세요. 한 번은 실제로 실행해 보세요. 10분을 헤맨다면 고칠 대상은 확대 단계가 아니라 롤백입니다.

아직 누가 돈을 낼지 찾는 단계라면 이 방식은 미뤄도 됩니다. 평범하게 배포하고 롤백 스크립트를 준비해 두세요. 장애가 실제 고객을 잃게 만드는 시점이 오면 그때 카나리로 돌아오면 됩니다. 이미 그 단계라면 가중치 라우팅과 중단 기준 하나면 주말 작업으로 끝납니다. 나쁜 릴리스가 100%가 아니라 1%에서 멈추는 것만으로도 충분히 본전을 뽑습니다.

모든 것을 카나리로 배포해야 할까요?

아니요. 설정 변경, 문구 수정, 푸터 오타 고치기에는 확대 과정이 필요 없습니다. 틀렸을 때 돈이나 신뢰를 잃는 변경에만 카나리를 쓰세요. 결제, 인증, 데이터 모델, 핫 패스를 건드리는 변경 같은 것들입니다. 모든 커밋에 1시간짜리 확대 과정을 붙이면, 누군가 급할 때 우회하게 되고, 우회되는 프로세스는 아예 없는 것보다 나쁩니다.

그러면 다음 릴리스에서 가장 위험한 변경은 무엇이고, 그것을 1% 사용자에게 먼저 보내려면 무엇이 필요할까요?

자주 묻는 질문

카나리 배포란 쉽게 말해 무엇인가요?
새 버전이 먼저 실제 사용자 일부에게만 서비스하고, 나머지는 기존 버전을 계속 씁니다. 지표가 건강하면 그 비율이 늘어 모든 사용자에게 도달하고, 지표가 나빠지면 트래픽이 stable 버전으로 돌아갑니다.
카나리는 트래픽 몇 %에서 시작해야 하나요?
많은 팀이 1%에서 5% 정도로 시작합니다. 적절한 값은 트래픽 규모에 따라 다릅니다. 구간에서 오류율과 응답 시간을 비교할 만큼 요청이 나와야 합니다. 트래픽이 매우 적다면 고정된 분 수 대신 최소 요청 수를 기다리세요.
카나리와 블루-그린 배포의 차이는 무엇인가요?
블루-그린은 환경 두 벌을 두고 트래픽을 한 번에 전환하므로 롤백은 다시 전환하는 것입니다. 카나리는 트래픽을 점진적으로 옮기기 때문에 나쁜 릴리스에 노출되는 사용자가 적지만, 트래픽 가중치와 버전별 모니터링이 필요합니다.
카나리 배포는 피처 플래그와 같은가요?
아니요. 카나리는 배포된 두 코드 버전 사이에서 트래픽을 나눕니다. 피처 플래그는 한 버전 안에서 기능을 켜거나 끕니다. 둘은 잘 결합됩니다. 플래그 뒤에 기능을 꺼 둔 채 배포한 뒤, 일부 사용자에게만 켜면 됩니다.
카나리 배포를 하려면 Kubernetes가 필요한가요?
아니요. nginx의 가중치 업스트림, CDN이나 엣지 규칙, 관리형 호스트의 트래픽 분할로도 가능합니다. Kubernetes 도구는 단계 확대와 자동 분석을 쉽게 해 주지만 필수는 아닙니다.
카나리에서 데이터베이스 마이그레이션은 어떻게 하나요?
두 버전이 하나의 데이터베이스를 공유하므로 확장 후 축소 패턴을 씁니다. 새 컬럼을 먼저 추가하고, 두 형태를 모두 다루는 코드를 배포한 뒤, 이전 컬럼은 나중 릴리스에서 제거합니다.