배포를 하나의 변경이 아니라 열 개의 계층으로 본다

롤백 가능한 배포는 이전 Version의 실행 파일을 보관해 둔 상태가 아닙니다. 이전 Version과 새 Version이 일정 기간 같은 설정과 데이터베이스 스키마, 데이터 형식, 외부 계약을 함께 처리해야 합니다. 여기에 기능 노출과 트래픽을 따로 줄이거나 끄고, 어떤 신호가 나타나면 누가 어떤 행동을 할지까지 정해져 있어야 합니다.

코드만 이전 Version으로 돌렸는데 장애가 더 커지는 경우가 있습니다. 새 배포가 이미 컬럼을 지웠거나 데이터를 손실 있는 형태로 바꿨을 수 있습니다. Secret이 폐기됐거나 설정이 새로운 외부 시스템을 바라볼 수도 있습니다. 새 형식의 메시지가 Queue에 쌓인 뒤라면 이전 코드는 이를 읽지 못합니다. 이런 상황에서 이전 바이너리를 다시 띄우는 것은 복구가 아니라 또 하나의 비호환 변경입니다.

배포 도구는 정해진 행동을 실행하는 장치일 뿐입니다. Kubernetes의 Deployment revision은 Pod template을 중심으로 관리되며 외부의 설정과 DB, 데이터를 함께 되돌리지 않습니다.[1] 진행이 멈춘 Deployment도 상태를 보고할 뿐, 그 변경에 Rollback과 Pause, Forward Fix 가운데 무엇이 맞는지는 상위 운영 체계가 정합니다. 그래서 배포 전에 적어야 할 것은 이번에 어떤 코드가 바뀌었는가보다 이번 변경이 어떤 상태와 계약을 바꾸는가입니다.

Google SRE는 Artifact의 재현성과 자동화, 설정의 소유자와 Version, Semantic Validation, 점진 적용과 중단 가능성을 각각 다른 운영 조건으로 다룹니다.[6] 설정이 실행 시점마다 바뀌는 외부 값을 따라가면 같은 Version으로 돌아가도 같은 상태가 재현되지 않습니다.

계층
배포 전에 고정할 계약
실패 시 우선 행동
호환성 제거 조건
Owner
Code / Artifact같은 소스와 입력으로 식별 가능한 Artifact를 만들고 Digest와 빌드 출처, 이전 Artifact를 보존한다검증된 이전 Artifact로 트래픽을 돌리거나 해당 Replica를 다시 확장한다Rollback Window이 닫히고 새 Artifact가 안정 상태로 승인된 뒤Release Owner
DependencyLockfile과 Base Image, Runtime, SDK, 외부 API Version을 기록한다이전 Dependency 묶음을 쓰거나 호환 Adapter를 켠다이전 Runtime과 API를 쓰는 실행 주체가 없어졌을 때Application Owner
Configuration설정에 Version과 소유자를 부여하고 형식뿐 아니라 의미 검증까지 한다. 바뀔 수 있는 외부 참조를 그대로 따라가지 않게 한다이전 설정 Version으로 돌아가거나 설정 배포를 중단한다이전·새 코드가 모두 새 설정을 정상 처리하고 이전 참조가 사라졌을 때Service / Platform Owner
SecretSecret의 Version과 유효 대상, 교체 순서, Provider 장애 시 동작을 정한다. 보안상 허용될 때만 짧은 중복 유효 기간을 둔다아직 유효한 Secret으로 전환하거나 새 Secret을 다시 배포한다. 유출된 Secret은 복원하지 않는다모든 이전 Consumer가 사라지고 새 Secret 사용이 확인된 뒤Security / Platform Owner
DB Schema먼저 추가적인 변경만 하고 일정 기간 이전·새 코드가 같은 Schema에서 동작하게 한다이전 코드를 다시 쓰되 확장된 Schema는 유지한다이전 컬럼과 테이블, 제약을 쓰는 코드와 작업이 완전히 사라졌을 때DB Owner
Data이전 원장과 재실행 가능성, 중단·재개 조건, 정합성 검사와 보상 방법을 정한다Backfill을 멈추고 데이터를 보정하거나 Forward Fix한다. 필요하면 격리된 복구본에서 데이터를 재구성한다Backfill과 검증, 대사가 끝나고 손실 없는 전환이 확인된 뒤Data / Application Owner
Feature exposureFlag의 기본값과 Provider 오류 시 값, 전파 지연, 권한, 감사 기록을 정의한다. Kill Switch를 실제로 시험한다기능 노출을 끄고 기존 동작으로 우회한다기능이 안정화되고 Flag가 더 이상 복구 수단이 아닐 때Product + Application Owner
TrafficVersion별 Route와 Weight, Session Stickiness, Connection Drain, 비동기 트래픽의 귀속을 기록한다Candidate Traffic을 0으로 낮추거나 이전 환경으로 전환한다이전 Version으로 돌아갈 운영 필요가 사라졌을 때Traffic / Platform Owner
Health SignalCandidate와 Control을 구분하는 신호, 관찰 기간, 최소 Evidence와 행동을 잇는다확장 중단, Flag Off, Traffic 회수, Rollback, Forward Fix 가운데 사전 지정된 행동을 실행한다배포 평가가 끝나고 증거와 결정 기록이 보존됐을 때Service Owner / Incident Commander
Owner중단 권한과 Rollback 승인자, DB 변경 책임자, 트래픽 실행자, 수동 Override와 Escalation을 명시한다담당자가 없는 자동화는 멈춘다. Incident Mode로 전환해 하나의 의사결정권을 세운다변경 종료 기록과 후속 책임이 인계됐을 때Change Owner
계층별 Rollback Contract — 배포 전에 계층마다 계약과 실패 시 첫 행동, 제거 조건, 책임자를 적는다

