이 글은 케빈 호프만의 무료 전자책인 "클라우드 앱의 12가지 요소를 넘어서(Beyond the Twelve-Factor App)"에서 발췌한 내용이다. 여기에서 전자책 전체를 다운로드 할 수 있다.
"클라우드 앱의 12가지 요소를 넘어서(Beyond the Twelve-Factor App)"은 Heroku에서 발표했던 "클라우드 앱의 12가지 요소(The Twelve-Factor App)"을 토대로 클라우드 기반의 앱 구축을 위한 최신의 모범 사례들을 반영하여 새로운 가이드라인을 제시하고자 한 것이다. (역자주 : "클라우드 앱의 12가지 요소(The Twelve-Factor App)"은 Heroku에서 클라우드 기반의 앱(웹앱 또는 SasS)를 개발할 때 고려할 12 가지의 요소들에 대해 설명한 문서이다. 한국어 버전은 https://12factor.net/ko/ 에서 볼 수 있다). 이 책에서 우선순위를 고려하여 몇 가지 요소들의 순서를 바꾸었고, 클라우드에서 실행되는 모든 애플리케이션에서 고려해야 할 원격측정(telemetry), 보안(security) 및 "API 우선(API First)" 개념 등을 새로운 요소로 추가하였다. 이렇게 새로 정리한 15가지 요소 가이드라인은 다음과 같다.
원래 12가지 요소에서 빌드, 릴리즈, 실행(Build, release, run)에서는 빌드 단계와 실행 단계를 엄격하게 구분해야 한다고 설명한다. 매우 훌륭한 조언이긴 하지만, 이 가이드라인을 고집한다면 미래 어떤 시점에서 어려움을 겪을 수도 있다. 또한, 이 글에서는 빌드, 릴리즈, 실행(build, release, run) 이라는 세 단계에 별도로 디자인 단계를 추가하였는데, 이들 단계와 디자인 단계를 구분하는 것은 매우 중요한 의미가 있다.
디자인 단계에서 실행 단계까지의 흐름은 아래 그림과 같이 표현할 수 있다. 이 흐름은 폭포수(Waterfall) 다이어그램이 아니고, 디자인부터 실행까지 반복되는 사이클이다. 물론 이 주기에 걸리는 시간은 팀이 처리할 수 있는 시간으로 각 팀의 상황에 따라 달라질 것이다. 팀에서 CI/CD 파이프라인에 충분히 익숙한 상황이라면, 디자인부터 프로덕션 환경에서 실행까지 몇 분밖에 안걸릴 정도로 매우 빠르게 처리될 수도 있다.
그림 1. 디자인, 빌드, 릴리즈, 실행 주기
컴파일 결과를 생성하는 빌드 프로세스를 통해서 하나의 코드 베이스를 얻게 된다., 컴파일 결과물은 애플리케이션에서 보면 외부 정보인 설정(Configuration)와 결합하여 최종 릴리즈(immutable release)가 된다. 이 최종 릴리즈는 클라우드 환경(개발, QA, 프로덕션, 등)으로 전송되어 실행된다. 이런 과정에서 가장 중요한 점은 각각의 디플로이먼트 단계를 독립적으로 수행해야 한다는 점이다.
디자인(Design)
폭포수(Waterfall) 모델로 응용 프로그램을 개발하던 방식에서는 애플리케이션을 디자인하느라 많은 시간을 사용하며, 디자인이 끝나기 전까지는 단 한 줄의 코드도 작성하지 못하는 경우가 있다. 이런 방식의 소프트웨어 개발 방식은 가능한 자주 애플리케이션을 릴리즈 해야 하는 최근 환경에는 적합하지 않다.
애플리케이션을 자주 릴리즈한다는 것이 디자인을 하지 않는다는 의미는 아니다. 대신, 릴리즈 할 수 있는 작은 기능을 디자인한다는 의미이고, 전체적으로는 개발해야 할 것을 알려주는 상위 수준의 디자인이 있어야 한다. 그러나, 이러한 상위 수준의 디자인은 바뀔 수도 있다는 것을 알고 있어야 하며, 작은 디자인은 다만 전체를 완성하는 하기 위한 것이 아니라 반복주기의 일부로 받아 들어야 한다.
애플리케이션 개발자가 애플리케이션 의존성을 잘 이해하고, 벤더나 다른 번들에 대한 의존성을 선언하고 정리하는 과정이 디자인 단계이다. 즉, 개발자는 애플리케이션에서 어떤 라이브러리를 사용할 것이고, 그 라이브러리가 릴리즈에 꼭 포함되어야 하는 지를 디자인 단계에서 결정하게 된다.
빌드(Build)
빌드 단계는 저장소에 있는 소스 코드가 버전이 부여된 이진 코드로 변환되는 단계라고 할 수 있다. 이 단계에서는 디자인 단계에서 선언된 의존성을 확인하여, 이를 포함한 결과물을 묶어내는 과정이 진행된다(종종 그냥 단순히 "빌드"라고 한다). 자바의 경우, 빌드는 WAR[1] 또는 JAR 파일을 만드는 것이며, 다른 언어와 프레임워크에서는 ZIP 파일 또는 바이너리 실행파일을 만들게 된다.
빌드는 CI(지속통합, Continuous Integration) 서버에서 처리되는 것이 가장 이상적이며, 대개의 경우 빌드와 배포 사이에는 1:N 관계가 된다. 하나의 빌드 결과는 여러 환경으로 릴리즈되거나 배포될 수 있고, 어떤 상황에서라도 빌드한 내용은 예상한대로 실행되어야 한다. 빌드 결과의 불변성과 다른 요인에 대한 준수(특히 환경 패러티)는 애플리케이션이 QA 환경이든 프로덕션 환경이든 동일한 결과를 가질 것이라는 신뢰성을 얻게 된다.
"제 컴퓨터에서는 되는데요"라는 문제점을 발견했다면, 이 것은 이러한 4가지 단계가 독립적이지 않다는 명확한 신호인 셈이다. 팀에서 CI 서버를 꼭 사용하도록 한다면, 이런 저런 사전 작업이 많이 보이긴 하지만, "하나의 빌드, 다양한 배포" 패턴으로 작업할 수 있을 것이다.
일단 코드 베이스가 어떤 환경에서도 잘 동작할 것이라는 신뢰가 생기고, 그래서 프로덕션 릴리즈를 걱정하지 않게 되면, 코드를 체크인하고 한달이 아닌 몇시간에 지속적인 배포(continuous deployment) 및 릴리즈와 같은 클라우드 기반 애플리케이션의 놀라운 장점을 확인할 수 있을 것이다.
릴리즈(Release)
클라우드 기반 애플리케이션의 릴리즈는 보통 애플리케이션이 클라우드 환경으로 푸시되는 것이라고 할 수 있다. 빌드 결과와 실행 환경 정보, 애플리케이션 설정 정보를 통합하여 만들어낸 고유한 결과물을 릴리즈라고 할 수 있다.
릴리즈는 유일해야 하고, 모든 릴리즈는 시간정보(timestamp)나 자동증가 번호 와 같은 고유 ID로 구분되는 것이 이상적이다. 빌드와 릴리즈가 1:N 관계임을 다시 생각해 보면, 릴리즈를 빌드 ID로 구분하는 것은 좋은 방법이 아니라는 말이 이해될 것이다.
CI 시스템에서 애플리케이션을 빌드하여 build-1234 라는 ID를 붙였다고 가정해 보자. CI 시스템에서는 이를 개발/스테이징/프로덕션 환경으로 릴리즈하게 될 것이다. 이때 어떤 방법으로 각각의 경우를 구별할 것인지는 당신에게 달려있지만, 빌드된 결과와 각 환경에 따른 설정 값이 결합된 것이 하나의 릴리즈라고 본다면, 모든 릴리즈마다 고유한 값을 부여하는 것이 올바른 방법이 될 것이다.
릴리즈 이후에 문제가 생기면, 기존의 릴리즈로 롤백하는 것이 필요한 경우가 발생할 수도 있는데, 이때 최종적으로 릴리즈한 것이 무엇인지를 정확히 알고 있어야 한다. 이러한 이유에서 각 릴리즈마다(설정 정보와 함께) 변하지 않는 고유한 식별자를 부여하고 관리하는 것이 필요하다.
특정 시점의 릴리즈를 다시 만들어내지 못해서 생기는 수많은 문제들이 있는데, 빌드와 릴리즈 단계를 분리하고, 각 단계의 결과물을 각각 저장하고 관리하여 롤백을 하거나 이전 버전을 조사할 때 많은 도움이 될 것이다.
실행(Run)
실행 단계는 대개 클라우드 서비스를 통해 수행되며(비록 개발자가 애플리케이션을 실행해야 하지만), 실행을 위해 필요한 세부 사항은 클라우드 서비스 제공자 마다 달라진다. 하지만, 애플리케이션을 어떤 컨테이너(Docker, Garden, Warden 등)에 포함시키고, 이들 컨테이터 프로세스가 실행되면서 애플리케이션을 실행하게 되는 것이 일반적인 패턴이다.
CD(Continuous Delivery) 파이프라인을 통해서 여러 클라우드에 배포되는 상황이라면 개발자가 자신의 워크스테이션에서 애플리케이션이 잘 실행되는 것을 확인하는 것만으로 해결하기 어려운 문제들이 종종 발생한다. 그러나, 이 문제는 개발자가 클라우드 기반 애플리케이션을 개발할 때 제한받지 않는 느낌을 받을 필요가 있기 때문에 해결해야 할 가치가 있다.
애플리케이션이 실행되면, 클라우드 런타임 환경은 항상 실행되어야 하고, 문제가 없는지 모니터링되고, 로그를 수집하고, 동적 스케일링과 장애 대응(falut tolerance) 와 같은 다른 관리 작업이 필요하다.
결국 이 가이드의 목표는 자동화된 테스트와 배포를 통해 높은 신뢰성을 유지하면서 배포 속도는 최대로 하기 위한 것이다. 우리는 클라우드에서 애플리케이션이 실행되고 있더라도, 개발의 민첩성과 속도라는 장점을 얻을 수 있다. 하지만, 디자인, 빌드, 릴리즈 및 실행 가이드라인을 따르게 되면, 애플리케이션이 정상동작할 것이라는 신뢰성을 희생하지 않으면서 제품 릴리즈에 필요한 속도와 민첩성을 최대로 얻을 수 있다.
---
[1] 여러 가지 이유에서 WAR(그리고 ERA) 파일은 JAR 파일에 비해 클라우드 환경에 적합하지 않다. 외부에서 제공되는 서버나 컨테이너에 대한 의존성이 있기 때문이다.
*****
원문 : Design, build, release, run
번역 : 권원상
이전 글 : 효과적인 퍼포먼스 엔지니어링이란 무엇인가?
다음 글 : 도커 기반 워크플로우를 효율화하는 네 가지 팁
최신 콘텐츠