본문 바로가기
개발/개발방법론

The Twelve-Factor App (1/2)

by cscscs 2023. 6. 3.

The Twelve-Factor App (1/2)

^기술부채^


글에 들어가기 앞서

서비스를 개발하다 보면, 아래와 같은 고민들을 많이 하게 됩니다.

  • config를 어떻게 관리해야 하지?
  • 로그는 어떻게 처리하는 것이 좋지?
  • 코드를 어떻게 관리하지?
  • 의존성은 어떻게 관리하지?
  • 트래픽이 몰려서 서비스 성능을 올려야 하는데, 여러 머신에서 구동했을 때 충돌이 일어나네..?! 🚨🚨🚨

기존에 똑똑하신 선조분께서 컨벤션을 잘 잡아주신 경우는 컨벤션을 따라가면 되지만,
처음 프로젝트를 킥오프 하는 상황에서 컨벤션을 정해야 하는 경우가 필연적으로 존재합니다. 😢😢😢 (˚ ˃̣̣̥⌓˂̣̣̥ )(˚ ˃̣̣̥⌓˂̣̣̥

)

☄✨🌟💫⭐    그런 상황에서 기준이 될 수 있는 `The Twelve-Factor App` 을 소개합니다!  ⭐💫🌟✨☄

 


 

The Twelve-Factor App

The Twelve-Factor App는 12가지 요소를 구현할 때 규칙들을 제시합니다.
서비스 개발 시 해당 규칙들을 지켰을 때, 아래 장점들을 얻을 수 있다고 제시합니다.

  • 서비스의 생산성과 확장성이 증가
  • 실행 환경 사이의 이식성이 극대화
  • 지속적인 배포 가능
  • 클라우드 환경에 적합
  • 최소한의 변경으로 확장 (scale up / out) 가능

🤔진짜?🤔

구현시 신경써야 하는 12가지 요소는 아래와 같습니다.

 코드베이스  하나의 코드베이스는 revision control (git 등)으로 관리
 각 환경(live, stage 등)에 배포 (많은 배포)
 의존성  명시적으로 선언되고 분리된 의존성
 Config  환경 변수에 저장된 config
 Backing Service
 (DB, Redis, 다른 백엔드 서비스 등등)
 backing service를 리소스 취급
 빌드, 배포, 실행  빌드와 실행 단계를 완전히 분리
 프로세스  application을 stateless한 process들로 실행
 포트 바인딩  서비스를 port binding을 통해 공개 (외부 노출)
 동시성  process를 scale out (app을 process model로 구성)
 죽을 가능성
(ex. graceful shutdown)
 fast startup과 graceful shutdown으로 안정성 극대화
 개발, 스테이징, 프로덕션 환경  개발, 스테이징, 프로덕션 환경을 최대한 비슷하게 유지
 로그  로그를 event stream 취급
 admin 프로세스  admin, maintenance 작업을 일회성 프로세스로 실행

 

음.. 별거 없군! (이해 못함😭)

하나씩 차근 차근 살펴봅시다~ 🥰

 


 

I. Codebase (코드베이스)

어플리케이션은 git과 같은 VCS(Version Control System)으로 부터 관리되어야 합니다.

1:1 관계

codebase는 임의의 단일 레포지토리를 뜻합니다. codebase와 app간에는 일대일 관계가 항상 성립해야 합니다.

즉, app은 단일 레포지토리로 구성되어야 합니다.
여러 codebase (여러 레포지토리)로 구성된 시스템은 app이 아니고 분산 처리 시스템(distributed system)입니다.
또한 여러 app들이 같은 codebase를 공유한다면, 12 Factor App 원칙에 위배됩니다.
(해당 케이스에서는 codebase가 여러 app에 얽혀있으면 코드베이스 수정이 어려워서 그런 듯 합니다. (*필자의 추측))

deploy는 실행중인 app의 instance를 의미합니다.
app은 여러 deploy들에 배포될 수 있습니다.
app과 codebase는 1:1 관계라 했으니, 하나의 codebase가 여러 deploy에 배포되게 됩니다.
단, 각 deploy들은 다른 버전이 활성화 될 수 있습니다. (ex. product는 v1.2.4, stage, dev는 v1.3.0)

 


 

II. Dependencies (의존성)

The Twelve-Factor App에서의 config를 아래와 같이 관리합니다.

  1. 모든 의존성들을 explicit하게 dependency declaration manifest를 통해 관리
  2. 시스템 도구를 포함한 implicit한 의존성이 존재해서는 안됨

