한 줄 정의
실행 중인 시스템을 멈추지 않고 바꾸는 방법은 변경을 작게 쪼개고, 완성되지 않은 변경도 안전하게 프로덕션에 올려 두는 기술에 있습니다.
쉽게 말하면
영업 중인 가게의 배관을 교체하는 상황을 떠올리면 이 장이 한 줄로 꿰어집니다.
물을 잠그고 낡은 배관을 뜯어낸 뒤 새 배관을 연결하는 방식은 가장 단순하지만, 그동안 가게는 문을 닫아야 합니다. 게다가 뜯어낸 중간에 문제가 생기면 옛 배관도 새 배관도 없는 상태가 됩니다.
그래서 순서를 바꿉니다. 새 배관을 옆에 먼저 깔아 둡니다. 물은 여전히 옛 배관으로 흐르지만, 새 배관은 이미 설치되어 압력 테스트까지 끝난 상태입니다. 준비가 되면 밸브만 돌려 물길을 옮기고, 며칠 지켜본 뒤 아무 문제가 없을 때 비로소 옛 배관을 떼어냅니다. 문제가 생기면 밸브를 되돌리면 그만입니다.
이 장의 기술들 — 병렬 인스턴스, 확장과 축소, 블루-그린, 피처 토글 — 은 전부 이 “먼저 깔아 두고, 나중에 옮기고, 마지막에 떼어낸다”의 변주입니다.
왜 중요한가?
빠른 변경이 시스템을 불안정하게 만든다는 통념은 틀렸습니다. 속도는 안정성을 높이는 요소이며 그 반대도 마찬가지입니다.
Quote
‘빨리 움직여서 망가트려라(move fast and break things)‘가 아니라 ‘빨리 움직여서 개선하라(move fast and improve things)‘입니다.
핵심은 속도와 품질 중 하나를 고르는 것이 아니라 둘 다 최적화하는 것입니다. 하나만 최적화하려 하면 결국 어느 쪽도 얻지 못합니다.
문제는 인프라를 자주 바꾸면 중단 없는 서비스를 제공하기 어려워진다는 점입니다. 이 장의 사고 방식은 그 어려움을 변경을 안정성에 대한 위협으로 보는 대신, 현대 인프라의 동적 특성을 활용해 푸는 것 입니다. 인스턴스를 자유롭게 만들고 지울 수 있다는 클라우드의 성질이 곧 무중단 변경의 재료가 됩니다.
핵심 내용
변경 범위를 줄인다
큰 변경보다 작은 변경이 계획·구현·테스트·디버깅하기 쉽습니다. 그래서 목표는 배치 크기를 줄이는 것 입니다. 시스템을 크게 바꿔야 하는 상황에서도, 한 번에 하나씩 전달할 수 있는 작은 변경 모음으로 작업을 쪼갤 수 있습니다.
큰 변화를 작은 변화의 연속으로 구현하는 것은 새로운 사고방식과 습관을 요구합니다. 완전한 상태에 조금씩 가까워지는 작은 변화를 만드는 쪽이 오히려 더 어렵기 때문입니다. 소프트웨어 개발의 TDD·CI·CD가 그 길을 먼저 보여 주었습니다.
| 용어 | 무엇을 쪼개는가 |
|---|---|
| 증분(incremental) | 계획된 구현을 부분별로 완성. 네트워킹 스택 → 웹 클러스터 스택 → 애플리케이션 인프라 스택 순으로 하나씩 구현 |
| 반복(iterative) | 세 스택 모두의 기본 버전을 먼저 만들고, 각 스택이 하는 일을 넓혀 가며 개선 |
| 워킹 스켈레톤(walking skeleton) | 주요 부분의 최소 구현으로 전체 설계와 구조를 먼저 검증. 딜리버리·배포·운영이 어떻게 작동하는지 초기에 확인 |
| 리팩터링 | 작동을 바꾸지 않고 설계·구조만 변경. 이후의 변경을 쉽게 만들기 위한 토대 |
워킹 스켈레톤에서 쓰는 도구와 서비스의 초기 선택은 장기 계획일 필요가 없습니다. 최종적으로 모든 기능을 갖춘 모니터링 솔루션을 쓸 계획이더라도, 스켈레톤 단계에서는 클라우드 벤더가 제공하는 기본 서비스로 시작해도 됩니다.
새로운 빌드
설계와 구현을 대폭 바꿀 때는 기존 시스템을 점진적으로 고치는 것보다 신규 버전을 별도로 빌드한 뒤 사용자를 옮기는 편이 쉽습니다. 다만 한 번에 시스템의 한 부분만 떼어내 리빌드하는 것이 한 번에 전부 리빌드하는 것보다 덜 위험합니다. 대규모 리빌드도 점진적으로 수행할 수 있습니다.
불완전한 변경을 프로덕션에 푸시한다
작은 변경 하나하나는 그 자체로 쓸모없을 수 있고, 기존 기능 제거는 변경 전체가 끝나기 전까지 실용적이지 않습니다. 그래서 기존 코드와 기능을 제자리에 유지한 채 작은 변경을 밀어 넣을 방법 이 필요합니다.
병렬 인스턴스
패키지형 Kubernetes(KubeCan)를 관리형 서비스(FKS)로 바꾸는 것처럼, 작은 단계로는 도저히 나눌 수 없는 교체가 있습니다. 이때는 두 클러스터를 병렬로 실행합니다.
flowchart TB subgraph A["방법 1 — 파라미터로 선택"] MA["메인 스택"] -->|"활성"| KA["KubeCan 스택"] MA -.->|"비활성"| FA["FKS 스택"] end subgraph B["방법 2 — 둘 다 통합"] MB["메인 스택"] --> KB["KubeCan 스택"] MB --> FB["FKS 스택"] end
방법 1은 메인 스택의 파라미터로 통합할 클러스터를 고르는 방식입니다. 하나만 실시간 워크로드를 처리하고 나머지는 존재하되 비활성 상태입니다. 완전히 작동하는 환경에서 두 번째 스택을 테스트하고 파이프라인을 개발할 수 있습니다.
방법 2는 두 스택을 모두 메인 스택과 통합해 워크로드를 나누는 방식입니다. 나누는 기준에 따라 성격이 달라집니다.
| 분할 기준 | 내용 | 관련 개념 |
|---|---|---|
| 워크로드 비율 | 신규 스택에 작은 비율의 요청만 흘려 보내며 평가. 잘 되면 100%까지 올리고 이전 스택 해제 | 카나리 배포(canary release) |
| 서비스 마이그레이션 | 서비스를 하나씩 신규 클러스터로 이동. 애플리케이션 수정이 함께 필요할 때 유용 | — |
| 사용자 파티셔닝 | 테스터·내부 사용자를 먼저 신규 스택에 태우고, 이후 알파·프리뷰 지원 고객으로 확대 | 다크 런칭(dark launching) |
신규와 이전 부분을 조건부 또는 병렬로 실행하는 것 자체가 추상화에 의한 브랜치(branch by abstraction) 유형입니다.
왜 이전 솔루션을 굳이 스택으로 추출할까?
신규 솔루션으로 독립형 스택을 만들 것이라면, 이전 솔루션을 추출하는 단계는 건너뛸 수 있어 보입니다. 그럼에도 추출하는 이유는 신규 솔루션이 이전 솔루션의 작동과 일치하는지 확인하기 쉬워지기 때문 입니다. 추출된 스택은 클러스터가 다른 인프라와 통합되는 방식을 명확히 정의하고, 프로덕션에서 그 스택을 쓰면 통합점이 정확함이 보장됩니다.
반대로 이전 솔루션을 원래 스택에 그대로 두고 신규 솔루션만 별도로 구축하면 스왑 아웃이 중단됩니다. 호환되지 않는 설계·구현 결정을 내렸는지 끝까지 알 수 없습니다.
이전 버전과 호환되는 변환
소비자용 컴포넌트에 제공하는 것을 바꿀 때, 기존 통합점을 유지한 채 신규 통합점을 추가 하면 소비자는 자기 일정에 따라 전환할 수 있습니다.
단일 VLAN을 3개로 쪼개는 예제에서 네트워킹 스택은 신규 식별자를 내보내면서, 이전 이름도 신규 VLAN 중 하나를 가리키도록 남겨 둡니다.
export:
- appserver_vlan_A: appserver_vlan_A.id
- appserver_vlan_B: appserver_vlan_B.id
- appserver_vlan_C: appserver_vlan_C.id
# Deprecated
- main_vlan: appserver_vlan_A.id
이전 식별자에 대한 모든 의존성이 사라지면 그때 네트워킹 스택 코드에서 제거합니다.
피처 토글
변경이 완료될 때까지 기존 구현을 계속 써야 할 때, 브랜치를 파는 대신 기본 코드베이스에서 구성 파라미터로 코드 경로를 전환 합니다.
브랜치를 피하는 이유는 세 가지입니다. 버그 수정 같은 다른 영역 변경을 두 브랜치에 반영하려면 추가 작업이 들고, 두 지점을 지속적으로 테스트·배포하려면 리소스가 들며, 결국 전환하는 순간이 실패 위험이 큰 ‘빅뱅’ 작업이 됩니다.
input_parameters:
name: toggle_use_multiple_vlans
default: false
variables:
- name: appserver_A_vlan
value:
$IF(${toggle_use_multiple_vlans} appserver_vlan_A ELSE main_vlan)
토글이 false면 모든 서버가 이전 main_vlan 을 쓰고, true면 각각 신규 VLAN을 씁니다. 같은 토글이 라우팅 등 스택 코드의 다른 부분에서도 함께 쓰입니다.
피처 토글은 부채입니다
토글과 조건은 코드를 복잡하게 만들어 이해·유지보수·디버깅을 어렵게 합니다. 가능한 한 빨리 이전 구현의 의존성과 조건부 코드를 제거해 토글의 수명을 짧게 유지해야 합니다. 몇 주 뒤에도 남아 있는 토글은 사실상 구성 파라미터입니다.
이름은 수행하는 작업을 그대로 드러내야 합니다.
new_networking_code같은 모호한 이름은 물론,toggle_vlans처럼 여러 VLAN 코드를 활성화하는지 비활성화하는지 알 수 없는 이름도 위험합니다. 조건부 연산을 반대로 쓰는 오류가 여기서 나옵니다.toggle_use_multiple_vlans는 피처 토글임과 작동 방향을 모두 이름에 담고 있습니다.
실시간 인프라를 변경한다
앞의 기술들은 인프라 코드 를 바꾸는 방법입니다. 이미 실행 중인 인스턴스, 특히 다른 인프라가 사용 중인 리소스를 바꾸는 것은 별개의 문제입니다.
main_vlan 을 3개의 VLAN으로 교체하는 코드를 적용하면 그 VLAN에 속한 세 서버 인스턴스가 함께 삭제됩니다. 대부분의 플랫폼은 연결된 서버가 있는 네트워킹 구조의 제거를 거부하므로 작업이 실패하는데, 이때 일부 변경은 이미 적용된 뒤라 환경이 이전 버전과 신규 버전 사이의 중간 상태로 남습니다. 이것이 거의 항상 최악입니다.
이전 VLAN을 유지하고 신규 VLAN 두 개만 추가하는 타협도 가능하지만, 이름이 하나만 다르고 IP 주소 범위 같은 다른 측면도 바꿀 수 없습니다. 일관성 없는 시스템을 만들어 유지보수와 디버깅을 어렵게 하므로 나쁜 습관입니다.
인프라 수술
Terraform 같은 도구는 인프라 리소스를 코드에 매핑하는 데이터 구조를 노출하고, 일부는 이 구조를 편집하는 기능(terraform mv, pulumi state)을 제공합니다.
신규 코드로 두 번째 스택 인스턴스를 만든 뒤, 데이터 구조상에서 main_vlan 을 이전 인스턴스에서 신규 인스턴스로 옮기고 appserver_vlan_A 로 이름을 바꾸는 식입니다.
$ stack datafile move-resource \
source-instance=shared-networking-stack-production-old \
source-resource=main_vlan \
destination-instance=shared-networking-stack-production-new
$ stack datafile rename-resource \
instance=shared-networking-stack-production-new \
from=main_vlan \
to=appserver_vlan_A
실제 VLAN은 전혀 변경되지 않고 서버 인스턴스도 손상되지 않습니다. 장부 기입(bookkeeping) 연습에 가깝습니다.
일상적으로 할 일이 아닙니다
데이터 구조를 손으로 편집하면 실수하기 쉽고, 스크립트로 만들어도 멱등적이지 않습니다. 특정 시작 상태를 가정하므로 다른 경우를 예측하지 못합니다. 운영 중단 같은 문제를 풀려고 압박 속에서 편집하다 실수가 겹치는 시나리오가 전형적입니다.
데이터 구조를 보는 것 은 디버깅에 유용하지만 편집하는 것 은 피해야 합니다. 편집에 의존할 때마다 비난 없는 포스트모템으로 반복을 피하는 방법을 찾아야 합니다.
확장과 축소
확장과 축소(expand and contract, 병렬 변경parallel change) 는 공급자 인터페이스 변경을 공급자 변경과 소비자 변경 두 단계로 분리 하는 패턴입니다. 실시간 인프라를 안전하게 바꾸는 정공법입니다.
flowchart LR E["확장<br/>기존 유지 + 신규 추가"] --> M["전환<br/>소비자를 신규로"] --> C["축소<br/>사용 안 하는 이전 제거"]
각 단계가 파이프라인으로 딜리버리되므로 매번 철저한 테스트를 거칩니다. 인프라 수술과 달리 스택의 두 번째 인스턴스를 만들지 않고 기존 인스턴스만 변경합니다.
VLAN 예제의 전개는 다음과 같습니다.
shared-networking-stack에 신규 VLAN 3개를 추가하고main_vlan은 그대로 둡니다. 기존 소비자는 영향받지 않습니다- 신규 VLAN에 신규 서버 인스턴스(
appserver-A2)를 추가합니다. 아직 사용되지 않지만 자동화된 테스트로 정상 실행을 증명할 수 있습니다 static_ip선언의attach를 신규 서버로 바꿔 트래픽을 전환합니다. 문제가 생기면 쉽게 롤백합니다- 신규 서버가 정상 작동하면 스택 코드에서 이전 서버를 제거합니다
- 모든 소비자 인프라가 전환된 뒤 공급자 스택에서
main_vlan을 제거합니다
기존 가상 서버 인스턴스를 신규 VLAN에 재할당할 수 없다는 제약을, 서버 자체를 교체하는 것으로 우회 한 점이 이 예제의 핵심입니다.
제로 다운타임 변경
블루-그린(blue-green) 변경 은 신규 인스턴스 생성 → 신규로 사용량 전환 → 이전 인스턴스 제거로 이루어집니다. 스택 같은 컴포넌트 단위라는 점만 다를 뿐, 확장과 축소와 개념적으로 같고 불변 인프라의 핵심 기술입니다.
로드 밸런서처럼 워크로드를 옮기는 메커니즘이 필요합니다. 정교한 구현에서는 워크로드가 비워지고(drain) 새 작업은 신규 인스턴스로 가되, 이전 인스턴스의 모든 작업이 끝날 때까지 기다렸다가 제거합니다. 클러스터의 ‘롤링 업그레이드’ 기능이 이 방식입니다.
이름의 의미도 중요합니다. 블루-그린은 기본-보조 환경이 아니라 실시간으로 서로 전환될 수 있는 동일한 환경 입니다. 다만 데이터 센터 전체를 전환하는 규모는 다루기 어렵습니다. 업그레이드 중인 특정 서비스에 대해서만 수행하는 편이 현실적입니다.
연속성 — MTBF에서 MTTR로
구시대 방식은 예방 을 강조하며 속도와 변경 빈도를 희생해 평균 무고장 시간(MTBF)을 최적화했습니다. 클라우드 시대 방식은 평균 복구 시간(MTTR)을 최적화합니다.
MTTR에 초점을 맞추면 MTBF를 희생하게 된다는 것은 함정입니다. 네 가지 주요 지표에 중점을 둔 팀은 결과적으로 강력한 MTBF를 달성합니다. 요점은 ‘빨리 움직여서 망가트려라’가 아니라 ‘빨리 움직여서 고쳐라(move fast and fix things)‘입니다.
오류 방지를 통한 연속성
구시대에는 실수 수정 비용이 높아 변경할 수 있는 사람을 제한하고, 세부 계획과 설계를 여러 사람이 오래 검토했습니다.
이 방법의 문제는 설계 문서와 구현 사이의 격차 입니다. 다이어그램에서 단순해 보이는 것이 실제로는 복잡할 수 있고, 특히 중요하지 않아 보이는 업그레이드에서 실수가 납니다. 빈도가 낮고 고도로 계획된 대규모 배치 변경은 실패율이 높고 복구도 오래 걸립니다.
코드로 정의된 변경은 다이어그램이나 설계 문서보다 구현을 훨씬 정확하게 나타냅니다. 작업하면서 지속적으로 통합·적용·테스트하면 프로덕션 준비가 그 과정에서 완료됩니다. 자주 변경함으로써 오류를 예방한다 는 태도의 역전이 핵심입니다.
다만 시스템이 복잡해질수록 프로덕션에서 코드가 어떻게 작동할지 정확히 테스트할 수 있는 능력은 줄어듭니다. 그래서 배포 전 테스트로 잡을 수 있는 것과 없는 것을 구분하고, 프로덕션 시스템의 가시성을 개선해 위험을 완화 하는 방법을 알아야 합니다.
빠른 복구를 통한 연속성
오류를 완전히 예방할 수 있다는 가정은 비현실적이므로 빠르고 쉽게 복구할 수 있어야 합니다. 느슨하게 결합된 컴포넌트가 멱등성 있는 코드로 정의되어 있으면, 코드를 다시 적용하는 것만으로 인스턴스를 복구하거나 삭제 후 리빌드할 수 있습니다.
| 실패 유형 | 대응 |
|---|---|
| 상태 확인 실패 | 플랫폼·런타임이 컴포넌트를 자동 삭제하고 다시 빌드 |
| 코드와 어긋난 드리프트 | 지속적으로 코드를 적용해 자동 되돌림, 또는 파이프라인 단계를 수동 트리거 |
| 상태 확인을 통과하는 오작동 | 자동 수정 불가. 컴포넌트를 고장난 것으로 플래그 지정해 교체하거나 직접 삭제 후 리빌드 |
사람이 개입해야 하는 시나리오에서는 일련의 단계를 나열하는 대신 필요한 모든 단계를 수행하는 작업 하나를 호출 하게 만들어야 합니다. 목표는 비상 시에 복구 방법을 생각할 필요가 없게 만드는 것입니다.
지속적인 재해 복구
구시대에는 재해 복구를 비정상적인 이벤트로 보고, 워크로드를 대기 상태로 유지해 온 별도 하드웨어 집합으로 전환했습니다. 문제는 그 복구 작업을 몇 달에 한 번, 심하면 1년에 한 번 테스트하거나 아예 테스트하지 않는다는 점입니다.
지속적인 재해 복구는 인프라를 프로비저닝하고 변경하는 데 쓰는 것과 동일한 프로세스·도구를 그대로 활용 합니다. 인프라 코드를 적용해 실패한 인프라를 리빌드하고, 데이터 손실 방지를 위한 자동화를 덧붙입니다.
그러면 팀은 일상 작업 중 하루에도 여러 번 복구 프로세스를 사용하게 됩니다. 누군가 프로비저닝을 중단시키거나 데이터 손실을 유발하는 코드를 넣으면 보통 파이프라인 테스트 단계에서 실패하므로 신속하게 고칠 수 있습니다. 재해 복구를 예외가 아니라 일반 작업의 확장으로 취급하는 것이 훨씬 안정적입니다.
카오스 엔지니어링
Netflix의 Chaos Monkey와 Simian Army는 지속적 재해 복구를 한 단계 더 밀어붙여 프로덕션 시스템에 오류를 주입 하고 연속성 메커니즘의 효율성을 입증했습니다.
카오스 엔지니어링
시스템의 능력에 대한 확신을 구축하기 위해 시스템을 실험하는 학문
무책임하게 프로덕션 중단을 유발하는 것이 아닙니다. 시스템이 처리할 것으로 예상되는 특정 실패 시나리오 를 실험하는, 탐지와 복구 메커니즘이 올바로 작동함을 입증하는 필수 프로덕션 테스트입니다. 목적은 시스템의 어떤 변경이 이 메커니즘을 방해할 때 빠른 피드백을 얻는 것입니다.
실패에 대한 계획
실패는 불가피하므로, 피해가 적고 다루기 쉬운 형태가 되도록 조치합니다. 실패 시나리오 워크숍에서 각 시나리오의 가능성과 영향을 맵으로 만들고, 조치 목록의 우선순위를 정해 팀 백로그에 반영합니다.
시나리오마다 던지는 질문이 정해져 있습니다.
| 조건 | 질문 |
|---|---|
| 원인과 예방 | 어떤 상황이 실패로 이어지고, 실패를 줄이려면 무엇을 할 수 있는가 |
| 실패 모드 | 장애가 발생하면 어떻게 되고, 사람의 개입 없이 피해를 줄이려면 무엇을 할 수 있는가 |
| 탐지 | 실패를 어떻게 감지하고, 더 빨리 또는 미리 감지하려면 무엇이 필요한가 |
| 수정 | 장애를 복구하기 위해 어떤 조치를 취해야 하는가 |
디스크 공간 부족 시나리오를 예로 들면, 사용 패턴을 분석해 디스크를 확장하는 것이 예방이고, 기록 실패 시 트랜잭션 수락을 중지하도록 애플리케이션을 고치는 것이 실패 모드 개선이며, CEO가 고객 항의 전화를 받기 전에 알림을 받는 것이 탐지입니다. 이상적인 실패 모드는 시스템을 완전한 작동 상태로 유지합니다. 애플리케이션이 응답을 멈추면 로드 밸런서가 그쪽으로 트래픽을 보내지 않는 식입니다.
시나리오를 정의하는 데서 그치면 안 됩니다. 파이프라인 단계나 카오스 실험으로 시나리오가 실제로 처리되는지 증명하는 검사 를 구현해야 합니다. 실패에 대한 계획은 한 번의 워크숍이 아니라 지속적인 프로세스입니다. 개발·테스트 환경을 포함해 문제가 생길 때마다 새로운 시나리오를 추가합니다.
연속성을 증분적으로 향상시키기
모든 오류를 정상적으로 처리하는 야심찬 복구 수단을 정의하기는 쉽지만, 그 절반이라도 만들 시간과 리소스가 있는 팀은 없습니다. 시나리오의 가능성·잠재적 손상·구현 비용을 기준으로 구현 스토리를 나누고 백로그에서 우선순위를 정합니다. 예를 들어 디스크가 부족할 때 자동 확장하는 것도 좋지만, 부족해지기 전에 알림을 받는 것이 더 중요합니다.
변화하는 시스템에서의 데이터 연속성
클라우드 시대의 실행 방법은 리소스의 일상적인 삭제와 확장을 권장하면서 데이터 문제는 가볍게 다룹니다. 12-factor 애플리케이션은 스테이트리스로 구현되지만, 현실의 시스템에는 대부분 데이터가 있습니다.
데이터가 걸리면 앞의 기술들이 그대로 통하지 않습니다. 스토리지 인프라의 병렬 인스턴스를 실행하면 불일치나 손상이 발생하고, 점진적 배포는 롤백에 의존하는데 데이터 스키마 변경은 롤백이 불가능할 수 있습니다.
| 방법 | 내용 | 한계 |
|---|---|---|
| 잠금 | 특정 리소스를 잠가 삭제 명령에서 보호 | 보호된 리소스에 변경을 적용하면 스택이 부분 수정 상태로 남아 서비스가 중단됨. 근본적으로 수동 변경 구간을 만들어 실수를 부름 |
| 분리 | 데이터 호스팅 리소스를 별도 스택으로 떼어냄. 디스크 볼륨을 분리했다 재연결하면 컴퓨팅 인스턴스를 자유롭게 리빌드 | 데이터를 호스팅하는 스택 자체의 연속성 전략은 여전히 필요. 문제 범위를 좁힐 뿐 |
| 복제 | 분산 데이터베이스 클러스터처럼 노드 간 데이터를 복제. 리빌드된 노드에 다른 노드에서 데이터가 다시 로드됨 | 대규모 호스팅 장애로 너무 많은 노드가 손실되면 실패. 첫 번째 방어선일 뿐 |
| 리로드 | 백업하고 복원. 리빌드 전에 백업하고 신규 인스턴스에 다시 로드 | 백업과 복구 사이의 변경은 손실. 트랜잭션 로그 스트리밍으로 최소화 가능 |
DBaaS를 쓰면 데이터 연속성을 통째로 벤더에 이전할 수 있습니다. 리로드에서는 스토리지 서비스의 내구성 차이도 활용합니다. AWS S3 같은 오브젝트 스토리지는 EBS 같은 블록 스토리지보다 강력한 내구성을 보장하므로, 데이터를 오브젝트 스토리지 볼륨에 복사하거나 스트리밍해 백업을 구현할 수 있습니다.
최고의 솔루션은 분리·복제·리로드의 조합입니다. 분리로 시스템의 다른 부분을 유연하게 관리하고, 복제로 대부분의 시간 동안 데이터를 사용 가능하게 유지하며, 리로드가 더 극단적인 상황의 지원 방안이 됩니다.
테스트되지 않은 백업은 백업이 없는 것과 같습니다
백업뿐 아니라 복구 프로세스도 자동화하고 정기적으로 실행 해야 합니다. 이미 시스템의 여러 측면에 자동화된 테스트를 쓰고 있다면 백업에도 같은 작업을 할 수 있습니다. 프로덕션 여부와 관계없이 파이프라인에서 또는 카오스 실험으로 복원 프로세스를 실행합니다.
비교 / 트레이드오프
실시간 인프라를 바꾸는 세 가지 방식은 무엇을 늘렸다 줄이느냐에서 갈립니다.
| 인프라 수술 | 확장과 축소 | 블루-그린 | |
|---|---|---|---|
| 무엇을 다루나 | 스택 도구의 데이터 구조 | 스택 코드의 리소스 정의 | 컴포넌트·인스턴스 전체 |
| 스택 인스턴스 | 두 번째 인스턴스를 만들어 리소스를 이동 | 기존 인스턴스만 변경 | 두 환경을 나란히 유지 |
| 파이프라인 통과 | 도구 명령을 직접 실행하므로 우회 | 각 단계가 파이프라인으로 딜리버리 | 각 단계가 파이프라인으로 딜리버리 |
| 멱등성 | 없음. 시작 상태를 가정 | 있음 | 있음 |
| 언제 쓰나 | 다른 방법이 없을 때의 최후 수단 | 공급자 인터페이스 변경의 기본기 | 인스턴스 통째 교체, 불변 인프라 |
연속성에 대한 두 시대의 전제도 정면으로 갈립니다.
| 구시대 | 클라우드 시대 | |
|---|---|---|
| 최적화 대상 | MTBF (예방) | MTTR (복구) |
| 변경에 대한 태도 | 비싸고 위험하므로 최소화 | 자주 변경함으로써 오류를 예방 |
| 신뢰의 근거 | 설계 문서와 다중 검토 | 코드와 자동화된 테스트, 프로덕션 가시성 |
| 재해 복구 | 비정상 이벤트, 별도 대기 하드웨어, 드문 테스트 | 일반 작업의 확장, 동일 도구, 상시 실행 |
내 생각
- “완성될 때까지 프로덕션에 올리지 않는다”가 사실 가장 위험한 전략입니다. 미완성 변경을 붙들고 있는 기간이 길수록 통합 비용과 실패 반경이 함께 커집니다. 병렬 인스턴스·피처 토글·확장과 축소는 전부 “미완성을 안전하게 올려 두는” 장치이지 편법이 아닙니다.
- 확장과 축소는 인프라만의 이야기가 아닙니다. API 응답 필드 변경, DB 컬럼 rename, 큐 메시지 포맷 변경에 똑같이 씁니다. 신규 필드 추가 → 소비자 전환 → 이전 필드 제거의 3단계로 나누면 배포 순서에 대한 조율 자체가 필요 없어집니다.
- 피처 토글의 진짜 비용은 만드는 게 아니라 지우는 것입니다. 토글은 추가할 때 티켓을 만들지만 제거는 아무도 안 만듭니다. 도입 시점에 제거 조건과 담당을 같이 적어 두지 않으면 몇 년 뒤 아무도 끄지 못하는 조건문이 됩니다.
- 인프라 수술은 “쓰면 안 되는데 결국 쓰게 되는” 기술입니다.
terraform state mv로 급한 불을 끈 뒤 그 사실을 기록하지 않으면, 다음 사람은 코드와 실제 상태가 왜 어긋나는지 영원히 모릅니다. 편집 자체보다 편집을 남기지 않는 것이 사고를 만듭니다. - 데이터가 붙는 순간 모든 무중단 기법의 난이도가 한 단계 올라갑니다. 스테이트리스 서비스는 블루-그린으로 끝나지만 DB는 스키마 변경 롤백이 안 되므로, 애초에 롤백이 아니라 앞으로만 가는 마이그레이션(expand-migrate-contract) 을 전제로 설계해야 합니다.
- 복구 절차를 문서로 쓰는 대신 명령 하나로 만드는 것이 실질적입니다. 장애 시간에 위키를 열어 단계를 따라가는 순간 이미 늦었고 실수가 납니다. 평소 파이프라인에서 매일 돌아가는 복구 작업만이 새벽 세 시에도 작동합니다.
관련 개념
- Ch08 코드를 지속적으로 테스트하고 딜리버리한다 — 각 증분 변경을 딜리버리하는 파이프라인
- Ch12 서버 변경 관리 — 불변 서버와 블루-그린 교체의 기반
- Ch14 코드형 클러스터 구축 — 서비스형 클러스터와 패키지형 클러스터 배포의 차이
- Ch15 시스템을 작고 간단하게 빌드한다 — 변경 범위를 줄이기 위한 컴포넌트 크기
- Ch17 스택을 컴포넌트로 사용하기 — 스택 간 통합점과 의존성 검색
- Ch20 팀 워크플로 — 자동화 지연, 구성 드리프트, 지속적 적용