Search
Duplicate
🥿

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

Category
S/W 엔지니어
Tags
The Twelve-Factor App
방법론
methodology
Architecture
확장성
scalability
concurrency
disposablity
GitOps
Created time
2023/11/19

Introduction

The Twelve-Factor App 개인적 해석 1/2 에서 이어지는 The Twelve-Factor App에 대한 나머지 6개 지침에 대한 해석이다. 앞선 글과 마찬가지로 주로 참조한 문서는 다음과 같다.

The Twelve-Factor App

7. Port Binding: 포트 바인딩으로 서비스 내보내기

Export services via port binding (포트 바인딩으로 서비스 내보내기)
이 문장, “The twelve-factor app is completely self-contained and does not rely on runtime injection (Twelve-factor app은 완전히 자기완결적이어야. 그리고 런타임 주입에 의존하지 말라)”이 핵심인 듯. 문서에서는 예전에 많이 사용하던 방식인 Tomcat에 app을 주입하여 app을 노출시키는 방식을 자기완결적이지 않은 예로 시작부터 들이밀며 위 문장을 강조한다.
runtime injection과 port binding이 무슨 관계인지 잘 이해가 안되었는데, 여러 app을 주입할 수 있되 각 app이 자체적인 port를 갖는 컨테이너를 만드는 게 가능하기 때문. 물론 컨테이너로 인해 app 간에 독립성을 해치게 되므로 좋은 구조가 아님은 분명하다. 실제 이렇게 동작하는 컨테이너가 있는지도 의심스럽고.
이와 같은 관점에서, 각기 다른 port는 ‘일반적으로’ 각기 독립적인 실행 환경을 가짐을 암시한다는 측면에서, 나아가 service 식별 수준을 높인다는 수준에서 port binding을 논한 것으로 이해한다. 보통 한 process가 한 port를 점유한다는 측면에서 아래 8. Concurrency와도 의미가 연결되는 듯.

8. Concurrency: 프로세스 모델을 통한 규모 확장

Scale out via the process model (프로세스 모델을 통한 규모 확장)
프로세스 모델이라 함은 workload type 별로 process type(정확히는 process가 인스턴스화 될 프로토타입)을 나누라는 의미이다. 그리고 프로세스 모델을 취하는 이유는 concurrency, 즉 확장 용이성을 위함이다. 문서는 이에 반하는 예로 PHP와 JVM을 드는데, PHP의 request 량에 따른 child process spawn의 경우 동일 workload type임에도 parent와 child process가 이질적이란 점이 이슈로 보이고, JVM의 multi threading은 thread 사용 자체보다는 단일 JVM 내에서 서로 다른 workload type이 함께 운용되는 케이스를 문제 삼는 듯.
문서에서 process를 가리켜 first class citizen이라 표현하는데, 이는 workload에 대한 process 중심의 처리 정도로 이해한다(JVM 등에서는 process의 낮은 가시성을 문제 삼는다). 여담으로 first class는 함수형 언어에서 주로 사용되는 용어로, 데이터처럼 생성, 할당, 전달, 반환할 수 있는 function을 first class function이라 부른다. 결국 first class citizen란 연산 가능한 무엇을 의미하는데, 연산이 computing에서 가장 중요한 속성이기에 이 같이 칭하지 않았나 싶다.

9. Disposability: 빠른 시작과 우아한 종료를 통한 강건성 극대화

Maximize robustness with fast startup and graceful shutdown (빠른 시작과 우아한 종료를 통한 강건성 극대화)
무엇을 권하는지는 선언문이 다른 지침에 비해 이해하기 쉽다. 오히려 빠른 시작과 우아한 종료가 강건성과 무슨 관계인지 파악하는 데 초점을 두는 것이 좋을 듯.
빠른 시작의 경우 몇 초 내로 서비스 준비 상태로 도달하도록 하도록 권장하는데, OS의 프로세스 매니저는 프로세스가 준비 완료 상태에 도달할 때까지 해당 프로세스에 매달리기 때문이라고. OS의 강건성을 유지하기 위한 방안이겠다. 오히려 scaling이 빨라지는 것은 부차적인 장점.
강건성은 빠른 시작보다 우아한 종료에서 더 중요한데, 데이터 무결성에 직접적으로 영향을 미칠 뿐 아니라 일반적으로 시작보다는 종료에 신경을 덜 쓰기 때문이다. SIGTERM 신호에 대한 처리(종료 프로세스 시작) 뿐 아니라, 예기치 않은 종료(e.g. 하드웨어 실패 등)도 함께 고려해야.