배포 상태를 둘로 만들면 무엇을 잃나

배포 파이프라인을 실행과 성공 또는 실패의 두 상태로 만들면 중간에서 할 일이 Rollback 하나뿐이 됩니다. 실제 운영에는 최소한 Prepared, Partial Exposure, Evaluate / Bake 세 상태가 필요합니다. 평가 뒤에는 Expand와 Pause, Rollback, Forward Fix 네 갈래가 열려 있어야 합니다.

결과가 좋으면 확장합니다. Evidence가 부족하거나 신호가 오염됐으면 멈춥니다. 이전 상태와 호환성이 살아 있다면 Rollback이 가능합니다. 데이터나 외부 상태가 이미 비가역적으로 바뀌었다면 수정 Version과 보상 작업을 적용하는 Forward Fix가 더 적절합니다. Canary는 제한된 배포와 평가 절차를 결합한 것이며 트래픽을 적게 보냈다는 사실만으로는 충분하지 않습니다.[2]

여기서 Pause는 중요한 상태입니다. 신호가 불확실한데 자동으로 이전 Version을 다시 배포하면 원인과 무관한 두 번째 변경을 만들어 상황을 더 복잡하게 합니다. 확장을 멈추되 현재 상태를 보존하면 비교와 진단에 필요한 Evidence를 잃지 않습니다.

Prepared
Prepared는 Artifact와 설정, Secret, Schema 확장, Route, 관측 신호가 준비된 상태입니다. 이전 Version으로 돌아갈 경로도 이때 검증합니다.
Partial Exposure
Partial Exposure는 새 Version을 제한된 Replica와 사용자 집단, 요청 비율 또는 Feature Flag 범위에만 노출한 상태입니다.
Evaluate / Bake
Evaluate와 Bake는 시간이 지나기를 기다리는 상태가 아니라, Candidate와 Control의 차이와 비동기 작업의 완료, Cache와 Queue의 영향이 나타날 때까지 관찰하는 상태입니다.
서비스 작동 방식

관측에서 복구와 개선까지 이어지는 운영서비스 지표와 경보를 기준으로 대응하고 변경 이력과 사후 보고를 다음 개선에 연결합니다.

Backward Compatibility Window는 Artifact 보관 기간이 아니다

이전 Version으로 돌아갈 수 있는 기간은 단순한 Artifact 보관 기간이 아닙니다. 이전 코드가 새 Schema와 새 데이터를 읽고, 새 코드도 아직 남아 있는 이전 데이터와 요청을 처리하는 기간입니다.

실무에서 호환성을 유지해야 할 기간은 일곱 값 가운데 가장 긴 것보다 짧아서는 안 됩니다. Rollback 판단에 필요한 시간, 가장 오래 실행되는 배치와 작업, Queue·Event의 최대 체류 시간, Client와 Session, Cache의 수명입니다. 나머지는 데이터 Backfill와 정합성 검증 시간, Secret의 중복 유효 기간, 복제 지연과 복구 검증 시간입니다.

