점진 배포·rollback·SLO
새 pod가 Ready가 되었다고 릴리스가 성공한 것은 아닙니다. 실제 요청의 오류율과 지연 시간이 기준을 넘지 않아야 하고, 실패하면 새 스키마 위에서도 이전 image가 다시 동작해야 합니다.
진짜 canary는 별도 Deployment나 service mesh가 트래픽 일부만 candidate로 보내야 합니다. 아래의 짧은 스크립트는 Kubernetes 기본 rolling update 뒤 SLO를 확인하는 예제이며, 이것만으로 canary 트래픽 분할을 구현했다고 부르지 않습니다.
배포 성공은 프로세스 시작보다 넓다
candidate를 얼마나 노출할지는 배포 기술의 문제이고, 승격할지는 사용자 지표의 문제입니다. rollback은 단순히 pod 수를 되돌리는 일이 아니라 이전 image가 이미 적용된 migration과 호환되는지까지 포함합니다.
오류율 임계값은 코드 안의 장식 숫자가 아니라 관측 구간·최소 요청 수·지연 시간 기준과 함께 운영 정책으로 합의해야 합니다. 예제의 1%는 흐름을 보여 주는 값이므로 서비스 SLO로 그대로 가져오지 않습니다.
rollout과 rollback 조건을 수치로 고정한다
스크립트는 변경 전에 현재 image를 읽어 두고, rollout 실패나 SLO 초과가 발생하면 그 정확한 image로 돌아갑니다. METRICS_URL은 실제 배포 시스템이 candidate 구간의 오류율을 숫자 하나로 반환하도록 제공해야 하며 예제 주소를 호출하지 않습니다.
#!/usr/bin/env bash
set -euo pipefail
deployment=study-log-api
namespace=study
image=registry.example.com/study-log-api@sha256:8f1c9d6a5b4e3f20718293a4b5c6d7e8f90123456789abcdef0123456789abcd
: "${METRICS_URL:?set METRICS_URL to the approved rollout error-rate query}"
previous_image=$(kubectl -n "$namespace" get deployment "$deployment" \
-o jsonpath='{.spec.template.spec.containers[?(@.name=="api")].image}')
rollback() {
trap - ERR
kubectl -n "$namespace" set image deployment/"$deployment" api="$previous_image"
kubectl -n "$namespace" rollout status deployment/"$deployment" --timeout=180s
}
trap rollback ERR
kubectl -n "$namespace" set image deployment/"$deployment" api="$image"
kubectl -n "$namespace" rollout status deployment/"$deployment" --timeout=180s
error_rate=$(curl -fsS "$METRICS_URL")
if awk "BEGIN { exit !($error_rate > 0.01) }"; then
echo "error rate exceeded 1%: $error_rate" >&2
false
fi
trap - ERRALTER TABLE study_session ADD COLUMN note VARCHAR(500);
COMMENT ON COLUMN study_session.note IS
'nullable during the compatibility window; enforced in a later release';rollout status는 pod 전환만 확인하고 METRICS_URL은 사용자 결과를 확인합니다. 두 단계 가운데 어디에서 실패했는지 로그를 남겨야 probe 문제와 애플리케이션 회귀를 섞지 않습니다.
승인된 환경에서 승격 실패를 리허설한다
bash -n은 cluster를 바꾸지 않고 셸 문법만 검사합니다. 실제 실행은 study namespace를 변경할 권한, 존재하는 image digest, 승인된 지표 URL을 준비한 뒤 수행하며, 의도적으로 임계값을 넘는 테스트 지표를 넣어 이전 image 복귀까지 관찰합니다.
bash -n release-rollout.sh
# 승인된 학습 cluster에서만:
# METRICS_URL='https://<internal-metrics>/...' bash release-rollout.sh
# kubectl -n study rollout history deployment/study-log-apirollout 실패나 오류율 1% 초과는 실행 전에 기록한 image로 복귀해야 합니다. `rollout history` 확인도 cluster 상태를 읽는 명령이므로 로컬 문법 검사와 달리 접속 권한이 필요합니다.DB 변경은 이전 버전과의 호환 창을 둔다
expand-migrate-contract 순서로 스키마를 바꾸어 새 버전과 이전 버전이 동시에 동작할 시간을 확보합니다.
이 릴리스에서는 nullable note 열만 추가합니다. 새 코드가 기존 행을 채우고 이전 image가 더는 필요 없다는 사실을 확인한 뒤에야 별도 릴리스에서 NOT NULL 제약을 추가할 수 있습니다.
rollback 자체가 실패하면 자동 반복을 멈춘다
이전 image가 새 스키마에서 시작하지 못하거나 registry에서 사라졌다면 같은 자동화를 계속 반복하면 복구 시간을 늘립니다. 현재 ReplicaSet, candidate와 previous digest, migration 버전, 오류율 원본을 보존하고 수동 장애 대응으로 전환합니다.
배포 경계를 익혔으므로 다음 장에서는 트랜잭션이 끝난 뒤 실행되는 이벤트와 비동기 작업처럼 애플리케이션 내부의 시간 경계를 다룹니다.