プログラミング初心者がアーキテクトっぽく語る

見苦しい記事も多数あるとは思いますが訂正しつつブログと共に成長していければと思います

Twelve-Factor App

Twelve-Factor Appはモダンなアプリケーションの開発、Deploy、Scaleを成功させるための12のBest Practiceである。

2012年にHerokuのAdam Wiggins氏が発表し、https://12factor.net/にて公開されている。

Twelve-Factor Appはマイクロサービスを前提としており、かつクラウド環境の引っ越しを強く意識している。世の中、このような要件の開発ばかりではないので自分のプロジェクトに当てはまらない部分もあるだろうが、考え方は大変参考になるので理解しておくとよいだろう。


1. Codebase

  • GitなどのVCSでTrackする
  • 1アプリケーショにつき1 Repository
  • Repositoryにあるcodebaseをdevelopment, testing, staging, productionなどすべてのStageで利用する

Bad practice

  • 1つのアプリケーショが複数のRepositoryにまたがっている
    • CI/CDのAutomationが難しくなる
  • 複数のアプリケーションを1つのRepositoryで管理する
    • 個別に開発、リリースする柔軟性が失われる
    • 分割して個別にバージョニングした上でそれぞれの間のDependencyを構築するべき

2. Dependencies

  • 依存関係は明示的に宣言する
    • Manifestファイルなどに書かれていると明示性が高い
    • Package Managerを使うとよい
      • NuGet (.NET)
      • Maven/Gradle (Java
      • npm (Node.js)
      • pip/virtualenv (Python
  • 依存関係を分離する
    • あるアプリケーションの依存関係が他のアプリケーションに影響を与えないようにする
      • Pythonのvirtualevn/pyenv
      • Javaのcustom class loader
      • コンテナ

Bad practice

  • packageのインストールを自動化するときにcurl/wgetが存在するという前提で使用しない
    • 環境によっては特定のシステムツールが利用不可になっていることがある
    • もしDeployした環境にcurl/wgetが存在しなかったらエラーになってしまうので利用前に確認すること

3. Configuration

  • Deployment環境ごとに異なる値をConfigurationとして管理する
  • Configurationは環境変数に入れる
    • 言語非依存
    • GitにPushされるリスクが低い
    • codebaseを変更することなく環境に合わせて変更できる
  • Configurationはcodebaseには決して含めないこと
    • つまりGitにコミットしてはならない
  • Credentialの保管も注意が必要
    • Gitにコミットすると多くの人に見られてしまう
  • 環境変数以外の方法としてConfiguration管理専用ツールやCloudベースのconfiguration管理サービスもある
    • k8sのSecretsやconfigMap
    • AWSのKMSやSecrets Manager

Bad Practice

  • constants(定数)でConfigurationを管理する
    • 環境ごとにコードを変更しビルドする必要がある
  • Java System Propertyファイルや.NETのweb.configなどでConfigurationを管理する
    • 言語依存
    • 環境ごとにそれらファイルを変更し、ビルドする必要がある

4. Backing Services

  • Backendサービスは交換可能なattached resourcesとして扱う。
  • 例えばデーベースへのアクセス情報はConfigurationとして保存する。
    • データベースを交換するときはConfigurationを変更すればよい。

Bad Practice

  • データベースへのアクセス情報がcodebaseの一部として管理されている
  • 障害が発生したデータベースを交換するためにビルドが必要になる

5. Build, Release, Run

  • コードを修正してリリースするプロセスは下記の通り。
    1. Build:実行できるものをつくる
    2. Release:環境依存のConfigurationと組み合わせて版数を付与する
    3. Run:実行
  • このBuid/Release/Runの順番を守ること

Bad Practice

  • 環境ごとにBuildする
  • Run中のコードを直接変更する。

6. Process

  • プロセスはステートレスなものとする。
  • メモリやFile systemの内容に依存した処理をしない。
  • セッション情報などはMemcachedやRedisなどのin-memory session databaseに保存する。

7. Port Binding

  • サービスの中でWeb server libraryを使ってサーバをたてること
  • Web server libraryの例
  • システム側のWebサービスTomcatJBOSSIIS)に依存しないself-containedなサービスになる。
  • これにより環境ごとのサーバ設定が不要になる。また他のサービスのBackend Serviceになれる。

8. Concurrency

  • Scale outできるようアプリケーションを並列実行可能な構造にする。
    • ステートレス
    • 他プロセスとなにかを共有しない
    • systemdやForemanなどでプロセスを管理する

Bad Practiice

  • Scale upしかできないサービス
    • Scale upは限界がある

9. Disposability

  • プロセスの起動と停止を高速に行えるようにする
  • プロセス停止はGracefulに実施できるようにする
    1. SIGTERMを受信する
    2. 新規Requestの受付停止する
    3. 処理中のRequestを完了させる
    4. リソースを開放して終了する
  • これでいつでも起動・停止できるようになり、Scale out/inしやすい
  • 突然の終了(HW障害等)にも備える
    • Beanstalkdのようなbackground processing queueing softwareで処理を永続化する
    • Queueに溜まっていた未完了のJobをプロセス復旧後に処理できる

10. Dev/Prod Parity

  • 3つのギャップを埋める。

時間のギャップ

  • 開発からデプロイまでを数時間で行えるようにする。

人材のギャップ

  • 開発者が運用まで行えるようにする。

ツールのギャップ

  • ローカル、開発環境、本番環境によってツールが異ならないようにする。
  • 開発者はSQLMemcachedなども面倒くさがらずに開発環境にいれる。

11. Log

  • ログはファイル出力しない
  • ファイルはScale in時にサービスごと消えてしまうので意味がない。
  • 標準出力に出力し、ツールで1箇所に集約する。
  • 環境が異なっても標準出力は常に行える。
  • 集約したログを画面、ファイル、Splunkなど好きなところに送る。

12. Admin Process

  • 管理作業はスクリプト化してcodebaseの一部として管理、バージョニングする。
  • 手動作業はエラーが発生しやすい。
  • codebaseの一部として管理しないとアプリケーション版数と管理作業の整合性が取れなくなる。