Search
Duplicate
🥿

The Twelve-Factor App 개인적 해석 1/2

Category
S/W 엔지니어
Tags
The Twelve-Factor App
방법론
methodology
codebase
config
dependency
반의존성
Created time
2023/11/17

Introduction

web app, SaaS와 같은 서비스형 소프트웨어를 구축하기 위한 일종의 Best Practice인 Twelve-Factor 앱에 대한 개인적 해석이다. 얼마 전에야 우연히 마주쳤는데, Google이나 Red Hat, Wikipedia에도 소개되는 등 꽤나 유명한 듯. 알고보니 무려 2011년에 발행되었다고. 알게 모르게 이미 따르고 있는 관례가 대부분이지만 이들 중 중요한 사항을 추출하고 명시화했다는 점이 유의미해보인다. 다음은 주로 참조한 문서.
아래는 한국어로 번역된 The Twelve-Factor App 방법론 링크이다. 여담으로, 번역을 누군가 해줘서 고맙기는 한데, 요즘엔 자동 번역 품질이 너무 좋다보니 그 고마움이 반감되고는 하는게 함정. 오히려 잘못된 의역의 위험이 줄기에 이를 더 선호하기도. 실제 아래 번역에서 그 위험성이 보인다. backing service를 백엔드 서비스라 번역을…

The Twelve-Factor App 방법론의 이점

Google Cloud 문서의 표현을 그대로 옮긴다.
Twelve-Factor 설계를 활용하면 앱 구성요소를 분리할 수 있으므로 각 구성요소를 쉽게 바꾸거나 원활하게 확장 또는 축소할 수 있습니다. 이러한 요소는 모든 프로그래밍 언어 또는 소프트웨어 스택과는 별개이므로 Twelve-Factor 설계를 다양한 앱에 적용할 수 있습니다.

The Twelve-Factor App

1. Codebase: 버전 제어로 추적되는 단일 코드베이스, 다수의 배포

One codebase tracked in revision control, many deploys (버전 제어로 추적되는 단일 코드베이스, 다수의 배포)
요즘에 이렇게 사용하지 않는 경우가 있나 싶기도. 여튼, Git과 같은 버전 관리 시스템을 사용하고, 단일 app에는 단일의 독립적 (Git) repository를 사용하란 이야기이다.
GitOps 시대의 git branching 모델 : TBD(Trunk Based Development) 관점에서 위의 단일 repo에 대응하는 다수의 환경은 developer 1, 2 경우 개별 branch로 표현되고 staging은 trunk (main 또는 master) branch에, production은 trunk branch의 특정 commit에 version tagging된 무엇일 듯. 관련 Red Hat 문서는 배포 스크립트 조차도 단일 codebase로의 통합을 논하는데, GitOps를 위한 Git 관리 전략에서는 application code와 configuration code 분리를 논한다는 데 충돌이 있다. 개인적으로는 RedHat이 좀 과격히 해석한 것이 아닌가 싶다.

2. Dependencies: 명시적 선언과 의존성 격리

Explicitly declare and isolate dependencies (명시적 선언과 의존성 격리)
본 지침의 선언문(명시적 선언과 의존성 격리)이 전체를 잘 요약한 듯 보인다.
python의 경우, The Twelve-Factor App에서 언급한 종속성 선언을 위한 pip은 사실상 requirements.txt를 의미한 것으로 보인다. ‘dependency declaration manifest’란 정의에도 알맞고.
별도로 종속성 격리를 언급한 이유는 무언가 ‘종속석 선언’만으로는 모자란 부분이 있기에 그랬을 듯 한데, virtualenv를 언급한 점으로 보아 환경(environment)으로부터의 격리를 의미하는 듯. 사실 종속성 선언 자체에도 격리의 의미가 내포한다 생각되지만 특정 환경에 의존적인 codebase가 만들어지는 경우가 다반사이기에 이를 별도로 강조한게 아닌가 싶다.

3. Config: 환경(변수)에 config 저장

