この記事は、The Twelve-Factor Appを補足し、実際に現代的なWebアプリケーションで適用する場合の注意点などを紹介するシリーズです。下記の原文を読んだ上でのワンポイント解説になります。
概要
- 設定は環境変数のみで分岐する
- 設定はコードに含めない
これは何を表しているか
「1. コードベース」では、「ステージング」や「本番」といった環境によってコードを分けたりしてはいけないとありましたが、コードの中に入っている設定は別です。
設定とは、例えばデータベースの接続先、APIのキーといったものから、稼働環境のURLや、環境によって違う全ての値が対象となります。
フレームワークによっては、それ自体に環境毎に設定ファイルを作る機能が用意されている場合がありますが、それらを使ってしまうと環境毎に設定ファイルが必要になってしまい、環境を作るたびにコミットが生まれます。また、修正にもコミットして修正が必要になってしまいます。このような環境の違いがコードそのものに含まれていると、違う環境で動かすことが困難になってしまいますので、環境要因によるものはコードに含めてはいけません。
コードに含めないとなるとどこか別の場所に保存しないといけませんが、環境変数を使用することで多くの環境で共通で設定を差し込むことができます。特にsystemdやDockerでは環境変数の注入が簡単になっておりますので、積極的に利用することができます。
実際に運用する場合
設定をコードに含めないことによって、設定だけを書き換えて好きな環境でアプリケーションを起動することができるようになります。パスワードなどの機密情報をGitHub等にpushしてしまうと、そこから機密情報が漏れるといったリスクもありますので、設定が切り出されているのはセキュリティ的な点からも好ましい構成になります。
Dockerを使っている場合は前述の通り簡単に環境変数を扱うことができますが、開発環境でDockerを使わない場合はdotenvのようなツールを使って.envファイルを読めるようにするか、direnvのようなツールで注入する必要があります。
どう環境変数化するかについては、例えば「本番環境では動くけどステージングでは動かない」みたいなものを用意したい場合は、「なぜ動かしたくないのか」という理由を考え、そこの切り分けは「本番かステージングか」ではなく「それを動かす理由」の環境変数で切り替えるのが良いでしょう。
また、nginxやphp-fpmといった既成のサーバーアプリケーションの場合、起動前に環境変数を読むのが難しいですが、これらも環境変数で設定を切り分けるべきです。これらの場合は envsubst
コマンドや、類似のテンプレートエンジンで設定ファイルを事前にレンダリングしてから起動するという手法で解決することができます。
フロントエンドの場合、「ビルド時に必要な設定」と「実行時に必要な設定」が存在します。ビルドはCIなどで自動で行い、実行はWebサーバー上で行われますので、それぞれ必要なタイミングが変わります。特にフロントエンドは構造上ビルド後に環境変数を読むことは困難ですが、12Factor Appではビルド結果を環境毎に分けてはいけませんので、起動時に一手間かける必要があります。