이는 특정 도구의 공식이 아니라 병행 변경과 점진 배포 원칙을 하나의 운영 잣대로 묶은 모델입니다.[3] 오래된 Client나 Queue 메시지가 남아 있는데 호환 컬럼과 Adapter를 제거하면, 전체 트래픽이 새 Version으로 넘어갔더라도 배포는 아직 끝난 것이 아닙니다.

DB 변경은 Expand–Migrate–Contract로 나눈다

호환되지 않는 DB 변경을 코드 배포와 같은 순간에 실행하면 Rollback Window이 거의 즉시 사라집니다. 이를 피하는 대표적인 방식이 Expand–Migrate–Contract로 나누는 것입니다. customer_name 컬럼을 display_name으로 바꾸려 한다고 하겠습니다.

Expand 단계에서는 새 컬럼을 더하되 기존 컬럼을 지우지 않습니다. 이전 코드와 새 코드가 모두 동작하는 Schema를 먼저 만들고, 새 컬럼이 비어 있어도 오류가 나지 않게 읽기 경로를 설계합니다. Migrate 단계에서는 새로 생기는 데이터를 필요한 기간 동안 두 경로에 기록하거나, 한쪽을 원장으로 두고 다른 쪽을 비동기로 채웁니다. 기존 데이터는 작은 단위로 채우면서 작업 위치와 결과를 기록합니다. 중단 후 재개해도 중복 변환이나 데이터 손상이 없어야 합니다. Contract 단계에서는 읽기 경로가 새 컬럼으로 넘어갔고 이전 Version과 배치, Queue Consumer가 더 이상 기존 컬럼을 쓰지 않는다는 Evidence를 확인한 뒤 별도 배포에서 기존 컬럼을 제거합니다. 새 코드가 정상 배포됐다와 이전 계약을 제거해도 된다는 서로 다른 결정입니다.[3]

DB 엔진에 따라서도 운영 조건이 달라집니다. PostgreSQL의 ALTER TABLE은 하위 명령에 따라 강한 잠금을 얻거나 Table Rewrite를 일으킵니다.[4][7] 상수 기본값 추가처럼 재작성을 피하는 경우도 있지만 조건을 확인해야 합니다. Migration 파일이 실행된다는 사실과 운영 중 안전하다는 사실은 다르므로 예상 Lock, Rewrite, 실행 시간, 복제 영향을 확인합니다. MySQL의 Atomic DDL은 장애 시 일관성을 높이는 개념이지 사용자가 임의로 되돌리는 Transactional DDL과 같지 않습니다.[8] 여러 DDL은 암묵적 Commit을 일으키고 Metadata Lock의 영향을 받으므로, 애플리케이션 트랜잭션과 같은 방식으로 DDL을 취소한다고 가정하지 않습니다.

시점 복구도 일반 배포 Rollback과는 다릅니다. PostgreSQL은 Base Backup과 WAL로 Cluster 전체를 특정 시점으로 복구하며 설정 파일은 별도 대상입니다. MySQL 역시 전체 Backup과 Binary Log 재생을 결합합니다. 운영 DB를 과거 시점으로 되돌리면 목표 시점 이후의 정상 변경까지 영향을 받으므로, 먼저 격리된 복구본에서 필요한 데이터를 뽑아 현재 상태와 대사하는 방식이 더 적절한 경우가 많습니다.[9]

비가역 데이터 변경은 처음부터 표시한다

일곱 종류의 변경에는 완전한 역변환이 없거나 비용이 지나치게 큽니다. 여러 값을 하나로 합치는 손실성 집계, 원본을 버린 채 수행한 암호화와 재인코딩, 중복 계정이나 레코드를 하나로 병합하는 작업입니다. 외부 부작용과 폐기 항목도 있습니다. 외부 결제와 이메일, 메시지, Webhook 전송, 이미 소비된 Event와 비동기 작업, 복구 불가능하게 폐기한 암호화 키, 새 형식으로만 저장한 뒤 지운 원본 필드입니다.

이 경우 Rollback Contract의 행동은 이전 코드 재배포가 아닙니다. 새 쓰기를 멈추고 영향 범위를 식별한 뒤 수정 Version을 배포하고 보상 트랜잭션이나 데이터 보정을 거쳐 정합성을 다시 검증하는 순서가 됩니다.

