> [!abstract] Introduction > 이번 글에서는 지속적 배포*Continuous Deployment*에 대해 알아봅니다. # 개발 현장에서 소비자까지 소프트웨어 공학에서 지속적 배포가 어떤 의미를 가지는지 이해하기 위해서는 지속적 배포가 없었던 시절부터 지속적 배포의 등장, 그리고 그 이후의 변화를 알 필요가 있다. ## 낭만의 시대 지속적 배포*Continuous Deployment*가 본격적으로 대두된 것은 2000년대 초반부터다. 소프트웨어가 개발된 순간부터 프로덕션 환경으로, 다시 말해 소비자에게 전달되기까지 가는 여정은 험난하기 그지없었다. ![[TheTypicalPathToProductionBeforeTheEarly2000s.png]] 개발이 완료된 소프트웨어 제품이 프로덕션 환경으로 가는 과정에서 기여자*contributor*에 의해 수정이 가해지면 그것이 반영될 때까지 어느 정도의 시간이 필요했고, 빌드는 수작업으로 이루어졌으며, 설정과 의존성 설정은 버전관리 시스템의 통제가 없는 상태에서 이루어졌다. 배포 과정에 대한 문서도 제대로 되어 있지 않아서 배포를 위해서는 매우 세심하게 과정을 다루어야 했다. 심지어 소프트웨어 제품에 문제가 없는지 확인하기 위한 테스트는 매번 직접 수행해야만 했다. 이로 인해 제품의 최초 개발부터 소비자에게 배포되는 릴리즈 버전까지의 여정*release life cycle*은 몇 달, 심지어 몇 년이 걸릴 때도 있었다. ## 자동화 다행히 요즘은 기업들이 소프트웨어 제품을 소비자에게 전달하기까지 필요한 시간을 단축하기 위해 많은 노력을 기울인 끝에 그 기간을 며칠까지 줄일 수 있었다. 이 과정에서 큰 역할을 수행한 것이 바로 자동화*automation*이다. ![[TheTypicalPathToProductionToday.png]] 자동화가 시간을 줄이는 원리는 간단히 말해 사람이 내리는 결정을 최대한 줄이는 것이다. 빌드, 테스트, 배포 등 프로덕션 환경까지 가는 과정에서 수작업으로 이루어지던 주요 작업들은 이제 젠킨스*Jenkins*나 IaC(Infrastructure as Code), 단위 테스트*unit test*, E2E(end-to-end) 테스트 등으로 대체되었다. 이 길을 닦아준 것은 바로 XP(eXtreme Programming), [[DevOps]], CI(Continuous Integration), CD(Continuous Delivery)와 같이 새롭게 등장한 업무 프랙티스들이다. # 지속적 배포의 토대 지속적 배포가 정확히 무엇이고 어떻게 작동하는 것인지 알기 위해서는 지속적 배포에 도달하기까지 걸어온 길을 살펴볼 필요가 있다. 우선 XP부터 살펴보자. ## eXtreme Programming 테스트, 리뷰, 통합, 배포와 같은 작업은 코드가 배포되는 과정에 있어서 중추적이지만 귀찮고 복잡한 작업이기도 하다. 그래서 이런 작업은 개발 사이클의 최후반부에 비정기적인 수작업을 통해 이루어졌다. 여기에 변화를 가져온 것이 바로 XP다. XP는 [[Agile Software Developement|애자일 소프트웨어 개발]]의 방법론 중 하나로, 소프트웨어 개발에서 가장 중요한 부분을 최대한 자주 할 것을 강조한다. 여기에는 두 개발자가 하나의 컴퓨터를 공유하며 끊임없이 서로의 코드를 공유하는 페어 프로그래밍*Pair Programming*, 코드를 쓰기 전에 테스트 코드부터 작성하는 테스트 주도 개발*Test-Driven Development*, 그리고 주 브랜치[^1]에 코드를 최대한 자주 합치는 CI도 포함된다. 새로운 방법들이 등장하는 것은 아니지만 기존의 프랙티스를 끝까지 밀어붙인다. ## DevOps 데브옵스*DevOps*는 소프트웨어의 개발과 운영을 하나의 방향으로 합치기 위한 운동의 이름이다. 데브옵스는 경쟁하는 개별 부서로 운영되던 소프트웨어의 개발과 운영 사이의 간극을 줄이기 위한 문화를 통칭하며, 여기에는 자동화, 부서 간 소통과 협업, 그리고 부서 재구성 등이 포함된다. 자세한 내용은 [[DevOps]]를 참고하면 된다. ## Continuous Integration 지속적 통합*Continuous Integration*은 이미 XP의 프랙티스 중 하나로 이미 등장했던 개념으로, 큰 변화를 반영하는 과정에서 생기는 오류도 많고 과정 자체도 복잡하니 작은 변화를 빠르게 빠르게 추가하자는 의미에서 시작되었다. CI는 코드의 변화를 "몸통"*Trunk*[^2]에 최대한 자주 저장하는 것으로 달성할 수 있다. 오직 이곳에서만 진정한 통합이 이루어질 수 있으며, 주 브랜치에 직접 코드를 푸시하는 몸통 기반 개발*Trunk-based Development, TBD*로 달성하는 것이 가장 효과적이다. 그러나 그렇다고 해서 CI를 구현하기 위해 다른 브랜치가 없어야 한다는 것은 아니다. 이를 위해서는 주 브랜치를 제외한 다른 브랜치의 수명을 짧게 하고 풀 리퀘스트*Pull Request, PR*를 최소 하루에 한 번 이상 하는 것이다. ![[CIAutomatedPipeline.png]] CI의 또다른 측면은 자동화된 빌드 파이프라인*Automated Build Pipeline*이다. 위 그림은 자동화된 빌드 파이프라인의 구조를 대략적으로 나타낸 것이다. 코드가 "몸통" 역할을 수행하는 브랜치로 합쳐지거나 갱신되면, 팀 전체가 공유하는 중앙 서버에서 버전 관리 시스템을 통해 이를 알아챌 것이다. 그러면 빌드가 자동으로 이루어지고 그 결과 아티팩트[^3]가 생성된다. 아티팩트가 만들어지면 파이프라인은 테스트와 코드 검사를 자동으로 수행해 아티팩트를 검증한다. 이에 대한 피드백은 팀 전체에 공유되고, 실패한 검사가 있다면 자동으로 알려준다. 하지만 CI는 단순한 도구 그 이상으로, 팀을 운영하기 위한 여러 프랙티스와 상호 합의가 포함되어 있다. 파이프라인의 상태는 곧 검증된 소프트웨어를 만드는 능력을 상징하며 그러한 소프트웨어를 배포하는 일은 그다지 오래 걸리지 않을 것이다. CI에서 처음 등장한 중앙화된 파이프라인의 등장은 이후 등장하는 모든 자동화 기법의 밑바탕이 되었다. ## Continuous Delivery CI가 등장하고 얼마 지나지 않아 다음 단계의 개념인 지속적 전달*Continuous Delivery, CD*이 등장했다. CD는 현재 가장 최근에 확립된 표준 프랙티스로 여겨지고 있고, 많은 자동화 파이프라인 도구들이 CI와 더불어 CD를 지원한다. 물론 CD를 지원하기 위해서는 기존의 자동화 파이프라인을 조금 더 확장할 필요가 있다. 파이프라인 자체가 언제나 최신 버전의 코드를 빌드하고 검증해야 하고, 여기에 더해 언제나 모든 환경으로 배포할 수 있는 능력을 갖추어야 한다. 이 능력은 배포의 자동화와 반복을 보장하는 IaC(Infrastructure as Code)와 프로비저닝*provisioning*[^4] 도구를 통해 구현된다. ![[CDAutomatedPipeline.png]] 가장 흔한 CD 구현에서는 모든 빌드가 스테이징 단계까지 자동으로 배포될 것이다. 자동화된 테스트를 통과하고 나면, 해당 빌드가 릴리즈가 될 가능성도 높아질 것이다. 이 릴리즈 후보를 프로덕션 환경에 실제로 릴리즈하는 것은 필요에 따라 같은 파이프라인 도구를 통해 이루어질 것이다. 그러나 실제로는 CD를 구현할 때 프로덕션 환경까지 자동으로 배포하도록 구현하지는 않는다. 대신, 프로덕션에 준하는 환경까지는 자동으로 배포가 이루어지도록 한 뒤 아래와 같이 프로덕션 환경으로 배포하기 위해 사람이 수동으로 허가하도록 구현한다. ![[FinalGateToProduction.png]] 이 "마지막 버튼"이 바로 지속적 전달과 지속적 배포의 주요 차이점이다. 프로젝트가 커질 수록 세심한 관찰이 요구되고, 발견하지 못할 만큼 오류가 코드 깊숙이 숨어있을 가능성도 덩달아 올라간다. 배포되고 나서야 발견할 수 있는 오류도 존재한다. 만약 긴 시간을 직점 검증해야 한다면 지속적인 프로세스라고 보기도 어렵다. 이것이 바로 지속적 전달에서 지속적 배포로 나아가기 위한 마지막 관문이다. # 지속적 배포의 의미 이제 XP, DevOps, CI, CD를 기반으로 지속적 배포가 무엇이고 어떤 의미를 지니는지 알아보자. 개발부터 최종 배포까지 이어지는 대부분의 과정을 자동화했지만, 아직 한가지 관문이 남았다. 앞서 언급했던 "마지막 버튼"이다. 지속적 배포에 도달하기 위한 마지막 관문은 바로 이 과정을 자동화하는 것이다. ![[TheContinuoudDeploymentAutomatedPipeline.png]] 그래서 지속적 배포는 지속적 전달의 구현으로도 간주될 수 있으며, 코드에 대한 모든 변화가 프로덕션에 배포될 준비를 마쳤다고 보장한다. 핵심은 사람의 손길이 닿을 필요가 없는 전 과정의 자동화다. 스테이징과 같은 중간 단계에서 기다릴 일도 없고, 수동으로 테스트할 일도 없다. 이 변화를 프로덕션 환경으로 보낼지 말지에 대해 사람이 고민할 필요가 없는 것이다. 소프트웨어가 지속적으로 배포된다는 것은 곧 주 브랜치에 푸쉬되거나 머지되는 커밋이 곧 프로덕션 환경에 반영된다는 의미다. 개발이 곧바로 배포로 이어지는 환경이 탄생하면서 코드에 대한 피드백을 받는 시간을 며칠 혹은 몇 시간에서 몇 분까지 줄일 수 있게 되었다. 배포 주기가 줄어들게 되니 한번의 배포가 끼치는 영향이 줄어들고, 배포 후 제품에 문제가 생겼을 때 발생하는 위험도 같이 줄어들었다. 그러나 무엇보다 지속적 배포가 가장 큰 영향을 끼친 부분은 비즈니스다. 만약 프로덕션 단계의 코드 변화가 개발 단계와 동일하게 가볍고 빠르다면, 소프트웨어 제품 또한 그와 같은 속도로 개선된다는 것을 의미한다. 이것은 곧 비즈니스 측면에서는 의사결정을 내리는 시간이 뒤로 밀리고 그만큼 최대한 정보를 모아 합리적인 의사결정을 내릴 시간을 벌었다는 뜻이다. 사용자로부터의 피드백도 즉각적으로 돌아오고 그 피드백을 즉각적으로 다음 배포에 반영할 수도 있으니 예상치 못한 변화를 이끌어낼 수도 있다. --- # 출처 - Servile, V. and Farley, D. (2024) _Continuous deployment: enable faster feedback, safer releases, and more reliable software_. First edition. Beijing Boston Farnham Sebastopol Tokyo: O’Reilly Media, Incorporated. [^1]: 이름은 상관없다. `main`일 수도 있고 `master`일 수도 있고, 심지어 다른 이름일 수도 있다. 중요한 것은 그 브랜치가 해당 저장소를 대표한다는 것이다. [^2]: 나무의 중심이 되는 가장 큰 몸통이라는 의미에서 사용하는 Trunk다. 대표적인 버전 관리 시스템인 깃*Git*에서 브랜치*branch*라는 이름을 사용하는 것과 같은 맥락으로 보면 된다. "몸통"은 가장 최근에 작성된 코드가 모이는 곳으로, 이곳에서만 진정한 통합이 이루어질 수 있다. [^3]: Artifact. 프로그램이 작동하기 위한 코드, 의존성, 설정 등이 모두 포함된 번들*bundle*을 의미한다. 그 형태는 .jar나 .war 파일 혹은 컨테이너 이미지일 수도 잇다. [^4]: 여기서는 IT 인프라를 만들고 설정한다는 뜻이다.