systemdを介して起動されたphp-fpm 5.6サービスに、グローバル環境変数の読み取りを強制します

これは、実行している環境に応じて、PHPサービス構成を実装するための短い方法です。 誰かがよりエレガントな解決策を求めたり、ささいなことを修正したりしてくれたら嬉しいです。



主なアイデア



環境変数構成された同じエコシステム内でサービス、マイクロサービス、および依存アプリケーションを実行します



問題


この記事では、「環境変数」を何度も繰り返しています。

デフォルトでは、php-fpmはグローバル環境変数( getenv関数 )を無視しますが、php cliはそれらを受け取ります。



背景


すでに.envを使用している場合は、このセクションをスキップできます


現在、ZF2で書かれたプロジェクトに取り組んでいます。 プロジェクトを構成するために、さまざまな環境で構成ファイルが使用されました 。 これにより、この種のプロジェクトリポジトリに多数の重複した構成が生成されます。



これらの複製は、互いに常に同期する必要があります。 また、特定のphpロジックを内部に保存しているため、コードが重複します。



.envファイルから環境を読み取り、それを$ _ENV(簡略化)にロードできるライブラリをプロジェクトに追加しました。



vlucas / phpdotenvライブラリをZF2に接続する
composer require vlucas/phpdotenv







公開/index.phpを開く

「init_autoloader.php」が必要な後、以下を追加します。

 $dotenv = new Dotenv\Dotenv(__DIR__ . '/../'); // $dotenv->required('SOME_IMPORTANT'); //      $dotenv->load(); //   overload(),   .env   ,     ( )
      
      







さらに(これは完全にオプションです)、larravelのヘルパー関数env()を追加しました。これは、php getenv()のラッパーです。



ZF2にenvメソッド($キー、$デフォルト= null)を追加します
内容を含むファイル、例えばlibrary / Common / Config / env.phpを作成します。

 if ( ! function_exists('value')) { /** * Return the default value of the given value. * * @param mixed $value * @return mixed */ function value($value) { return $value instanceof Closure ? $value() : $value; } } if ( ! function_exists('env')) { /** * Gets the value of an environment variable. Supports boolean, empty and null. * * @param string $key * @param mixed $default * @return mixed */ function env($key, $default = null) { $value = getenv($key); if ($value === false) return value($default); switch (strtolower($value)) { case 'true': case '(true)': return true; case 'false': case '(false)': return false; case 'empty': case '(empty)': return ''; case 'null': case '(null)': return; } return $value; } }
      
      







composer.jsonで 、「autoload」セクションに追加します。

 "autoload" : { ..., "files": ["library/Common/Config/env.php"] },
      
      





次に、 composer dumpautoloadを実行します。



このステップにより、不要な重複した設定ファイルをすべてリポジトリから破棄できました(local.php、unittest.php、* .php.dist)。 代わりに、.env.globalがプロジェクトのルートに表示され、構成に関係する使用可能なすべての変数のリストが表示されます。



今の設定方法は?
環境はサービス変数を認識していませんが、サービスはそれが実行されている環境を考慮します。

1.以来 稼働中のマシンでは、環境変数に何もないかもしれません。異なるマシン間でプロジェクトを交換するのは不便です。phpdotenvライブラリは、アプリケーションを起動する前に.envファイルを読み取り、その変数を$ _ENV [$ name] = $ valueにプッシュします。

2.構成ファイルは、php関数getenv()のラッパーであるenv()メソッドを呼び出し、環境変数を読み取り、必要に応じてデフォルト値に置き換えます。

 //  : $config['emails']['from'] = env('APP_EMAIL', 'info@myemail.com'); $config['is_production'] = ( 'production' == env('APP_ENV') ); if (env('ZF_DEBUG_TOOLS', false)) { $config['modules'][] = 'ZendDeveloperTools'; }
      
      





3. .envファイルはオプションです 。 構成では、グローバル環境変数またはデフォルト値を使用できます。 .envファイルがない場合、例外がスローされ(ライブラリの機能は最も正確ではありません)、実稼働サーバーからまったく省略できます。 例外を回避するには、プロジェクトのルートにファイルを作成するだけです(.envに触れます)。

4. .envファイルには、使用可能なすべてのプロジェクト変数を保存する必要はありません。 デフォルト値が設定で設定されている場合、特定の環境で異なる変数のみを.envに書き込むだけで十分です。

5. .envファイルをリポジトリにコミットする必要はありませ 。 バージョン管理システムで無視するように追加する必要があります。

