ネコの下の記事では、構成ファイルのエントロピーに対処する方法について説明します。
構成ファイルの誕生
むかしむかし、ある開発者は、従業員の給与データを保存するための簡単なWebアプリケーションを作成しました。 彼は2つのベースを使用しました。実際の従業員と給与を使用する実働ベースと、架空のデータを使用するテストベースです。
ある深夜、彼は新しい機能を作業ベースに移し、テストベースへの固定リンクを変更するのを忘れていました。
mysql_connect("db-staging.example.com", "admin", "admin");
翌朝、上司はシステムにログインし、従業員の代わりに神秘的にディズニーの漫画のヒーローに登場したことを発見しました。
上司は満足していません。
この間違いを二度と繰り返さないことを固く意図していたため、開発者はハードドライブのホスト名を変数に置き換えることにしました。
それで最初の設定ファイルが生まれました。
; SVN [db] host = db1.example.com dbname = payrolls user = admin pass = s3cur3
数年が経ちましたが、データベースに接続するための設定は、構成ファイルに入れようとする最初の試みです。 しかし今では、APIキー、サードパーティシステムのトークン、その他のあらゆる種類の必要な情報もあります。これらは不快な機能を持ち、定期的に変更されます。
以前、 buildoでは、 Webアプリケーションは2つの構成ファイルを使用していました。
ScalaサーバーAPIはapplication.conf
ファイルから構成データを読み取ります。 このように見えた:
app { db = { url = "jdbc:postgresql://localhost:5432/app" user = "postgres" password = "" driver = org.h2.Driver keepAliveConnection = true queriesTimeoutSeconds = 1 connectionTimeout = 1000 numThreads = 1 } interface = "0.0.0.0" port = 8082 allowedHostnames = ["localhost"] allowedHeaders = ["Content-Type", "Authorization", "Cache-Control", "Pragma"] #Timeout for reading routine time from file routineTimeDataTimeout = 1 localBackupPath = "/Users/fra/buildo/app/backup" serviceEndpoint = "http://localhost:8083" maximumItemsNumber = 100000000 #Wait 5 seconds before killing all connections waitBeforeKillingConnectionsMillis = 5000 #Size of the buffer used to read and write files streamBufferSize = 4096 }
JSクライアントはconfig.json
JSONファイルを使用しました:
{ "NODE_ENV": "development", "hostname": "localhost", "port": 9090, "apiEndpoint": "https://api-buildo-dev.example.com/v2", "gMapsAPIKey": "abcdefghijklmnopqrstuvwxyz", "title": "Yolo", "username": "test-temp@buildo.io", "password": "test", "debug": "state*,react-avenger*" }
両方のファイルが.gitignore
に追加され、Gitで.gitignore
すること.gitignore
ありませんでし.gitignore
。
環境変数を使用する必要があります!
Twelve-Factor Appマニフェストに精通している可能性があります。マニフェストでは、構成ファイルではなく環境変数に構成情報を保存することを推奨しています。 ただし、これは言語に依存しない便利な構成情報の保存方法であるにもかかわらず、主な問題は解決しません。 アプリケーションにいくつかの構成パラメーターが必要な場合、次の内容のファイルを作成することになります。
export MY_APP_VAR1="foo" export MY_APP_VAR2="bar"
おめでとうございます、これでユニバーサル構成ファイルが作成されました! また、構成力学の最初の法則も発見しました。
構成パラメーターの値は作成または破棄できません。1つのタイプから別のタイプにのみ渡されます。
https://commons.wikimedia.org/wiki/File:Carnot_heat_engine_2.svg
共有とは、注意することです
プロジェクトの作業を始めて初めてリポジトリのクローンを作成するとき、多くの場合、プロジェクトは構成ファイルなしで開始することを拒否します。
$ npm install && npm start [...] Error: Cannot find module './config.json'
通常、私はSlackで質問し、別の開発者がプライベートチャットで設定の作業バージョンを投げます(これはもちろん愚かですが、これを行うのは私たちだけではないことは確かです)。
もう一度前の2つの例を見ると、かなり長いことがわかります。 これは、構成動力学の2番目の法則によるものです。
構成ファイルの合計長は、時間の経過とともに増加するだけです。
実際、数か月前にSlack経由で送信した実際の構成ファイルからいくつかの値を見逃していました。 しかし、これらが正しい設定であり、何らかのテスト構成ではないことを常に確認することは可能ですか?
2番目の法則に対処する唯一の方法は、(開発者の)少しのエネルギーを取り、ほとんど変更されない構成パラメーターを探し始めることです。 これらをコードにハードドライブしたくないかもしれませんが、これらの値を他の形式でリポジトリに注入することを禁止する人はいません。
Scalaのアプリケーションでは、Lightbend Configを使用します。 リポジトリに安全に配置できるデフォルトの構成パラメータを使用して、 reference.conf
を定義できます。
少し前に、 reference.conf
ファイルで何が起こっているかに注意を向け始めました。 これは単なるフレームワークではなく、アプリケーションを実行するために必要なすべての値が含まれる本格的な構成ファイルであることを確認したいです。
これらの値を上書きする場合は、ローカル環境変数を設定するか、 .gitignore
追加されるのでコミットされないapplication.conf
ファイルを作成しapplication.conf
。
これが新しいreference.conf
始まりです。
# This is the reference config file that contains all the default settings. # Make your edits/overrides in your application.conf. app { interface = "0.0.0.0" interface = ${?SERVICE_INTERFACE} port = 8080 port = ${?SERVICE_PORT} ... }
同様の状況はクライアントパーツでもdevelopment.json
ます。ここでは、常にdevelopment.json
ファイルを作成し(コミットを取得します)、オプションのlocal.json
ファイルでオーバーライドできるデフォルト値を含みます(コミットを取得しません)。 また、 production.json
用の設定を含むproduction.json
ファイルを作成します。 この場合、オープンソースライブラリは使用しませんが、独自のシンプルな実装を作成しました 。
たとえば、このような古いアセンブリCIスクリプトを変換できます。
echo '{ "NODE_ENV": "production", "port": 9090, "apiEndpoint": "/api", "uglify": true, "gzip": false, "title": "Awesome App" }' > config.json npm run build
新しい外観に:
NODE_ENV=production npm run build
多くの環境の伝説
ローカルの開発者環境でアプリケーションを実行するのに十分な1つのデフォルト設定がリポジトリにロードされるようにする必要があります。
ここから、構成力学の第三法則が定式化されます:
開発者の環境での理想的な構成ファイルの長さはゼロです。
https://commons.wikimedia.org/wiki/File:Can_T%3D0_be_reached.jpg
しかし、他の環境はどうですか? 実稼働環境でアプリケーションをデプロイすることもできます。 また、ステージングサーバーにわずかな違い(たとえば、より詳細なログ記録)がある可能性もあります。
最初に、オプションの違いの数を減らす必要があります。 同じ設定が環境に適している場合、ほとんどの場合それらを組み合わせる必要があります。
次に、環境ごとに、特定の設定でファイルを作成し、デフォルトの設定を上書きします。 アプリケーションリポジトリのGitまたは別の「インフラストラクチャ」リポジトリに保存します。 開発者は、さまざまな環境の構成をすばやく見つけ、必要に応じてそれらを開発環境に適用できる必要があります。
最後に、Gitでバージョン管理されているアーティファクトがサーバーに自動的に展開されるようにします。 SSH経由でサーバーに入り、設定を手動で修正する誘惑に抵抗します。 Ansible 、 Chef、または別の構成管理ツールを使用します。 または、 Packerを取得して、新しいAMIを構築し、 Terraformで展開します。 自分にとって最も便利なツールを使用しますが、ファイルは常に同期状態に保ちます。
ドッカーの力
Dockerを使用してアプリケーションをパッケージ化します。これにより、環境間の違いが減り、構成ファイルの操作が簡単になります。
次のDocker Composeファイルは、MacBookと本番サーバーの両方で正常に機能します。 APIホストの名前は常にapi
になり、ベースを持つホストはdb
になり、Dockerはこれらの名前を正しいコンテナに関連付けます。 これで、異なる環境に異なるホスト名を登録する必要はありません!
services: web: image: quay.io/buildo/app-frontend ports: - "80:5000" links: - api api: image: quay.io/buildo/app-backend links: - db db: image: postgres
環境固有の設定を1つのファイルに収集するには、 複数のDocker構成ファイルの機能を使用します 。 testing.yml
見ると、テスト環境が非標準のHTTPポートを使用し、開発トークンを含み、異なるデータベース構成をロードしていることがすぐにtesting.yml
ます。
services: web: ports: - 8008:5000 api: environment: - "USE_DEVELOPMENT_TOKEN=true" ports: - 8005:8080 db: volumes: - ./config/postgres/staging.conf:/usr/share/postgresql/postgresql.conf.sample
したがって、Dockerイメージはすべての環境でまったく同じであり、Composeファイルを使用して、環境変数または構成ファイルを使用して環境固有の設定を設定します。
ほとんどの場合、さまざまな(マイクロ)サービスの構成パラメーターの値を1つのComposeファイルに簡単に含めてGitに保存できるため、環境変数を使用することをお勧めします。 上記の例に示すように、場合によっては構成ファイルの方が良いと思う場合は、Dockerボリュームを使用して接続できます。 ただし、構成ファイルに記載されているすべての構成ファイルもGitに保存する必要があることを忘れないでください。
秘密を守る方法
構成ファイルのパラメーターは、プライベートリポジトリであってもGitに保存するには敏感すぎることがあります。 たとえば、AWSのキー、プロダクションAPIトークンなどになります。 最近 、Diogo Monica は 、このデータも環境変数に保存すべきではないと述べました。
buildoでは、ほとんどの場合git-cryptを使用して機密情報を暗号化するため、この情報はGitに保存できますが、ホワイトリストのPGPキーなしではアクセスできません。
VaultやDockerシークレットなどのより洗練されたソリューションには、特定の利点があります。 ただし、これらのツールはまだ開発中であり、おそらく今後の記事でそれらについて書こうとしています...
おわりに
構成ダイナミクスの3つの法則の結果を覚えておいてください。
- 構成パラメーターを環境変数に移動しても、問題は解決しません。
- オプション設定を定期的に検索する必要があります。
- アプリケーションが構成ファイルなしで実行されるようにすることが重要です。
これらの法則の知識は、構成エントロピーを削減し、最終的に大幅な時間を節約できます。
次のステートメントは、構成力学のゼロ法則と呼ばれることもあります。
構成AがGitに保存され、2人の開発者BとCによってダウンロードされた場合、BとCは構成が平衡状態になります。
http://hyperphysics.phy-astr.gsu.edu/hbase/thermo/thereq.html#c2
参照:
- オリジナル: 設定ダイナミクスの3つの法則 。