Store config in the environment (환경 (변수)에 config 저장)
본 지침 역시 선언문(환경 (변수)에 config 저장)이 전체를 잘 요약한 듯 보인다.
config에는 credential, hostname등 여러 상수가 포함될 수 있는데, 여기서의 config 정의는 각 배포 별로 달라지는 값을 의미하여 배포와는 상관 없는 값은 코드 내부로 들어가도 무방하다고.
환경 변수를 사용함으로 특정 언어, 플랫폼으로의 종속(e.g. Java System Property)을 배제할 수 있다는 점이 유의미한데, 실제 위의 config 정의를 따른다면 이들 값은 특정 언어, 플랫폼에 묶일 이유가 없어질 듯. 무엇보다도 환경 변수는 OS에 의존하지 않는 표준이란 점이 종속성 관리에 유리한 지점.
환경 변수에 config를 저장하면 VCS(version control system)에 credential 등의 민감 정보가 저장되는 위험을 한층 더 줄일 수 있다는 점에서 더욱 유의미.

4. Backing services: 지원 서비스를 연결된 리소스로 취급

Treat backing services as attached resources (지원 서비스를 연결된 리소스로 취급)
지원 서비스(backing service)는 network를 통해 연결된 app을 지원하는 서비스를 의미. RDBMS, MQ, SMTP 서버 등이 예. 다음은 문서의 강조 사항.
‘attach’는 app이 backing service에 URL 또는 config에 저장된 특정 토큰(문서에서는 locator/credentials로 표현)을 통한 접근(access)을 의미. 이에 따라 backing service는 위치에 무관, 즉, local이건 remote이건 또는 third party의 서비스이건 모두 backing service이라고.
‘resource’는 backing service가 app과 약결합(loosely coupled)로 연결됨을 의미하여, 예컨데 코드 수정 없이 자유롭게 연결 해제(detach)됨과 동시에 타 backing service로 교체할 수 있어야 함을 의미한다고.
문서의 backing service 정의 상 위의 ‘attached resource’의 풀이는 당연한 논리적 귀결임과 동시에, 이를 위반한 케이스에 대한 비교 역시 없어 의미 파악이 쉽지 않았는데, 결국 약결합이 핵심으로 보인다. config 사용 등을 통해 backing service 주소에 대한 코드 내에서의 직접적 참조를 제거하는 것이 한 예가 될 듯.

5. Build, release, run: 엄격히 빌드와 실행 단계를 나누도록

Strictly separate build and run stages (엄격히 빌드와 실행 단계를 분리)
빌드는 app 실행 번들을 만드는 단계로 container 환경 관점에선 image를 만드는 단계에 해당한다. 릴리즈는 실행 번들에 실행될 환경에 대한 config과 버전을 붙이는 단계이며, 마지막으로 실행 단계는 릴리즈 단계까지 수행된 실행 번들을 실행하는 단계라고.
이들 세 단계를 엄격히 나누는게 어떤 의미를 갖는지 파악이 역시나 쉽지 않은데, 일단 실행의 경우 문서는 복잡하지 않은 실행 단계를 가져야 유사시 상황에서도 손쉽게 restart를 할 수 있음을 논한다. 앱 실행에 빌드나 릴리즈 단계의 무엇이 필요로하다면 빠른 대처가 쉽지 않겠지… 릴리즈의 분리는 버전닝을 고려했을 때 감사/추적 등을 고려한 것으로 이해된다.
GitOps를 도입하면 GitOps의 원칙에 따라 본 factor의 요구는 자연스럽게 만족된다.

6. Processes: 하나 이상의 상태 비저장 프로세스로 앱을 실행

Execute the app as one or more stateless processes (하나 이상의 상태 비저장 프로세스로 앱을 실행)
핵심은 ‘stateless(상태 비저장)’에 있는데, ‘프로세스’에 대한 강조 부분은 프로세스로 앱을 실행하지 않는 케이스는 극히 찾아보기 어려울 것이기 때문이다. 헌데 REST에 이어 Kubernetes 등에서도 이미 stateless에 대한 강조는 이미 오래된지라 새삼스러울 것은 없다. 상태 저장은 factor #4의 backing service를 이용하라고.
이외에 주안점으로 문서에서 언급한 부분이 있다면 프로세스 간 상태 비공유(share-nothing) 정도이겠다. 상태 공유는 concurrency 처리나 scalability에 악영향을 미친다는 점을 고려하면 될 듯.