変化に強いインフラの取り組み(2)
アーキテクチャ
APIを用いてインフラを操作し、さらにコンテナを使ったアプリケーションで「変化に強いインフラ」に取り組んできました。続いて、それらを最大限活用するためにはどういったアーキテクチャにするといいかを考えたいと思います。
アーキテクチャを考える上で、The Twelve-Factor AppとThe UNIX Philosophyと自動化について解説していきます。
The Twelve-Factor App
Heroku創業者の一人であり初代CTOでもあるAdam Wegginsによって書かれたアプリケーションの方法論があります。
Wantedlyはこの基本原則にのっとってアプリケーションを実装しています。Dockerでサービスを運用する上での基本の型となります。Dockerが使いづらいと思ったときは、この方法論に沿っていないケースが多いです。
このサイトでは12個の方法論が紹介されています。
コードベース(Codebase)
バージョン管理されている1つのコードベースに対して複数のデプロイ(qa、stage、production)ができるようにしましょう。さらに、コードとアプリケーションを一対一にし、コードの書き換えがなくても開発環境、本番環境で動作できるようにしましょう。
依存関係(Dependencies)
依存関係を明示的に宣言し分離しましょう。RubyでいうGemfileとGemfile.lockです。サーバー上で直接gem installするのではなく、パッケージマネジメントツールを使いましょう。
設定(Config)
設定を環境変数に格納しましょう。DATABASE_URLなどの設定を環境変数に格納し、コードを変更することなく、どの環境でも動くようにしましょう。
バックエンドサービス(Backing services)
バックエンドサービスをアタッチされたリソースとして扱い、ネットワーク越しに他のサービスを利用しましょう。特にデータストア系はサーバー上に保持せず、外に出しましょう。
ビルド、リリース、実行(Build、Release、Run)
ビルド、リリース、実行の3つのステージを厳密に分離しましょう。例えば「git pushの度にビルドが行われ、masterにマージされたタイミングでリリースを行い、コンテナを実行(Run)させる」といった流れを決めましょう。
プロセス(Processes)
アプリケーションを1つもしくは複数のステートレスなプロセスとして実行しましょう。コンテナはカーネル機能でプロセスを隔離して実行します。そのため、デーモンで起動しないようにしましょう。
ポートバインディング(Portbinding)
ポートバインディングを通してサービスを公開しましょう。ポートバインディングはDockerであればホストポートとコンテナポートで接続する前提になっています。そのため、コンテナで動くものはアドオン形式と同じようにバックエンドサービスとして利用できます。
並行性(Concurrency)
プロセスモデルによってスケールアウトできるようにしましょう。並行性はスケールアウトがプロセス単位でできるようにしましょう。これはdocker runを複数回実行すれば複数のプロセスが起動するため、Dockerを使うことで実現可能です。
廃棄容易性(Disposability)
高速な起動とグレースフルシャットダウンで堅牢性を最大化しましょう。突然の死やSpikeが来たとしても、とっさに動かせるようにしましょう。
開発/本番一致(Dev/prod parity)
開発、ステージング、本番環境をできるだけ一致させた状態を保ちましょう。一致させないと、サーバー作業と呼ばれる保守業務が増え、どんどんメンテナンスが難しくなります。
ログ(Logs)
ログをイベントストリームとして扱い、STDOUTで出力しましょう。sshでログインして見るのではなく、docker logsなどでAPIを通してイベントストリームで確認しましょう。
管理プロセス(Admin processes)
管理タスク(マイグレーション等)を1回限りのプロセスとして実行しましょう。railsを使っている場合は、rake db:migrateコマンドがわかりやすい例だと思います。サーバーに入って調査系以外で本番作業するのはやめましょう。
The UNIX Philosophy
『UNIXという考え方―その設計思想と哲学』(著:Mike Gancarz)という本があります。この本にはUNIXの原理原則が書かれています。モノリシックで大きなサービスにならないようにする上で、私たちが大切にしている考え方です。
- Small is beautiful.(小さいものは美しい)
- Make each program do one thing well.(一つのプログラムには一つのことをうまくやらせる)
- Choose portability over efficiency.(効率より移植性を優先する)
- Use software leverage to your advantage.(ソフトウェアを梃子(てこ)として使う)
- Avoid captive user interfaces.(過渡の対話的インターフェースを避ける)