10. Dev/prod parity: 개발, 스테이징, 운영 환경을 가능한 한 유사하게

Keep development, staging, and production as similar as possible (개발, 스테이징, 운영 환경을 가능한 한 유사하게)
형상 간 환경을 맞추지 않으면 그 차이가 오류를 만들기 때문에 누구나 최대한 맞추길 원할 듯 하지만 여러 이유로 달라지는 것이 현실이겠다. 문서에서 다루는 ‘차이’는 software / hardware 뿐 아니라 배포에 걸리는 시간, 코드 작성/배포 주체의 차이도 언급하며 이들 차이조차 최소화하거나 없어야 한다고.
The twelve-factor app이 CD(Continuous Deployment)를 고려한다는 측면에서 GitOps 도입은 자연스러운 본 지침에 대한 구현이 될 듯. 무엇보다 Docker, Docker Compose, 특히 Kubernetes는 code level에서 환경 구성을 지원하기에 이질성 최소화에 유리하다.
지원 서비스(e.g. MySQL, MQ)에 대한 환경 간 이질성 해소는 예전보다 훨씬 쉬운데, 요즘 왠간한 지원 서비스는 낮은 H/W 사양에서 잘 동작함과 동시에 apt-get 과 같은 packaging system 덕에 설치가 용이하기 때문이다.

11. Logs: 로그를 이벤트 스트림으로 다루기

Treat logs as event streams (로그를 이벤트 스트림으로 다루기)
구체적 행동 지침은 모든 log를 stdout으로 보내어 app 자신이 log 파일을 관리하지 않도록 하는 것이라고. log 관리는 FluentBit과 같은 stream 처리 앱이 별도로 취합하여 Elasticsearch, Splunk, Hadoop/Hive와 같은 분석 시스템으로 전달 처리하도록 한다.
stdout 으로의 log 통합의 장점은 무엇보다 표준화로 인한 호환성 증대로 보인다. app 별로 각기 다르게 log가 처리되면, app 별로 logging 구조 파악이 요구되어 일관된 처리가 어려워진다.
참고로 stream은 연속적이고 순차적인 데이터 요소의 시퀀스로서, 데이터를 일련의 연속적인 블록이나 요소로 다루며(임의 접근 없음), 일반적으로 한 번에 하나씩 처리된다고(ChatGPT 왈).

12. Admin processes: 어드민/관리 작업을 일회성 프로세스로 실행

Run admin/management tasks as one-off process (어드민/관리 작업을 일회성 프로세스로 실행)
여기서 admin process라 함은 보고서 생성, 데이터/스키마 마이그레이션이나 console(REPL shell)을 통한 app 관리 스크립트 실행 등을 의미한다. 핵심은 어드민/관리 작업 역시 앞서 논했던 app과 동일한 실행 환경, 나아가 앞서 논한 지침, 예컨데 Concurrency의 항목에서의 프로세스 모델이라던가, Codebase 또는 Build, release, and run을 동일하게 따르는 데 있는 듯 보인다. 그 이유는 app과의 동기화 이슈를 피하기 위해서라고.
본 지침의 이해에 Redhat의 문서가 도움이 되었는데, 아래의 한 문장이 돋보인다.
The admin process is not separate from the overall SDLC, but rather part of it(어드민 프로세스는 (app의) SDLC와 분리된 무엇이 아닌 일부이다).

첨언

Distilled. 공식 문서의 정확한 의미를 파악하는데 꽤나 어려움이 있었다. 중요한 사항만 압축해서 설명하려다보니 그리 되었으리라 예상하지만(글이 길면 안 읽게 된다. 특히나 요즘 같이 책 안 읽는 세상에서는…), 좀 심하다 싶어 이 첨언까지 남기게 된다. 그런데 본 글은 사실 상 ‘주석(comment)’에 해당하다보니 더 어려울 수도(ㅡㅡ;). 그럼에도 서비스형 S/W 개발에 이 만한 주요 지침을 찾기 어려우니 공식 문서를 참조하면서라도 내용 파악을 권하고 싶다.