LabHub
배우기 러닝패스 코스

CI/CD Pipelines

Blue-Green Switchover and Canary Analysis

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

이 실습은 진짜 VM 에서 돕니다

이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이 따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라 진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가 되고 docker execdocker logs 도 그대로 동작합니다.

예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라 컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어 보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.

알아 둘 것이 둘 있습니다.

목표

컨테이너 두 개로 블루그린 환경을 만들고, 트래픽 전환·헬스체크·자동 롤백·카나리 비율 분배·자동 중단 판정을 셸로 구현한다.

왜 중요한가

배포 전략의 차이는 결국 롤백 속도와 트래픽 제어 정밀도의 교환이다. 블루그린은 두 환경을 동시에 띄우므로 리소스가 Pod 2배로 들지만 문제가 보이면 트래픽을 통째로 즉시 되돌릴 수 있다. 카나리는 1% 단위로 정밀하게 노출하지만 되돌릴 때 단계가 필요하다. 그래서 대부분의 서비스에는 카나리를, 결제나 인증처럼 한 건의 오류도 비용이 큰 서비스에는 블루-그린을 쓴다. 이 실습에서 활성 대상은 파일 한 줄로 표현된다. 그 한 줄을 누가 언제 바꾸고, 바꾼 뒤 무엇을 확인하고, 확인이 실패하면 어떻게 되돌리는지가 배포 자동화의 전부다.

단계

  1. 응답 본문에 version=blue 가 들어가는 컨테이너를 이름 ci3-blue 로 띄우고 127.0.0.1:8091 로 게시한다. curl http://127.0.0.1:8091/ 에서 그 문자열이 보여야 한다.
  2. 같은 방식으로 ci3-green127.0.0.1:8092 에 띄우되 본문은 version=green 으로 한다. 이때 ci3-blue 는 계속 running 이어야 한다.
  3. /root/ci3/switch.sh <blue|green> 을 만든다. 활성 대상 이름을 /root/ci3/active 에 쓰되, ACTIVE_FILE 환경변수가 설정돼 있으면 그 경로에 쓴다. blue/green 이외의 값이면 아무것도 쓰지 않고 0 이 아닌 코드로 끝낸다. 이 단계를 마칠 때 /root/ci3/active 의 내용은 green 이어야 한다.
  4. /root/ci3/health.sh <URL> 을 만든다. 대상이 정상 응답하면 종료코드 0, 아무도 없거나 실패하면 0 이 아닌 코드를 낸다. 채점은 8091, 8092, 그리고 아무도 없는 8099 로 확인한다.
  5. /root/ci3/deploy.sh <대상> 을 만든다. 현재 활성 값을 기억해 두고 대상으로 전환한 뒤 그 대상의 포트로 헬스체크한다. 실패하면 활성 값을 이전 값으로 되돌리고 0 이 아닌 코드로 끝낸다. 성공하면 활성 값은 대상으로 남고 종료코드 0 이다. 포트는 PORT_BLUE(기본 8091), PORT_GREEN(기본 8092) 환경변수로 덮어쓸 수 있어야 하고, ACTIVE_FILE 도 존중해야 한다.
  6. /root/ci3/canary.sh <퍼센트> 를 만든다. 요청 100건을 보내고 어디로 갔는지 세어 blue=<수> green=<수> 를 출력한다. 두 수의 합은 항상 100 이고, 인자가 0 이면 blue=100 green=0, 100 이면 blue=0 green=100 이어야 한다.
  7. /root/ci3/analyze.sh <지표파일> <임계퍼센트> 를 만든다. 지표 파일에는 total=1000errors=10 이 각각 한 줄씩 들어 있다. 에러율은 errors * 100 / total 이고 임계 이하면 종료코드 0, 초과하면 실제 에러율을 출력하고 0 이 아닌 코드를 낸다. total=0 이면 표본이 없으므로 통과시키지 말고 실패로 처리한다.
  8. /root/ci3/deploy-report.json 을 만든다. 필드는 strategy(blue-green 또는 canary), active(현재 /root/ci3/active 내용과 같아야 한다), previous(active 와 달라야 한다), rollback_used, error_rate_pct, abort_threshold_pct 다. rollback_used 에는 이번 배포에서 롤백이 실제로 일어났는지를 JSON 불리언(true 또는 false)으로 적는다 — 문자열 "true" 는 안 된다. error_rate_pctabort_threshold_pct 이하여야 한다.

참고

blue 환경 띄우기

응답 본문에 version=blue 가 들어가는 컨테이너를 이름 ci3-blue 로 띄우고 127.0.0.1:8091 로 게시한다. curl http://127.0.0.1:8091/ 에서 그 문자열이 보여야 한다.

컨테이너 이름은 정확히 ci3-blue, 게시 포트는 127.0.0.1:8091 입니다. 1024 미만 포트는 바인딩할 수 없습니다. 응답 본문에 version=blue 가 들어가야 하니 index.html 을 만들어 마운트하는 방법이 가장 간단합니다.

green 환경을 나란히 띄우기

