Parity before cutover

Alex O'Callaghan

컷오버 전에 패리티부터

원문은 Alex O'Callaghan님이 에 게재했습니다. 이 블로그 구독하기

우리는 여러 팀과 서비스가 의존하는 서비스를 운영한다. 수년간 이 서비스는 두 개로 존재했다. 온프레미스 서버에 배포된 Python 2 기반의 프로덕션 버전과, 별도 브랜치에서 클라우드 마이그레이션을 기다리며 기존 버전을 대체할 날만 기다리던 현대화된 Python 3 버전이다.

많은 레거시 업그레이드가 이런 모습이다. 최종 상태는 명확하다 — 새로운 언어 버전, 새로운 인프라, 그리고 사라질 기존 시스템 — 그래서 팀들은 곧장 그곳을 향해 달린다. 작업은 오래 유지되는 브랜치나 “v2” 재작성에서 진행되고, 어려운 작업은 프로덕션과 떨어진 곳에서 해치운 뒤 마지막에 한 번에 전환하자는 것이 계획이다.

착륙하지 못하는 재작성

그 계획은 약속한 성과를 거의 내지 못한다. 새 버전이 릴리스되지 않은 채 머무는 동안 리스크는 사라지지 않고 쌓이기만 한다.

긴급한 수정 사항은 여전히 기존 버전에 먼저 반영되어야 하고, 그다음 새 버전으로 포팅해야 한다 — 그렇지 않으면 잊힌다. 두 버전 사이의 모든 동작 차이는, 의도한 것이든 아니든, 컷오버 이후 하위 팀에 의해 발견되기를 기다리는 버그이며, 그때는 원인을 규명하기가 가장 어렵다.

오래 유지되는 브랜치는 모든 것을 하나의 이벤트로 묶기 때문에 효율적인 것처럼 느껴진다. 실제로는 리스크를 한 시점에 집중시키고, 문제가 있다는 것을 알려줄 피드백을 지연시킬 뿐이다.

앞으로 가기 위해 뒤로 가기

우리가 마이그레이션을 맡았을 때, 본능은 최종 상태를 향해 밀어붙이는 것이었다. 현대화된 버전을 클라우드에서 실행하고 컨수머 이전을 시작하는 것이다. 나는 먼저 한 걸음 뒤로 가자고 주장했다. 다른 어떤 것을 옮기기 전에 현대화된 버전을 기존 인프라에서 프로덕션으로 실행해, 기존 버전과 새 버전이 동일한 코드가 되도록 하자는 것이었다.

레거시 호스트의 운영체제는 너무 오래되어 Python 지원이 3.6에서 끝났고, 현대화된 버전은 3.7을 대상으로 했다. 우회할 수도 있었다 — 소스에서 Python을 직접 빌드하거나, 애초에 컨테이너를 고려하지 않고 설계된 호스트에 컨테이너를 얹는 식으로 — 하지만 그런 우회책 하나하나가 이미 복잡한 마이그레이션에 부담만 더할 뿐이었다.

대신 우리는 서비스를 3.6으로 다운그레이드하고 온프레미스 배포 구성을 복원했으며, 설정은 런타임에 환경별로 선택되도록 했다. 하나의 코드베이스로 레거시 호스트와 Kubernetes 모두에 배포할 수 있게 됐다.

버전 다운그레이드는 퇴보처럼 보인다. 그것이 나머지 마이그레이션을 단순하게 만든 이유다.

한 번에 하나의 변수만

동등성을 확보한 뒤에는 모든 릴리스가 두 환경에 모두 배포됐다. 기존 버전과 새 버전 간의 동작 차이는 컷오버 때 한꺼번에 터지는 대신, 작은 단위로 즉시 드러났다. 두 버전 사이에 수년간 쌓인 차이는 기존 인프라가 여전히 폴백으로 남아 있는 동안 점진적으로 해소됐다.

클라우드로 컷오버할 때는 순수한 인프라 변경에 불과했다. “플랫폼 마이그레이션이 성공했는가?”와 “재작성이 성공했는가?”를 동시에 물을 필요가 없었다 — 무언가 고장 나면 코드가 동일했기 때문에 플랫폼 문제임을 알 수 있었다. 컷오버는 지루했고, 지루하다는 것이 바로 원하는 바다. 이는 마이크로 프론트엔드에서 React를 점진적으로 업그레이드하는 것과 같은 원칙이다. 변수를 차례대로 배치해 각 릴리스마다 한 가지만 바꾸는 것이다.

codeinfrastructureversionbig bang: everything at oncePython 2on-premPython 3.6on-premPython 3.6KubernetesPython 3.10Kubernetes

최종 상태가 아니라 경로를 배포하라

마이그레이션이 끝나자 수년간 막혀 있던 Python 업그레이드는 일상적인 릴리스로 배포됐다 — 기존 호스트의 버전 상한이 사라졌고, 업그레이드할 코드베이스도 하나뿐이었기 때문이다. 최종 상태는 우리가 곧장 그곳을 겨냥하지 않았기 때문에 더 빨리 도착했다.

브랜치가 수개월째 열려 있거나, 재작성이 다른 팀의 마이그레이션을 기다리고 있다면, 보통 한 번에 너무 많은 일을 하려는 신호다. 지금 당장 릴리스할 수 있는 중간 상태를 찾아라, 설령 한 걸음 뒤로 가는 것처럼 보여도 괜찮다. 어려운 것은 최종 상태가 아니라 거기로 가는 경로이며, 가장 안전한 경로는 한 단계씩 릴리스할 수 있는 경로다.

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.

댓글