비가역 여부가 불분명한 변경은 배포 문서에서 숨기지 말고 Forward Recovery Required로 분명히 분류해야 합니다. 그래야 장애 중에 없는 복구 경로를 찾느라 시간을 잃지 않습니다.

Feature Flag와 Kill Switch는 같은 말이 아니다

Feature Flag는 바이너리 배포와 사용자 노출을 나눕니다. 새 코드를 배포하되 기능은 숨긴 채 두거나 특정 사용자와 Tenant, 지역에만 열 수 있습니다. Google SRE도 Feature Flag를 Binary Release와 Launch를 분리하고 문제가 있는 기능을 선택적으로 끄는 수단으로 설명합니다.[2]

그러나 모든 Flag가 운영용 Kill Switch인 것은 아닙니다. 안전한 Kill Switch로 쓰려면 일곱 계약이 필요합니다. Flag Provider가 응답하지 않을 때 쓸 안전한 기본값, 변경이 모든 Instance에 퍼지는 최대 시간, 사용자와 Tenant, 지역별 적용 범위입니다. 나머지는 변경 권한과 감사 기록, 비상 상황에서 별도 배포 없이 조작하는 경로, 실제 운영 조건을 반영한 끄기 경로 시험, 제거 예정일과 담당자입니다.

OpenFeature는 Flag 평가 API와 Provider, Evaluation Context, Hook, Provider 상태 Event를 표준화합니다.[5] 평가 오류 시 애플리케이션이 전달한 기본값을 반환하도록 정의합니다. 다만 어떤 기본값이 안전한지와 Flag 변경이 데이터 부작용을 되돌리는지는 애플리케이션 설계의 책임입니다. 이미 새 형식의 데이터를 기록했거나 외부 요청을 보냈다면 Flag를 꺼도 그 상태는 남습니다. Feature Flag는 노출을 멈추는 제어 장치이지 데이터 복구 장치가 아닙니다.

Rolling·Canary·Blue-green·Traffic Split의 역할

네 용어는 서로 배타적인 선택지가 아닙니다. Canary를 별도 Deployment와 Traffic Split로 구현해도 됩니다. Blue-green 환경 사이에서 일부 트래픽만 새 환경으로 보내며 평가해도 됩니다.

Kubernetes의 RollingUpdate에서는 교체 중 이전·새 Pod가 동시에 존재합니다.[1] Google SRE는 Canary를 부분적이고 시간 제한이 있는 배포와 평가 절차로 정의하며 대표 트래픽과 측정 주기, 공유 Dependency의 영향을 함께 고려하게 합니다.[2] Blue-green은 경로 전환을 빠르게 하지만 DB와 상태 계약까지 자동으로 분리하지는 않습니다.

방식
무엇을 바꾸는가
장점
숨은 호환성 조건
대표 복구 행동
Rolling실행 중인 Instance를 순차적으로 새 Version으로 교체한다추가 환경을 크게 늘리지 않고 점진 교체가 된다이전·새 Version이 동시에 실행되므로 DB·API·Message 계약이 호환돼야 한다배포 중단, 이전 Replica 확장
Canary일부 Instance와 사용자, 요청에 Candidate를 제한된 시간 동안 노출한다영향 범위를 줄이고 Candidate와 Control을 비교한다표본이 대표성을 가져야 하며 공유 DB·Cache·Dependency이 Control까지 오염시킬 수 있다노출 중단, Traffic 회수, Flag Off
Blue-green이전 환경과 새 환경을 병렬로 유지하고 Route를 전환한다이전 환경을 보존한 채 새 환경을 검증하고 Route를 빠르게 되돌린다공유 DB와 Session, 연결, Secret, 외부 부작용이 이전 환경에서도 처리돼야 한다Route를 이전 환경으로 되돌림
Traffic SplitRouter나 Gateway에서 Version별 요청 비율을 조정한다비율뿐 아니라 사용자와 Tenant, 지역 기준으로 노출을 제어한다Session Stickiness와 WebSocket, Queue·Batch, 공유 상태를 따로 다뤄야 한다Candidate Weight를 낮추거나 0으로 전환
배포 방식 — 네 용어는 배타적 선택지가 아니라 서로 겹쳐 쓰는 도구다