같은 방식으로 ci3-green127.0.0.1:8092 에 띄우되 본문은 version=green 으로 한다. 이때 ci3-blue 는 계속 running 이어야 한다.

ci3-green 을 8092 에 띄우고 본문은 version=green 입니다. 이때 blue 를 내리면 안 됩니다. 두 환경이 동시에 살아 있어야 무중단 전환이 성립합니다.

활성 대상 전환 스크립트

/root/ci3/switch.sh <blue|green> 을 만든다. 활성 대상 이름을 /root/ci3/active 에 쓰되, ACTIVE_FILE 환경변수가 설정돼 있으면 그 경로에 쓴다. blue/green 이외의 값이면 아무것도 쓰지 않고 0 이 아닌 코드로 끝낸다. 이 단계를 마칠 때 /root/ci3/active 의 내용은 green 이어야 한다.

switch.sh <blue|green> 이고 기본 기록 파일은 /root/ci3/active 입니다. ACTIVE_FILE 환경변수가 있으면 그 경로를 써야 합니다(채점이 임시 경로로 검증합니다). 모르는 값이면 아무것도 쓰지 말고 실패하세요. 오타 하나가 트래픽을 없는 곳으로 보냅니다.

헬스체크

/root/ci3/health.sh <URL> 을 만든다. 대상이 정상 응답하면 종료코드 0, 아무도 없거나 실패하면 0 이 아닌 코드를 낸다. 채점은 8091, 8092, 그리고 아무도 없는 8099 로 확인한다.

health.sh <URL> 은 살아 있으면 0, 아니면 0 이 아닌 코드입니다. curl -fsS -m 3 처럼 실패 시 에러가 나고 타임아웃이 있는 형태로 부르세요. 항상 통과하는 헬스체크는 없는 것과 같습니다.

실패하면 자동 롤백

/root/ci3/deploy.sh <대상> 을 만든다. 현재 활성 값을 기억해 두고 대상으로 전환한 뒤 그 대상의 포트로 헬스체크한다. 실패하면 활성 값을 이전 값으로 되돌리고 0 이 아닌 코드로 끝낸다. 성공하면 활성 값은 대상으로 남고 종료코드 0 이다. 포트는 PORT_BLUE(기본 8091), PORT_GREEN(기본 8092) 환경변수로 덮어쓸 수 있어야 하고, ACTIVE_FILE 도 존중해야 한다.

deploy.sh <대상> 은 현재 활성 값을 먼저 기억해야 되돌릴 수 있습니다. 포트는 PORT_BLUE(기본 8091), PORT_GREEN(기본 8092)로 덮어쓸 수 있어야 하고 ACTIVE_FILE 도 존중해야 합니다. 헬스 실패 시 이전 값 복구 + 0 이 아닌 종료코드입니다.

비율 분배

/root/ci3/canary.sh <퍼센트> 를 만든다. 요청 100건을 보내고 어디로 갔는지 세어 blue=<수> green=<수> 를 출력한다. 두 수의 합은 항상 100 이고, 인자가 0 이면 blue=100 green=0, 100 이면 blue=0 green=100 이어야 한다.

canary.sh <퍼센트> 는 요청 100건을 보내고 blue=<수> green=<수> 를 출력합니다. 합은 항상 100 이어야 하니 요청 실패를 그냥 흘리면 안 됩니다. 난수보다 순번 기반 분배가 재현성이 좋습니다.

자동 중단 판정

/root/ci3/analyze.sh <지표파일> <임계퍼센트> 를 만든다. 지표 파일에는 total=1000errors=10 이 각각 한 줄씩 들어 있다. 에러율은 errors * 100 / total 이고 임계 이하면 종료코드 0, 초과하면 실제 에러율을 출력하고 0 이 아닌 코드를 낸다. total=0 이면 표본이 없으므로 통과시키지 말고 실패로 처리한다.

analyze.sh <지표파일> <임계퍼센트> 이고 지표 파일은 total=1000errors=10 두 줄입니다. 임계와 같으면 통과입니다. total 이 0 이면 표본이 없어 판단할 수 없으니 통과시키면 안 됩니다. 중단할 때는 실제 에러율을 출력하세요.

배포 리포트

/root/ci3/deploy-report.json 을 만든다. 필드는 strategy(blue-green 또는 canary), active(현재 /root/ci3/active 내용과 같아야 한다), previous(active 와 달라야 한다), rollback_used, error_rate_pct, abort_threshold_pct 다. rollback_used 에는 이번 배포에서 롤백이 실제로 일어났는지를 JSON 불리언(true 또는 false)으로 적는다 — 문자열 "true" 는 안 된다. error_rate_pctabort_threshold_pct 이하여야 한다.

/root/ci3/deploy-report.json 의 active 는 /root/ci3/active 내용과 같아야 하고 previous 는 달라야 합니다. rollback_used 에는 이번 배포에서 롤백이 실제로 일어났는지를 참/거짓으로 적습니다 — 따옴표 없는 JSON 불리언이어야 합니다. error_rate_pct 는 abort_threshold_pct 이하여야 합니다.