Blue/Green Deployment vs Canary Deployment
블루 그린 배포 #
블루/그린은 매우 직관적이다 현재 서비스중인 환경 BLUE와 완벽하게 동일한 인프라 환경 GREEN을 하나 더 구축해놓고 배포 시점에 로드밸런서의 스위치를 딸깍하고 100퍼센트 전환하는 방식이다
Zero-Downtime의 정석이라고 볼 수 있고 스위칭 순간에 세션이 끊기지 않도록 하는 Connection Draining (기존 요청은 끝까지 처리하고 새 요청만 green으로 전환) 설정만 잘 되어있다면 완벽한 무중단 배포가 가능하다.
Warm-up도 가능한데, 실사용자 트래픽을 넣기 전에, Green 환경에서 사내 테스트 트래픽을 흘려보내서 내부 도메인 사용이나 캐시를 미리 채워두거나 jvm jitcompiler 최적화등 최종 qa용으로도 사용할 수 있다.
단점은 비용인데 평소 100대의 서버로 운영한다면 배포를 위해 100대의 서버를 추가로 띄워야해서 클라우드 환경에서는 배포직후 blue를 바로 죽이면 비용을 아낄수있으나 on-promise나 그런환경에서는 하드웨어 비용이 2배로 든다.
카나리 배포 #
간 보는 방법으로 이해하면편한데, 과거 광부들이 유독가스를 탐지하기 위해 탄광에서 카나리아 새를 먼저 들여보냈던 것에서 유래했다.
신버전 서버 1대 또는 5%수준만 먼저 배포를 투입하고 일부 유저의 트래픽만 라우팅하여 에러율이나 지연시간이 튀는지 모니터링 한뒤 점진적으로 100%까지 늘린다.
Blast Radius(폭발 반경) 최소화가 가능한데 코드에 치명적인 버그가 있어도 전체유저 대상이아닌 5% 유저만 에러를 겪기 때문에 비즈니스 리스크를 극도로 줄이거나 에러버짓을 아낄 수 있다.
버전 혼재의 위험성이 있는데 현재 시스템에 구버전 신버전이 동시에 돌아간다. 만약 db스키마 변경이 되었거나 api 응답 스펙이 달라졌다면 클라이언트에서 v1 v2 모두 예외없이 처리할 수 있게 구현해놓고 100퍼센트 배포가 완료되면 구버전을 삭제치는 방식으로 운영하자.
세션 유지 필수다 유저 a가 새로고침할때마다 한번은 구버전 한번은 신버전으로 가면 데이터 정합성 혹은 ux에 큰 혼란이 올 수 있기에 한 번 카나리로 배정된 유저는 계속 신버전으로만 가도록 쿠키나 헤더기반의 라우팅 룰이 필요하다.
Example #
블루/그린 롤백 k8s service selector를 보겠다.
k8s 환경에서는 ingress나 로드밸런서를 건드릴 필요없이 트래픽을 연결하는 Service의 라벨타겟만 변경하여 트래픽을 100% 넘긴다.
# 1. 현재 구버전(Blue)을 바라보고 있는 Service 설정
apiVersion: v1
kind: Service
metadata:
name: my-backend-service
spec:
selector:
app: my-backend
version: v1.0 # <--- 현재는 Blue(v1.0) 파드들로 트래픽이 감
ports:
- port: 80
targetPort: 8080
kubectl patch service my-backend-service -p '{"spec":{"selector":{"version":"v2.0"}}}' 다른 방법들도 있게지만 직관적인 예시로 이런식으로 버전을 변경해줘 트래픽을 green v2로 향하게 해둘수있다.
카나리 배포도 nginx split_clients를 활용해서 트래픽 분산해볼건데
Nginx 자체 기능인 split_clients를 사용하여 유저의 ip 또는 세션 쿠키를 해싱해 5% 트래픽만 카나리 서버로 내보내는 구성이다.
http {
# 사용자 IP($remote_addr)를 기준으로 트래픽을 쪼갬
split_clients "${remote_addr}" $upstream_variant {
5% backend_canary; # 5%의 유저는 신버전으로
* backend_main; # 나머지 95%는 구버전으로
}
# 구버전 (Main) 서버 그룹
upstream backend_main {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
# 신버전 (Canary) 서버 그룹
upstream backend_canary {
server 10.0.1.99:8080; # 새로 배포된 서버 1대
}
server {
listen 80;
location / {
# 쪼개진 결과($upstream_variant)에 따라 트래픽 라우팅
proxy_pass http://$upstream_variant;
}
}
}
이 설정의 핵심은 remote_addr(사용자 ip)를 해싱한다는 것이다. 따라서 특정 유저 A는 언제 접속해도 항상 카나리로 가거나 항상 메인으로 가게 되어 세션 유지 문제가 어느정도 해결된다.
실무에서는 돈이 많거나, 서버가 그렇게 많지 않다면 블루/그린을 선호하고 최근에는 마이크로서비스와 k8s 환경에서 리소스를 낭비하지 않기위해서 istio, argocd같은 도구들로 자동화된 카나리 배포가 사실상 자주 쓰이는듯하다.