Bake Time은 고정된 분 단위가 아니다

Bake Time은 배포 후 30분 대기처럼 정해 두는 휴식 시간이 아닙니다. 이번 변경의 주요 실패가 관측될 만큼 대표적인 작업이 실제로 지나가는 기간입니다. 요청량과 사용자 유형의 다양성, 주간과 야간, 평일과 주말의 Traffic Pattern, 가장 오래 걸리는 배치와 비동기 작업, Queue 지연과 Retry 간격에 따라 필요한 길이가 달라집니다. Cache와 Session의 수명, 외부 Dependency의 호출 빈도, Metric 집계 주기와 지연, 데이터 Backfill와 정합성 검증 시간도 고려해야 하므로 필요한 길이가 달라집니다.

트래픽이 적은 서비스에서는 짧은 Canary보다 Synthetic Request이나 명시적 검증 시나리오가 더 필요합니다. 반대로 요청량이 많아도 Candidate와 Control을 구분하지 않은 전체 평균만 보면 Candidate의 오류가 정상 트래픽에 가려집니다.[2]

Rollback Trigger는 여덟 항목으로 구체화해야 합니다. 이미 정의된 사용자·서비스 건강 신호를 적습니다. Candidate와 Control과 전체 시스템 가운데 어디를 보는지, Candidate와 Control의 허용 차이 또는 절대 차단 조건을 적습니다. 해당 실패가 나타나는 데 필요한 관찰 기간, 최소 요청과 작업, 사용자 집단을 적습니다. Pause, Flag Off, Traffic Zero, Rollback, Forward Fix 가운데 어떤 행동인지 정합니다. 결정권자와 실행자, 수동 Override의 권한과 사유 기록, 만료 조건도 적습니다. 어떤 사용자 여정을 어떤 지표로 만들지는 별도 관측 설계의 영역입니다. 여기서는 이미 정의된 건강 신호를 배포 행동과 잇는 데서 멈춥니다.

서비스 작동 방식

서비스 구조에서 운영 기준까지네트워크와 서버를 설계하고 배포 경로, 접근 권한과 백업 기준을 함께 갖춥니다.

자동 Rollback이 더 위험해지는 경우

자동화가 가장 먼저 해야 할 행동이 항상 이전 Version 재배포는 아닙니다. 여덟 상황에서는 자동 Pause나 노출 중단이 더 안전합니다.

Google SRE는 Canary 평가에서 Candidate와 Control의 오염, 관찰 기간, 배포 중단과 사람의 판단을 함께 다룹니다.[2] Kubernetes 역시 진행 실패를 상태로 표시하지만 복구 행동을 대신 정하지 않습니다.[1] DB의 Lock·Rewrite·PITR 범위까지 고려하면, DB와 데이터, Secret, Restore 경로를 무조건 자동화하기보다 Traffic 확장 중단을 먼저 자동화하는 편이 안전한 경우가 많습니다.

상황
자동 Rollback의 위험
더 적절한 첫 행동
Candidate가 공유 DB에 이전 코드가 읽지 못하는 데이터를 기록함이전 코드가 같은 데이터를 읽으며 추가 오류를 낸다새 쓰기 중단, Traffic 분리, Forward Recovery
보안 취약점을 막으려고 이전 Version과 Secret을 폐기함이전 Version으로 돌아가며 취약점이나 폐기된 Credential이 되살아난다수정 Version 배포, 새 Secret 재발급
외부 Dependency 장애가 Candidate 오류처럼 보임원인과 무관한 재배포로 부하와 변수를 늘린다확장 중단, Candidate와 Control 비교
결제·메일·Webhook 같은 외부 부작용이 이미 발생함코드만 바뀌고 외부 세계의 상태는 남는다중복 실행 차단, 보상 작업
이전 환경의 Cache가 차갑거나 용량이 부족함Traffic 복귀가 새로운 과부하를 만든다점진 Traffic 회수, 용량 확보
여러 Canary나 설정 변경이 동시에 진행 중임신호의 원인을 가리지 못한 채 반복 Rollback이 일어난다모든 확장 중단, 변경 분리
신호가 짧게 흔들리며 자동화가 반복 동작함Version이 오가는 Flapping과 추가 장애가 생긴다Cooldown, 수동 승인, Incident Mode
이전 Artifact와 설정이 실제로 재검증되지 않음돌아간 뒤에야 이전 상태가 이미 쓸 수 없음을 알게 된다이전 경로 점검 후 수동 결정
자동 Rollback이 더 위험해지는 여덟 상황 — 첫 행동을 다시 고른다