6.環境変数を必須にするには、次の構成をindex.phpに追加します。

 $dotenv->required('APP_ENV'); //  APP_ENV          .env   
      
      





7.プロジェクトリポジトリで、.env。*(.Env.phpunit、.env.develop)の形式のファイルをコミットできます。 これは、さまざまな環境に対応した一連の変数を備えたブックマークに似ています。 オーケストレーターまたはCIシステムは、同じシステム内の複数のコピーでプロジェクトがデプロイされているプロジェクトがデプロイされている場合、またはグローバル環境変数を処理する方法がない場合、テンプレート(またはテンプレートの変数)をコピーします。 ブックマークは互いに比較するのに便利です。 これらのブックマークは、サービスのロジックには一切関与しません。

重要:.env.productionはプロジェクトリポジトリに保存しないでください。

.env.default-プロジェクトで現在サポートされているすべての環境変数を含むファイル(.envの最大可能テンプレート)を作成すると便利です。




- それで、今ではすべての設定を.envで複製する必要がありますか? 新しい環境変数をいつ追加しますか?



このオプションが異なるホストで異なる場合は、環境に構成を設定する価値があります。

環境変数に何かを書くことに何の問題もありません。

 $config['csv_separator] = ' | '; //      ,    . $config['like_panel'] = true; //   ,    env('APP_LIKE_PANEL', false) $config['facebook_app_id'] = 88888888881; //    
      
      







- パスワードと機密データはどうですか?



生産データを別のリポジトリ、パスワードリポジトリ、またはたとえば安全なオーケストレータリポジトリに保存します





そのため、プロジェクトでは環境を考慮に入れていますが、...



開発は稼働中のマシンで実行されましたが、プロジェクトは.envファイルを読み取り、すべてが機能しました。 しかし、テスト環境をデプロイしたとき、正しいシステム環境変数を設定すると、php-fpmはそれらを無視することがわかりました。 GoogleとStackOverflowのさまざまなレシピが、2つのよく知られた方法を使用して、1つの自動化または別の自動化に要約されました。



1. fastcgi_paramパラメーターSOMEE​​NVテストでnginxを介して変数を渡す。

2. php- fpm ワークフロープール構成で env形式[SOME_VAR]の変数を設定します



最初のオプションと2番目のオプションは、いくつかの特別な状況に便利です。 しかし、「アプリケーションではなく環境を構成する」というパラダイムで考えると、そのような方法は、たとえば、プロジェクトフォルダーに.envファイルを単に置くよりもはるかに困難です。 しかし、オーケストレーター、CIシステム、または単にシステム管理者はプロジェクトの詳細を知らないはずです。これはエレガントではありません。



提案された解決策


ネットワークからのさまざまなレシピを組み合わせて、次の実用的なソリューションが見つかりました。

Centos 7、PHP 5.6.14でテスト済み。



 1.  /etc/php.ini -  variables_order = "GPCS"  variables_order = "EGPCS" #   PHP       # http://php.net/manual/ru/ini.core.php#ini.variables-order 2.  /etc/php-fpm.d/www.conf,    /etc/php-fpm.conf (       ,   www-   php-fpm. -  ( ,   ): clear_env = no #        3.      /etc/environment (  A=B) 4. ln -fs /etc/environment /etc/sysconfig/php-fpm #      php-fpm       5. systemctl daemon-reload && service php-fpm restart
      
      







理論上は、同じsimlinkアプローチが他のサービスにも適用されます。



提案されたソリューションの長所:

-/ etc /環境に保存されている変数は、さまざまなアプリケーションで使用できます。 echo $ MYSQL_HOSTをシェルで呼び出すか、getenv( 'MYSQL_HOST')をphpで呼び出すことができます。

-/ etc / environmentで明示的に設定されていない環境変数は、php-fpmに入りません。 これにより、オーケストレーターを使用して、サービスが実行されている分離システムの外部から環境を制御できます。



短所:

-残念ながら、nginxとの類推によるphp-fpmのリロード用の作業コマンドが見つからなかったため、/ etc / environmentを変更する場合は、 systemctl daemon-reload && service php-fpm restartを実行する必要があります



重要 :アプリケーションが隔離された環境(サーバー、仮想マシン、コンテナー)で動作しない場合、環境変数の定義は、グローバルスペースの名前が一致するため、システム内の隣接サービスに予測できない影響を与える可能性があります。




参照:

- 記事を読んでいない人のために

-SAAS Twelve Design Factor Methodology: 環境でのストア構成

-PHPプロジェクトの開発環境に.envファイル使用して環境変数ロードします



All Articles