모든 의존성(Dependency)들은 dependency declaration(의존성 선언) manifest를 통해 명시되어야만 합니다.
App은 system 레벨의 패키지의 암묵적인(implicit) 존재에 의존해서는 안됩니다. (ex. 시스템에는 curl이 존재할거다~)
App은 dependency isolation 도구를 활용해 implicit한 의존성이 "leak in"되지 않도록 보장합니다. (python의 venv 등)
만약 curl등의 시스템 도구가 필요한 경우는 해당 도구를 app과 통일해야 합니다.

 


 

III. Config (설정)

하드코딩된 config

우선 config의 정의부터 생각해봅시다. config는 deploy간 다를 수 있는 모든 것(everything)을 의미합니다.
The Twelve-Factor App에서의 config를 아래와 같이 관리합니다.

  1. 코드로부터 완전히 분리되어야 합니다.
  2. config는 환경변수 (environment variable)로 관리되어야 합니다.

1. config의 코드로부터 완전히 분리

이유는 config는 deploy환경마다 미묘하게 다를 수 있기 때문입니다.
즉, 해당 코드베이스를 오픈 소스화하더라도 임의의 credential이 유출되지 않아야 합니다.
여기서 주의해야 하는 부분은 config의 정의는 internal application config를 포함하지 않는다는 것 입니다.

2. config를 환경변수(environment variable)에 저장

config를 환경변수로 관리함으로써 각 배포마다 독립적으로 관리되게 됩니다.
환경변수들은 서로에게 영향을 끼치지 않습니다. 
이를 통해, app이 더 많은 deploy로 확장될 때 유연하게 scale up할 수 있습니다.

 


 

IV. Backing services (ex. DB, Redis, 다른 백엔드 서비스 등등)

backing service는 app이 행하는 normal operation의 부분으로써 소비되는 임의의 서비스를 뜻합니다.
데이터베이스, 메세징큐, SMTP서비스, 캐싱시스템 등이 backingservice에 해당됩니다.

 

 

the twelve-factor app에서 어플리케이션은 backing service를 리소스로써 취급합니다.
코드는 같은 종류의 backing service를 이용 할 때 local 서비스의 이용과 thrid party 서비스의 이용간에 차이가 없어야 합니다.
즉 코드베이스의 수정 없이, 같은 종류의 다른 backing service로 전환이 가능해야 합니다.
어플리케이션의 입장에서는 둘의 차이는 config crendential 값의 차이일 뿐 그이상 그이하도 아닙니다.

backing service를 리소스 취급함으로써 어플리케이션과 backing service간의 loose coupling이 만족되게 됩니다.
만약 프로덕션의 DB가 하드웨어등의 이슈로 문제가 발생했다면, 코드 수정없이 빠르게 새로운 DB를 붙이는 배포를 수행할 수 있습니다.

 


 

V. Build, release, run (빌드, 배포, 실행)

Build, Release, Run stage

Codebase는 deploy로 3개 stage를 통해 변환되어야 합니다.

  1. build stage:
    codebase를 build (실행 가능한 bundle)로 변환
    빌드 stage에서 vendor들에게 dependency들을 fetch하고, binary들과 asset들을 컴파일
  2. release stage
    build stage가 만든 build를 받아서, deploy의 현재 config와 결합시킴
    결과 release는  실행 환경에서 즉시 실행 가능한 상태로 준비 됨
  3. run stage
    선택된 release에 대한 application process들을 시작해서, application을 실행 환경에서 동작하도록 함

The twelve-factor app에서는 build, release, run stage에 대해 엄격한 분리가 사용됩니다.

롤백 가능

배포 도구는 이전 release로 롤백할 수 있는 기능이 있어야 합니다.
모든 release는 unique한 release ID를 가져야 합니다. release된 timestamp일 수도 있고, incrementing한 숫자일 수 있습니다. (ex. `2023-06-01-12:34:56`, `v100`)
build stage는 에러를 예방하기 위해 복잡해도 (실행 시간이 오래 걸려도) 괜찮지만, run stage는 최대한 적은 moving part들을 유지해야 합니다.
run stage는 서버가 리부팅되거나, crash된 process들이 restart될 때 일어날 수 있기 때문입니다.

 


 

To Be Continue

양이 생각보다 많아서, 2부로 나누어 작성하도록 하겠습니다!

다음글 > The Twelve-Factor App (2/2)

 

'개발 > 개발방법론' 카테고리의 다른 글

The Twelve-Factor App (2/2)  (0) 2023.06.04