Rollback·Roll-forward·Failover·Restore는 서로 다른 행동이다

네 행동은 바꾸는 대상이 다릅니다. Failover는 실행 위치를 바꾸는 행동이고 Restore는 데이터를 재구성하는 행동입니다. 소프트웨어 결함이 모든 환경에 배포됐다면 Failover만으로 해결되지 않습니다. 데이터가 손상되지 않았다면 전체 Restore는 오히려 정상 트랜잭션까지 과거로 돌립니다.[10]

그래서 장애 중에는 먼저 지금 무엇이 망가졌는지를 묻고, 그다음 현재의 호환성 계약이 어디까지 살아 있는지를 확인해 네 행동 가운데 하나를 고릅니다.

행동
바꾸는 대상
적합한 상황
데이터에 미치는 영향
주요 위험
Rollback코드와 설정, 기능 노출, 트래픽을 이전의 호환 가능한 상태로 돌린다이전 상태와의 계약이 아직 유효하고 Candidate 영향이 제한적일 때대개 현재 데이터를 유지하지만 이전 코드가 이를 처리해야 한다Schema·데이터·Secret이 비호환이면 실패
Roll-forward / Forward Recovery수정 코드와 Adapter, Migration 또는 데이터 보정을 새 Version으로 적용한다상태 변경이 비가역이거나 이전 Version이 보안·호환성상 쓸 수 없을 때현재 상태를 보존하며 잘못된 부분을 고친다수정이 충분히 검증되지 않으면 추가 변경 위험
Failover트래픽이나 역할을 정상 Replica와 리전, 환경으로 전환한다특정 Instance·Zone·Region 또는 Primary를 쓸 수 없을 때복제 상태와 목표 복구 시점에 따라 최신 데이터에 차이가 난다같은 결함 Version이 대상 환경에도 있으면 문제 지속
RestoreBackup·Snapshot·WAL·Binary Log로 데이터 상태를 재구성한다삭제와 손상, 오염으로 현재 데이터 자체를 믿을 수 없을 때목표 시점 이후 변경을 잃거나 별도 대사가 필요하다긴 복구 시간, 정상 변경 손실, 의존 시스템과 불일치
Rollback·Roll-forward·Failover·Restore — 네 행동은 바꾸는 대상이 다르다

배포 전 Rollback 준비 점검

Artifact와 Dependency에서는 다섯 가지를 봅니다. 배포할 Artifact의 Digest와 빌드 출처가 기록돼 있는가. 개발 환경에서 다시 빌드하지 않고 검증된 동일 Artifact를 승격하는가. 이전 Artifact가 실제 실행 가능한 상태로 보존돼 있는가. Lockfile과 Base Image, Runtime, 주요 SDK Version을 확인했는가. 외부 API·Message·Event 계약의 이전·새 Version 호환성을 확인했는가입니다.

설정과 Secret에서는 여섯 가지를 봅니다. 설정에 Version과 소유자가 있는가. 형식 검사 외에 엔드포인트와 범위, 단위, 상호 배타 조건을 포함한 의미 검증을 했는가. 실행 시점에 바뀌는 외부 참조를 그대로 따라가지 않는가. Secret 교체 순서와 이전 Secret의 유효 종료 조건이 있는가. Provider 장애 시 Feature Flag와 Secret 조회의 기본 동작을 확인했는가. 유출되거나 폐기된 Secret을 Rollback 대상으로 쓰지 않는가입니다.

DB Schema와 데이터에서는 여덟 가지를 봅니다. 파괴적 변경 전에 Additive Expand를 했는가. 이전 Version이 확장된 Schema에서 읽고 쓰는가. Migration이 중단과 재개, 재실행이 되는가. Backfill 진행 위치와 정합성 검사 결과를 기록하는가. Dual Write를 쓴다면 불일치 탐지와 대사 방법이 있는가. 비가역 데이터 변경과 외부 부작용을 따로 표시했는가. Rollback이 불가능한 변경에 Forward Recovery 절차가 있는가. DB 엔진과 Version별 Lock·Rewrite·암묵적 Commit 조건을 확인했는가입니다.

