CFアプリ開発と管理#1 クラウドでのアプリケーションの設計と実行に関する考慮事項


## クラウドのアプリケーション設計

アプリケーション設計が簡単なガイドラインに従い、サポートされたアプリケーション・フレームワークに従って書かれたアプリケーションは、Cloud Foundry上で変更しなくても実行できます。このガイドラインに従うことで、アプリケーションは「クラウド・フレンドリー」になり、Cloud Foundry や *IBM Bluemix* への導入が容易になります。

以下のガイドラインは、クラウドプラットフォーム用の最新アプリケーションを開発するためのベスト・プラクティスを示しています。 クラウドの優れたアプリ設計について詳しくは、[The Twelve-Factor App](https://www.12factor.net/ja/)を参照してください。

Cloud Foundryルータで処理されるHTTPルーティングの機能の詳細については、「[HTTPルーティング](http://docs.cloudfoundry.org/concepts/http-routing.html)」のトピックを参照してください。 アプリケーションコンテナのライフサイクルの詳細については、「[アプリケーションコンテナのライフサイクル](http://qiita.com/MahoTakara/items/905a61ccc56c8daef2de)」を参照してください。

*注意事項：この記事は、Cloud Foundry Documentaion [Considerations for Designing and Running an Application in the Cloud](http://docs.cloudfoundry.org/devguide/deploy-apps/prepare-to-deploy.html) (last updated: May 26, 2017)の独自の翻訳とコメントです。 内容を保証するものではありません。* 


## ローカルファイルシステムへの書き込みを避ける

Cloud Foundryで実行されているアプリケーションは、次の理由によりファイルをローカル・ファイルシステムに書き込むべきではありません。

* ローカル・ファイルシステムのストレージは短命です。アプリケーション・インスタンスがクラッシュまたは停止すると、そのインスタンスに割り当てられたリソースは、アプリケーションが起動してから変更されたローカルディスクを含めて、プラットフォームによって再利用されます。インスタンスが再起動されると、アプリケーションは新しいディスクイメージで起動します。アプリケーションは実行中にローカルファイルを書き込むことができますが、アプリケーションが再起動するとファイルは消えます。

* 同じアプリケーションのインスタンスは、ローカル・ファイルシステムを共有しません。各アプリケーション・インスタンスは、独立した独立したコンテナで実行されます。したがって、あるインスタンスによって書き込まれたファイルは、同じアプリケーションの他のインスタンスからは見えません。ファイルが一時的な場合は、これは問題ではありません。ただし、アプリケーションがファイルのデータをアプリケーションの再起動後も保持する必要がある場合や、アプリケーションの実行中のすべてのインスタンスでデータを共有する必要がある場合は、ローカル・ファイルシステムを使用しないでください。この目的のために、データベースやブロブストアなどの共有データサービスを使用することをお勧めします。

たとえば、ローカルファイルシステムを使用する代わりに、MongoDBドキュメントデータベースやMySQLやPostgresなどのリレーショナル・データベースなどのCloud Foundryサービスを使用できます。 別のオプションは、Amazon S3、Google Cloud Storage、Dropbox、Boxなどのクラウドストレージプロバイダを使用することです。 アプリケーションが異なるインスタンス間で通信する必要がある場合は、Redisのようなキャッシュ、またはRabbitMQを使用したメッセージングベースのアーキテクチャを検討してください。

たとえば、アプリケーションがネットワーク接続ファイルシステムを介して他のアプリケーションとやりとりするため、またはアプリケーションが書き換えができないレガシーコードに基づいているため、アプリケーションにファイルシステムを使用する必要がある場合は、[ボリュームサービス](http://docs.cloudfoundry.org/devguide/services/using-vol-services.html)を使用して、 ファイルシステムをアプリケーションに追加します。

*注意：Bluemixでは、PaaSとして、NFS等のファイルシステムのサービスは提供されていません。オブジェクト・ストレージをご利用ください。また、Bluemix Infrastructure の ファイルストレージ・サービスを利用できません。 アプリ・コンテナ間でファイルの共有が必要な場合は、[単一コンテナーとスケーラブル・コンテナーのボリュームへの永続データの保管](https://console.bluemix.net/docs/containers/container_volumes_ov.html#container_volumes_ui) を参照して、IBM Container サービス の Kubernetes へ移行が必要です。*



## アプリケーション間でアクセス可能なCookie

ドメインを共有する環境では、アプリケーション間でCookieにアクセスできる可能性があります。

GoogleアナリティクスやMixpanelなどの多くのトラッキング・ツールでは、使用可能な最上位レベルのドメインを使用してCookieを設定しています。 example.comなどの共有ドメインを使用するアプリケーションの場合、最上位レベルのドメインを使用するように設定されたCookieは、HTTP応答ヘッダーに.example.comのDomain属性を持ちます。 たとえば、my-app.shared-domain.example.comのアプリケーションは、your-app.shared-domain.example.comのアプリケーションのCookieにアクセスできます。

クッキーを使用するアプリケーションやツールで、利用可能な最上位レベルのドメインにクッキーを設定して保存するかどうかを検討してください。


## ポートに関する考慮事項

クライアントは、アプリケーションに関連付けられたURLへのリクエストすることによって、Cloud Foundryで実行されているアプリケーションに接続します。 Cloud Foundryでは、ポート80および443のアプリケーションへのHTTP要求を許可します。詳細については、「[ルートとドメイン](http://qiita.com/MahoTakara/items/c34b3a1b117683a6e326)」のトピックを参照してください。

Cloud Foundryは、 "Upgrade header"を含むHTTP経由のWebSocketハンドシェイク要求もサポートしています。 Cloud Foundryルータは、WebSocket接続を形成するためのアプリケーションへのTCP接続を「アップグレードして開始」します。

WebSocketをサポートするには、オペレータはロードバランサを正しく設定する必要があります。 構成によっては、クライアントはWebSocket接続（ポート4443など）や別のドメイン名で別のポートを使用する必要があります。 詳細については、「[WebSocketのサポート](http://docs.cloudfoundry.org/adminguide/supporting-websockets.html)」トピックを参照してください。


## Cloud Foundryのアップデートとアプリケーション

アプリケーション管理のために、Cloud Foundryはアプリケーションインスタンスを停止して再起動する必要があります。 これが発生した場合、Cloud Foundryは次の手順を実行します。

* Cloud Foundryは、開始コマンドが起動するルートプロセスにシングルの終了シグナルを送信します。

* Cloud Foundryは、アプリケーションがすべての子プロセスをシャットダウンし、開いている接続を処理できるように10秒間待機します。

* 10秒後、Cloud Foundryは強制的にアプリケーションをシャットダウンします。

アプリケーションは正常にシャットダウンするように、終了シグナルを受け入れて処理する必要があります。


*コメント: プログラム言語のシグナル・ハンドラによって、TERMシグナルを受信して、終了処理を記述する必要があります。参考までに、代表的なプログラム言語のシグナル処理のリンクを以下に挙げます。*

* PHP [pcntl_signal](http://php.net/manual/ja/function.pcntl-signal.php)
* Ruby [module Signal](https://docs.ruby-lang.org/ja/latest/class/Signal.html)
* Node.js [Signal Events](https://nodejs.org/api/process.html#process_signal_events)
* Java [Integrating Signal and Exception Handling](http://www.oracle.com/technetwork/java/javase/signals-139944.html#gbzbl)
* Python [18.8. signal — 非同期イベントにハンドラを設定する](https://docs.python.jp/3/library/signal.html)


## Push時に不要なファイルを除外する

デフォルトでは、アプリケーションをPUSHする際に、アプリケーションのプロジェクト・ディレクトリ・ツリー内、次のファイル拡張子を持つファイルを除き、すべてのファイルが、Cloud Foundryインスタンスにアップロードされます。

* .cfignore
* _darcs
* .DS_Store
* .git
* .gitignore
* .hg
* /manifest.yml
* .svn

アプリケーション・ディレクトリに他のファイル（一時ファイルやログファイルなど）が含まれている場合、またはアプリケーションをビルドして実行する必要のないサブディレクトリを完成させる場合は、.cfignoreファイルを使用して除外することをお勧めします。 （.cfignoreはgitの.gitignoreと似ていますので、gitトラッキングからファイルやディレクトリを除外することができます）。特に大規模なアプリケーションでは、不要なファイルをアップロードするとアプリケーションのデプロイメントが遅くなります。

アプリケーション・ディレクトリ構造のルートにある.cfignoreというテキストファイルに、アップロードから除外するファイルまたはファイルタイプを指定します。 たとえば、これらの行は "tmp"と "log"ディレクトリを除外します。

~~~file:.cfignore
tmp/
log/
~~~

除外するファイルタイプは、使用するアプリケーションフレームワークに応じて異なります。 https://github.com/github/gitignore にある一般的なフレームワーク用の.gitignoreテンプレートは便利な出発点です。



## 複数のインスタンスを実行して可用性を高める

Diegoセルがアップグレードされると、その上で実行されているアプリケーションは正常にシャットダウンされ、別のDiegoセルで再起動されます。 Cloud Foundryのアップグレードプロセス中にアプリケーションが使用できなくなるリスクを回避するには、アプリケーションの複数のインスタンスを実行する必要があります。

*Diegoセルは、[Diego Architecture](https://docs.cloudfoundry.org/concepts/diego/diego-architecture.html)の図中に、記載があります。PaaS内部には複数のDiegoセルが稼働しており、アプリケーションのインスタンスを複数実行する事で、異なるDeigoセルで実行されることが期待されます。*



## ビルドパックの使用

ビルドパックは、アプリケーションのフレームワークとランタイムサポートを提供する検出スクリプトと構成スクリプトの束で構成されています。 ビルドパックが必要なアプリケーションをデプロイすると、Cloud Foundryはアプリケーションが実行されているDiegoセルにビルドパックをインストールします。

詳細については、[ビルドパック](http://docs.cloudfoundry.org/buildpacks/)のトピックを参照してください。