Web アプリケーションを開発中および運用中に効果的に管理できるようにするには、環境変数を理解する必要があります。 ほんの数年前までは、環境変数を使って Rails アプリケーションを構成している人はほとんどいませんでした。 しかし、Heroku が登場しました。
Heroku は開発者に 12 ファクター アプリのアプローチを紹介しました。 12 ファクター アプリのマニフェストでは、デプロイが簡単なアプリを作成するためのベスト プラクティスを数多く提示しています。
12-factor アプリは、環境変数 (しばしば env vars または env と短縮されます) に設定を保存します。 環境変数は、コードを変更することなくデプロイ間で簡単に変更できます。設定ファイルと異なり、誤ってコード リポジトリにチェックインされる可能性はほとんどありません。 しかし、しばしばそれは貨物的な方法で行われています。
この投稿では、環境変数が実際にどのように動作するか、そしておそらくより重要なこととして、どのように動作しないかを説明します。 また、Rails アプリケーションで環境変数を管理する最も一般的な方法のいくつかを探ります。
注意: 環境変数の保護については、こちらをご覧ください。
すべてのプロセスは独自の環境変数のセットを持つ
サーバー上で実行するすべてのプログラムには、少なくとも1つのプロセスが存在します。 そのプロセスは、独自の環境変数のセットを取得します。
初心者が犯しがちな間違いは、環境変数が何らかの形でサーバー全体に適用されると考えることです。 Heroku のようなサービスは、環境変数の設定がディスク上の設定ファイルの編集と同等であるかのように思わせるのは確かです。
サーバー上で実行するすべてのプログラムは、それを起動した時点で独自の環境変数のセットを取得します。
すべてのプロセスは独自の環境を持っています。
環境変数はプロセスとともに消滅する
環境変数を設定し、再起動したらなくなっていた、という経験はありませんか? 環境変数はプロセスに属しているので、プロセスが終了するたびに、環境変数も消えてしまいます。
これは、ある IRB セッションで環境変数を設定し、それを閉じて、2 番目の IRB セッションでその変数にアクセスしようとすることで確認することができます。
When a process shuts down, its environment variables are lost
This is the same principal that causes you to lose environment variables when your server reboots or you exit your shell. 環境変数をセッション間で持続させたい場合は、
.bashrc
.プロセスは親から環境変数を取得する
すべてのプロセスには親が存在します。
もし vim を起動するために bash シェルを使用するなら、vim の親はシェルです。
Child processes inherit env vars from their parent
以下の例では、IRB プロセスで $MARCO 環境変数の値を設定しています。 IRB は私が作成したシェルの親プロセスであるため、IRB は $MARCO 環境変数のコピーを取得します。
Ruby で設定した環境変数は子プロセスに継承される
親は子に送る環境変数をカスタマイズできる
デフォルトでは、子は親の持つ環境変数のコピーをすべて取得します。 しかし、親はこれをコントロールできます。
コマンドラインから env プログラムを使用することができます。 そして bash では、親に設定せずに子に環境変数を設定する特別な構文があります。
Use the env command to set child without set them on the parent
もし Ruby 内部からシェルアウトする場合、ENV ハッシュを汚染せずに子プロセスにカスタム環境変数を提供することも可能です。
How to pass custom environment variables into Ruby’s system method
Children cannot set their parents’ environment variables
子は親の環境変数のコピーを取得するだけなので、子による変更は親に影響しない。
環境変数は「参照」ではなく「値で渡される」
ここで、バックティック構文を使用して、環境変数を設定しようとシェルアウトしています。
Child processes cannot change their parents env vars
Changes to the environment does not sync between running processes
以下の例では、IRB のコピーを 2 つ並べて実行させています。
1 つのプロセスに環境変数を追加しても、他のプロセスでは変更されない
シェルは環境変数システムの UI にすぎない
システム自体は OS カーネルに含まれている。 つまり、シェルは環境変数に対して魔法のような力を持っていないのです。
環境変数はシェル変数と同じではない
最大の誤解のひとつは、シェルが独自の「ローカル」シェル変数システムを提供しているために起こるものです。 ローカル変数を使用するための構文は、多くの場合、環境変数と同じです。
しかし、ローカル変数は子にコピーされません。
環境変数はシェル変数と同じではない
例を見てみましょう。 まず、MARCOという名前のローカルシェル変数を設定しました。 これはローカル変数なので、どの子プロセスにもコピーされません。
次に、export コマンドを使って、ローカル変数を環境変数に変換します。 これで、このシェルが新しく作成するすべてのプロセスにコピーされるようになりました。
ローカル変数は子プロセスでは使用できません。 Export はローカル変数を環境変数に変換します。
環境変数の管理の実際
実際のところ、これはどのように機能するのでしょうか。
1 台のコンピューターで 2 つの Rails アプリケーションを実行しているとします。 これらのアプリの例外を監視するために Honeybadger を使用しています。 しかし、問題が発生しました。
あなたは、Honeybadger API キーを $HONEYBADGER_API_KEY 環境変数に格納したいと考えています。 しかし、2 つのアプリケーションには 2 つの別々の API キーがあります。
どうして 1 つの環境変数に 2 つの異なる値を設定できるのでしょうか? 環境変数はプロセス単位であり、私の 2 つの Rails アプリは異なるプロセスで実行されているので、$HONEYBADGER_API_KEY にそれぞれ独自の値を持つことができない理由はありません。
Figaro
Rails アプリに Figaro gem をインストールすると、起動時に config/application.yml に入力した値が ruby ENV ハッシュに読み込まれます。
gemをインストールするだけです:
# Gemfilegem "figaro"
そして application.yml に項目を追加します。 このファイルを .gitignore に追加することが非常に重要で、誤って secret をコミットしてしまうことがないようにします。
この gem をインストールするだけです:
# Gemfilegem 'dotenv-rails'
そして、設定値を .NET Framework に追加してください。env – そして、誤って github に公開しないように、ファイルを git 無視することを確認します。
HONEYBADGER_API_KEY=12345
Ruby ENV ハッシュの値にアクセスできます。
ENV
シェルで、あらかじめ定義した env 変数のセットを使って次のようにコマンドを実行することもできます。 Secrets.yml は – クールですが – 環境変数を設定するものではありません。 そのため、Figaro や dotenv などの gems の代わりにはなりません。
Plain old Linux
Linux の基本コマンドを使用して、アプリケーションごとに固有の環境変数のセットを維持することも可能です。 1 つのアプローチとして、サーバー上で実行されている各アプリを異なるユーザーによって所有させることができます。 そして、そのユーザーの .bashrc を使用して、アプリケーション固有の値を保存することができます。