기능 노출과 트래픽에서는 여섯 가지를 봅니다. Binary 배포와 기능 노출을 나눌 수 있는가. Kill Switch의 끄기 경로를 실제 운영 조건으로 시험했는가. Candidate와 Control을 구분하는 Route·Label이 있는가. Traffic Weight를 낮추거나 0으로 만드는 권한과 절차가 있는가. Session, Connection Drain, WebSocket, Queue·Batch 트래픽을 고려했는가. 이전 환경에 트래픽을 되돌릴 때 필요한 용량을 확인했는가입니다.

신호와 결정에서는 여섯 가지를 봅니다. 배포 전 이미 정의된 건강 신호를 Candidate 기준으로 보는가. Rollback Trigger에 관찰 기간과 최소 Evidence가 들어 있는가. Pause, Flag Off, Traffic Zero, Rollback, Forward Fix이 구분돼 있는가. 자동 행동의 Cooldown과 수동 Override가 있는가. 중단 권한자와 실행 담당자가 명시돼 있는가. 야간과 휴일, 담당자 부재 시 Escalation 경로가 있는가입니다. 마지막으로 복구 검증에서는 이전 Artifact와 설정으로 실제 복귀하는 Rehearsal을 했는가. Backup 존재 여부와 별도로 Restore 절차를 시험했는가. 복구 소요 시간과 데이터 손실 범위를 기록했는가. Incident 중 변경을 하나로 통제할 책임자가 있는가. 배포와 판정, Override 기록을 보존할 위치가 있는가를 봅니다.

배포 후 호환성 제거 점검

전체 트래픽이 새 Version으로 넘어갔다고 곧바로 이전 계약을 제거하지 않습니다. 먼저 이전 Version으로 향하는 동기 트래픽이 없고, 오래된 Client와 Session, Cache가 더 이상 이전 계약을 쓰지 않으며, 이전 형식의 Queue·Event·Batch 작업이 모두 처리됐는지 확인합니다. Backfill이 끝났고 원본과 대상의 정합성을 확인했는지, Dual Write 불일치가 없거나 승인된 허용 범위 안인지, 이전 컬럼과 API, Message Schema 사용량이 0인지, 이전 Secret을 쓰는 Consumer가 없는지도 함께 봅니다.

그다음이 정리 작업입니다. Rollback Window 종료를 Change Record에 명시합니다. 이전 Secret 폐기와 권한 회수는 별도 변경으로 수행합니다. Feature Flag와 Adapter, 임시 Read Fallback의 제거 담당자와 날짜를 정합니다. 이전 컬럼과 테이블 삭제는 Cutover와 분리된 별도 배포로 실행합니다. Migration 이후 새로운 Backup 또는 복구 기준점을 확인한 뒤 Runbook, Schema 문서, Dependency 기록, 운영 인계를 갱신합니다. 제거 작업 자체에도 새로운 Rollback과 Forward Recovery 계획이 있어야 합니다.

호환성 코드는 기술 부채가 됩니다. 그렇다고 새 Version이 정상이라는 이유만으로 같은 배포에서 제거하면 가장 중요한 복구 경로를 스스로 닫게 됩니다. 추가와 이전, 제거를 서로 다른 변경으로 나눠야 각 단계의 실패 원인과 복구 행동도 나뉩니다.

되돌릴 수 있는 배포는 배포 전에 만들어진다

Rollback 버튼은 마지막 실행 장치입니다. 그 버튼이 안전하려면 이전 코드가 새 Schema를 처리해야 합니다. 이전 환경이 현재 트래픽과 Session을 받고, 설정과 Secret의 이전 상태가 여전히 유효해야 합니다. 데이터 변경에 역변환이 없다면 버튼을 누르기 전에 이미 Rollback 선택지는 사라진 것입니다.

운영 중 가장 좋은 첫 행동은 때로 이전 Version 재배포가 아니라 노출 확대를 멈추는 것입니다. 그다음 현재의 호환성 계약을 확인해 Rollback과 Forward Recovery, Failover, Restore 가운데 맞는 행동을 고릅니다.

DNS와 Cache, 크론, DB 동기화가 함께 바뀌는 서버 이전 작업에도 같은 Rollback Contract이 필요합니다. 다만 구체적인 사전 점검과 전환 절차는 별도 이전 런북이 다룹니다.