Cloud Foundry コマンドライン・インターフェイス(cf CLI)のcf pushコマンドを使用してアプリケーションをデプロイします。 cf pushはデフォルトのインスタンス数、ディスク制限、メモリ制限などでアプリケーションをデプロイします。フラグと値を指定してcf pushを呼び出すか、マニフェストファイルにキーと値のペアを指定してデフォルト値を上書きできます。
マニフェストは一貫性と再現性を提供し、特に複数のアプリケーションを一度に自動化するのに役立ちます。
注意事項: この記事は、Cloud Foundry Documentaion Deploying with Application Manifests (last updated: July 25, 2017)からの独自の翻訳とコメントです。内容を保証するものではありません。
cf push がマニフェストを探す方法
デフォルトでは、cf pushコマンドは、現在の作業ディレクトリ内のmanifest.ymlファイルを使用してアプリケーションをデプロイします。
$ cf push
(ワーキング・ディレクトリのmanifest.ymlを使用します)
マニフェストが他の場所にある場合は、-fオプションを使用してファイル名へのパスを指定します。
$ cf push -f ./some_directory/some_other_directory/alternate_manifest.yml
(-f で指定されたパスのマニフェスト・ファイルが使用されます。)
ファイル名のないパスを指定する場合、ファイル名はmanifest.ymlでなければなりません。
$ cf push -f ./some_directory/some_other_directory/
( -f が指定するパスに存在するmanifest.ymlの使用)
マニフェストの例
マニフェストを使用することなくアプリケーションをデプロイできます。 提供されるメリットには、一貫性と再現性が含まれます。 異なるクラウド間でアプリケーションを移植できるようにするには、マニフェストが特に役立つことがあります。
マニフェストはYAMLで書かれています。 以下のようないくつかのYAML規則を以下のマニフェストに示します。
- マニフェストは3つのダッシュで始まることがあります。
- アプリケーション・ブロックは見出しとそれに続くコロンで始まります。
- アプリケーション名の前にダッシュとスペースが1つあります。
- ブロック内の後続の行は、nameと整列するために2つのスペースでインデントされます。
---
applications:
- name: my-app
memory: 512M
host: my-host
最小限のマニフェストでは、アプリケーション名のみが必要です。 有効な最小限のマニフェストを作成するには、memoryとhostのプロパティをこの例から削除します。
cf push にアプリケーション名を指定する
cf pushにはアプリケーション名が必要です。アプリケーション名は、マニフェストまたはコマンドラインで指定します。
前述の「マニフェストを探す方法」で説明したように、cf pushコマンドは、デフォルトでは現在の作業ディレクトリ内のmanifest.yml、または-fオプションで指定されたパスにmanifest.ymlを配置します。
マニフェストを使用しない場合、最小限のpushコマンドは次のようになります。
$ cf push my-app
注意:コマンドラインでアプリケーション名を指定すると、cf pushはマニフェストに異なるアプリケーション名があるかどうかにかかわらず、そのアプリケーション名を使用します。 マニフェストに複数のアプリケーションが記述されている場合は、コマンドラインでその名前を指定して単一のアプリケーションをプッシュできます。 cf CLIは他をプッシュしません。 これらの動作をテストに使用します。
cf push がアプリケーションを探す方法
デフォルトでは、cf pushは現在の作業ディレクトリの内容を再帰的にプッシュします。 または、マニフェストまたはコマンドラインオプションを使用してパスを指定することもできます。
-
パスがディレクトリの場合、cf pushは現在の作業ディレクトリではなくそのディレクトリの内容を再帰的にプッシュします。
-
パスがファイルに対するものである場合、cf pushはそのファイルだけをプッシュします。
注意:複数のファイルをプッシュしたいが、ディレクトリの内容全体をプッシュしたくない場合は、.cfignoreファイルを使用してcf pushに何を除外するかを指示することを検討してください。
マニフェスト、コマンドライン・オプション、および最新の値の間の優先順位
初めてアプリケーションをプッシュする場合、Cloud Foundryは、マニフェストまたはcf pushコマンドラインオプションで設定しない属性にデフォルト値を適用します。
- 例として、cf push my-appをマニフェストなしで実行すると、1ギガバイトのメモリでアプリケーションの1つのインスタンスをデプロイできます。この場合、インスタンスおよびメモリのデフォルト値は、それぞれ「1」および「1G」です。
1つのプッシュと別のプッシュの間で、属性値は他の方法で変化する可能性があります。
- 例として、cf scaleコマンドはインスタンスの数を変更します。
サーバー上の属性値は、その時点までに適用されたすべての設定の累積結果を表します。デフォルト、マニフェスト内の属性、cf pushコマンドライン・オプション、cf scaleなどのコマンドです。この結果のサーバーの値のセットには特別な名前はありません。あなたはそれらを最新の値と考えることができます。
cf pushは、属性値を設定するときの優先順位の規則に従います。
- マニフェストは、デフォルトを含む最新の値をオーバーライドします。
- コマンドラインオプションはマニフェストをオーバーライドします。
一般に、マニフェストはcf pushの別の入力として、コマンドラインオプションと最新の値と組み合わせると考えることができます。
オプションの属性
このセクションでは、マニフェストにオプションのアプリケーション属性を記述する方法について説明します。 これらの属性のそれぞれは、コマンドラインオプションで指定することもできます。 コマンドラインオプションはマニフェストをオーバーライドします。
buildpack
アプリケーションでカスタムビルドパックが必要な場合は、buildpack属性を使用して3つの方法のいずれかで指定できます。
- By name: MY-BUILDPACK.
- By GitHub URL: https://github.com/cloudfoundry/java-buildpack.git.
- By GitHub URL with a branch or tag: https://github.com/cloudfoundry/java-buildpack.git#v3.3.0 for the v3.3.0 tag.
---
...
buildpack: buildpack_URL
注:cf buildpacks コマンドは、マニフェストまたはコマンドラインオプションで名前で参照できるビルドパックをリストします。
この属性を上書きするコマンドラインオプションは -b です。
command
一部の言語およびフレームワークでは、アプリケーションを起動するためのカスタムコマンドを提供する必要があります。 カスタム起動コマンドを提供する必要があるかどうかを判断するには、buildpackのマニュアルを参照してください。
アプリケーションマニフェストまたはコマンドラインでカスタムの開始コマンドを提供することができます。 Cloud Foundryがデフォルトの開始コマンドをどのように決定するかの詳細については、「アプリケーションの起動、再起動、再ステージ」を参照してください。
アプリケーションマニフェストでカスタム開始コマンドを指定するには、次の例のようにSTART-COMMAND形式のコマンドで追加します。
---
...
command: bundle exec rake VERBOSE=true
指定した開始コマンドは、アプリケーションのデフォルトになります。 ビルドパックで設定された元のデフォルトの開始コマンドを使用するに戻るには、次のように属性を明示的にnullに設定する必要があります。
---
...
command: null
次の例に示すように、コマンドラインで-cオプションを使用してカスタム開始コマンドを指定します。
$ cf push my-app -c "bundle exec rake VERBOSE=true"
注:値が 'null'の-cオプションは、cf pushにbuildpack startコマンドを使用させます。 詳細については、Buildpack Startコマンドを使用するようにcf pushを強制するを参照してください。
Buildpackアプリケーションのstartコマンドを無効にすると、Linuxはbash -c YOUR-COMMANDを使用してアプリケーションを起動します。 Dockerアプリケーションのstartコマンドを無効にすると、Linuxはsh -c YOUR-COMMANDを使用してアプリケーションを起動します。 このため、開始コマンドを無効にする場合は、カスタム合成開始コマンドにexecの接頭辞を付ける必要があります。
アプリは終了シグナルを捕らえ、それを適切に終了処理をする必要があります。 シェルがプロセスツリーを管理するために、カスタムの複合シェルコマンド、特に&、&&、||などを使って子プロセスを作成するコマンドを使用すると、後続のアプリケーションがトップレベルのbashに送信されるシグナルを受信できなくなる可能性があります。
この問題を解決するには、execを使用してbashプロセスを独自のプロセスに置き換えることができます。
例えば:
bin/rake cf:on_first_instance db:migrate && bin/rails server -p $PORT -e $RAILS_ENV
プロセス・ツリーは、bash -> ruby です。 したがって、TERMシグナルを受信すると、bash はグレースフルにシャットダウンしますが、ruby プロセスは、そうなりません。
bin/rake cf:on_first_instance db:migrate && exec bin/rails server -p $PORT -e $RAILS_ENV
最終的なコマンドにexecプレフィックスが含まれているため、railsによって呼び出されたrubyプロセスは、複合コマンドの実行を管理するbashプロセスを引き継ぎます。 プロセスツリーはrubyだけなので、ruby WebサーバはTERMシグナルを受け取り、10秒のうちに正常にシャットダウンすることができます。
より複雑な状況では、カスタムビルドパックの作成のように、プロセスツリーを管理し、アプリケーションを正常にシャットダウンするために、bash trap、wait、およびbackgroundedプロセスを使用することができます。 しかし、ほとんどの状況では、適切に配置されたexecで十分です。
disk_quota
disk_quota属性を使用して、アプリケーションインスタンスのディスク領域を割り当てます。 この属性には、大文字または小文字のM、MB、G、GBの測定単位が必要です。
---
...
disk_quota: 1024M
この属性を無効にするコマンドラインオプションは-kです。
domain
すべてのcf pushは、特定のCloud Foundryインスタンスにアプリケーションをデプロイします。 すべてのCloud Foundryインスタンスには、管理者が設定した共有ドメインがある場合があります。 ドメインを指定しない限り、Cloud Foundryはその共有ドメインをアプリケーションへのルートに組み込みます。
デフォルトの共有ドメイン以外のドメインからアプリケーションを提供する場合は、domain属性を使用できます。
---
...
domain: unique-example.com
この属性を上書きするコマンドラインオプションは-dです。
domains
複数のドメインを提供するには、domains属性を使用します。 ドメイン属性とドメイン属性の両方を定義すると、Cloud Foundryはこれらの両方のフィールドに定義されたドメインのルートを作成します。
---
...
domains:
- domain-example1.com
- domain-example2.org
この属性を上書きするコマンドラインオプションは-dです。
health-check-http-endpoint
health-check-http-endpoint属性を使用して、httpヘルスチェックタイプのエンドポイントをカスタマイズします。 health-check-http-endpoint属性を指定しないと、エンドポイント '/'が使用されます。
---
...
health-check-type: http
health-check-http-endpoint: /health
health-check-type
health-check-type属性を使用して、health_check_typeフラグ をport、processまたはhttpのいずれかに設定します。 ヘルスチェックタイプの属性を指定しないと、デフォルトでportになります。
---
...
health-check-type: port
この属性を上書きするコマンドラインオプションは-uです。
noneの値は、プロセスのために推奨されなくなりました。
host
host属性を使用して、文字列の形式でホスト名またはサブドメインを指定します。 ルートのこのセグメントは、ルートが一意であることを確認するのに役立ちます。 ホスト名を指定しないと、アプリケーションのURLはAPP-NAME.DOMAINの形式になります。
---
...
host: my-app
この属性を無効にするコマンドラインオプションは-nです。
注:ワイルドカードのホスト名を指定するには、アスタリスクの前後に引用符を置きます。
例:host: '*'
hosts
複数のホスト名またはサブドメインを指定するには、hosts属性を使用します。 各ホスト名は、アプリのための一意のルートを生成します。 ホストはホストと組み合わせて使用できます。 両方の属性を定義すると、Cloud Foundryはホストとホストの両方で定義されたホスト名のルートを作成します。
---
...
hosts:
- app-host1
- app-host2
この属性を無効にするコマンドラインオプションは-nです。
instances
インスタンス属性を使用して、プッシュ時に開始するアプリケーションインスタンスの数を指定します。
---
...
instances: 2
フォールトトレランスが重要なアプリケーションのインスタンスを2つ以上実行することをおすすめします。
この属性を上書きするコマンドラインオプションは-iです。
memory
メモリ属性を使用して、アプリケーションのすべてのインスタンスのメモリ制限を指定します。 この属性には、大文字または小文字のM、MB、G、GBの測定単位が必要です。 例えば:
---
...
memory: 1024M
デフォルトのメモリ制限は1Gです。 アプリインスタンスが1Gのメモリを必要としていないことがわかっている場合は、クォータスペースを節約するために、より小さな制限を指定することをお勧めします。
この属性を上書きするコマンドラインオプションは-mです。
no-hostname
デフォルトでは、ホスト名を指定しないと、アプリケーションのURLはAPP-NAME.DOMAINという形式になります。 これを上書きしてルートドメインをこのアプリケーションにマッピングする場合は、no-hostnameをtrueに設定できます。
---
...
no-hostname: true
この属性を無効にするコマンドラインオプションは--no-hostnameです。
no-route
デフォルトでは、cf pushはすべてのアプリケーションにルートを割り当てます。 しかし、一部のアプリではバックグラウンドで実行中のデータを処理するため、経路を割り当てるべきではありません。
no-route属性をtrueに設定すると、アプリのルートが作成されないようにすることができます。
---
...
no-route: true
この属性を無効にするコマンドラインオプションは--no-routeです。
Diegoアーキテクチャでは、ルートを作成せずにアプリケーションのルートをバインドするのではなく、実行するヘルスチェックのタイプを指定しません。 あなたのアプリケーションがワーカーまたはスケジューラーアプリであるためにポートでリッスンしない場合、ポートベースのヘルスチェックを満たしておらず、Cloud Foundry はクラッシュとしてマークします。 これを防ぐには、cf set-health-check APP_NAMEプロセスでポートベース・ヘルスチェックを無効にします。
既存のアプリからルートを削除するには、次の手順を実行します。
- cf unmap-routeコマンドを使用してルートを削除します。
- マニフェストのno-route:true属性 または --no-route コマンドラインオプションを使用して、アプリケーションを再度プッシュします。
詳細については、下記の1つのマニフェストによる複数のアプリケーションの記述を参照してください。
path
path属性を使用して、Cloud Foundryにアプリケーションのパスを伝えることができます。
パスとして指定されたディレクトリは、属性として、またはコマンドライン上のパラメータとして、buildpack detect スクリプトが実行される場所になります。
この属性を無効にするコマンドラインオプションは-pです。
---
...
path: /path/to/application/bits
詳細については、「cf push がアプリケーションを探す方法」を参照してください。
random-route
ルート関連のCLIオプションまたはアプリケーションマニフェストフラグを指定せずにアプリをプッシュすると、cf CLIはアプリケーション名に基づいてルートを生成しようとします。これにより、衝突が発生する可能性があります。
random-route属性を使用すると、一意のルートを生成し、名前の衝突を回避できます。
random-routeを使用すると、cf CLIはランダムなホスト(ホストが設定されていない場合)または未使用のポート番号を持つTCPルートでHTTPルートを生成します。
次の使用例の例を参照してください。
- 同じアプリケーションをテスト目的で複数のスペースに配置します。 このような状況では、ランダムなルートを使用して、アプリケーションのマニフェストでroute属性で宣言されたルートをランダム化することができます。
- 複数のユーザーが同じアプリを同じスペースに配置する、クラスルームトレーニングの練習には、アプリケーションマニフェストを使用します。
この属性を上書きするコマンドラインオプションは--random-routeです。
---
...
random-route: true
routes
複数のHTTPおよびTCPルートを提供するには、routes属性を使用します。 このアプリの各ルートは、まだ存在しない場合に作成されます。
この属性は、--hostname、-d、および--route-pathを含むプッシュオプションの組み合わせです。
---
...
routes:
- route: example.com
- route: www.example.com/foo
- route: tcp-example.com:1234
Manifest Attributes
routes属性は、ホスト、ホスト、ドメイン、ドメイン、およびホスト名なしの属性と組み合わせて使用することはできません。 エラーが発生します。
Push Flag Options
この属性には、さまざまなコマンドラインオプションとの一意の相互作用があります。
Push Flag Option | Resulting Behaviour |
---|---|
--no-route | 宣言されたルートはすべて無視されます。 |
-d | 宣言されたすべてのHTTPルートとTCPルートのDOMAIN部分をオーバーライドします。 |
--hostname, -n | すべてのHTTPルートでHOSTNAMEを設定またはオーバーライドします。 TCPルートには影響しません。 |
--route-path | すべてのHTTPルートのPATHを設定または上書きします。 TCPルートには影響しません。 |
--random-route | すべてのHTTPルートのHOSTNAMEを設定、または、上書きします。全てのTCPルートのポートを設定、または、上書きします。ポート番号とホスト名をランダムに生成します。 |
stack
アプリケーションをデプロイするスタックを指定するには、stack属性を使用します。 使用可能なスタックのリストを表示するには、cf cliからcf stacksを実行します。
---
...
stack: cflinuxfs2
この属性を無効にするコマンドラインオプションは-sです。
timeout
timeout属性は、Cloud Foundryがアプリケーションを起動するために割り当てる秒数を定義します。
例えば:
---
...
timeout: 80
非常に大きなアプリの起動に時間がかかる場合は、タイムアウトの長さを長くすることができます。 デフォルトのタイムアウトは60秒で、上限は180秒です。
注意:管理者は、maximum_health_check_timeoutプロパティの上限を任意の値に設定できます。 デプロイメントマニフェストのCloud Controllerプロパティを変更するには、bosh deployを実行する必要があります。
IBM Bluemixでは管理者としてCloud Foundry環境を設定はできません
タイムアウト属性を無効にするコマンドラインオプションは-tです。
Environment Variables
envブロックは、見出し、1つ以上の環境変数と値のペアで構成されます。
例えば:
---
...
env:
RAILS_ENV: production
RACK_ENV: production
cf pushは、アプリケーションをサーバー上のコンテナにデプロイします。 変数はコンテナ環境に属します。
アプリケーションが実行されている間は、環境変数を変更できます。
- すべての変数を表示する:cf env my-app
- 個々の変数を設定する:cf set-env my-app my-variable_name my-variable_value
- 個々の変数の設定を解除する:cf unset-env my-app my-variable_name my-variable_value
環境変数は、次の方法でマニフェストと連携します。
- アプリケーションを初めて展開すると、Cloud Foundryはマニフェストの環境ブロックに記述されている変数を読み取り、アプリケーションがステージングされているコンテナの環境と、アプリケーションがデプロイされているコンテナの環境に追加します。
- アプリケーションを停止してから再起動すると、その環境変数が保持されます。
Services
アプリケーションは、データベース、メッセージング、キーバリューストアなどのサービスにバインドできます。
アプリケーションはApp Spacesに配備されます。 アプリケーションは、アプリケーションがデプロイされる前に、ターゲットApp Spaceに存在するサービスインスタンスにのみバインドできます。
サービスブロックは、見出し、次に1つ以上のサービスインスタンス名で構成されます。
サービスを作成する人は誰でもサービスインスタンス名を選択できます。これらの名前は、backend_queueのように、mysql_5.xのように論理的な情報を伝えることができます。以下の例のように:
---
...
services:
- instance_ABC
- instance_XYZ
サービス・インスタンスを指定したバインドは、環境変数VCAP_SERVICESを設定することの特殊なケースです。「サービス資格情報をアプリケーションに配信する」の「サービスのバインド」セクションを参照してください。
1つのマニフェストで複数アプリの記述
1つのcf pushコマンドで複数のアプリケーションを展開するには、それらを単一のマニフェストに記述します。その際、マニフェスト内のディレクトリ構造とパス行に特別な注意を払う必要があります。
spark と flame と呼ばれる2つのアプリケーションを配備し、Cloud Foundryがflameの前にsparkを作成し始めるようにしたいとします。マニフェストで最初にsparkをリストすることでこれを実現します。
このような状況では、プッシュしたい2セットがあります。 sparkディレクトリにspark.rb、flameディレクトリにflame.rbがあるとしましょう。 1つ上のレベルでは、fireplaceディレクトリには、manifest.ymlファイルと一緒に、spark と flame のディレクトリが含まれています。 fireplaceディレクトリからcf CLIを実行し、マニフェストを見つけることができます。
ディレクトリ構造とマニフェストの場所を変更したので、cf pushは現在の作業ディレクトリを調べるデフォルトの動作によってアプリケーションを見つけることができなくなりました。 cf pushしたいアプリケーションを見つけられるようにするにはどうすればいいですか?
答えは、各アプリケーション記述にパス・ラインを追加してcf pushを正しいアプリケーションに導くことです。 cf pushがfireplaceディレクトリから実行されているとします。
For spark:
---
...
path: ./spark/
For flame:
---
...
path: ./flame/
マニフェストは、2つのアプリケーションのブロックを含んでいます。
---
# this manifest deploys two applications
# apps are in flame and spark directories
# flame and spark are in fireplace
# cf push should be run from fireplace
applications:
- name: spark
memory: 1G
instances: 2
host: flint-99
domain: shared-domain.example.com
path: ./spark/
services:
- mysql-flint-99
- name: flame
memory: 1G
instances: 2
host: burnin-77
domain: shared-domain.example.com
path: ./flame/
services:
- redis-burnin-77
複数アプリケーション・マニフェストを使用する場合は、次の一般的な規則に従ってください。
- マニフェストにアプリケーションの名前を付けて完全に記述します。
- バックグラウンドサービスを別のアプリケーションに提供するアプリケーションの説明には、ルートなしの行を使用してください。
- cf pushでアプリケーション名を指定しないでください。
- cf pushでコマンドラインオプションを使用しないでください。
二つの例外があります。
-
マニフェストの名前がmanifest.ymlでないか、現在の作業ディレクトリにない場合は、-fコマンドラインオプションを使用します。
-
マニフェストに記述されているすべてのアプリケーションではなく、単一のアプリケーションをプッシュする場合は、cf push my-appを実行して、目的のアプリケーション名を指定します。
重複の最小化
複数のアプリケーションが設定やサービスを共有するマニフェストでは、重複した行があります。マニフェストは引き続き機能しますが、重複すると、誤植のリスクが高まり、展開が失敗する可能性があります。
この問題の解決策は、重複した行を「プロモート」することです。つまり、アプリケーションブロックの上に移動して、一行にまとめます。 プロモートされた行は、マニフェストに記述されているすべてのアプリケーションに適用されます。 2つの競合が発生した場合、アプリケーションブロックの行はアプリケーション・ブロックの上にあるコンテンツよりも優先されます。
マニフェストは短くなり、読みやすくなり、メンテナンスが容易になります。
このように宣言されているマニフェストの行数に注目してください。
---
...
# all applications use these settings and services
domain: shared-domain.example.com
memory: 1G
instances: 1
services:
- clockwork-mysql
applications:
- name: springtock
host: tock09876
path: ./spring-music/build/libs/spring-music.war
- name: springtick
host: tick09875
path: ./spring-music/build/libs/spring-music.war
継承を持つ複数のマニフェスト
1つのマニフェストで複数のアプリケーションを記述できます。別の強力な手法は、継承を持つ複数のマニフェストを作成することです。ここでは、マニフェストには親子関係があり、子は親からの説明を継承します。子供は、継承された説明をそのまま使用したり、拡張したり、上書きすることができます。
子マニフェストの行は、親マニフェストの行をオーバーライドします。
この手法は、これらのシナリオやその他のシナリオで役立ちます。
-
アプリケーションには、デバッグ、ローカル、パブリックなど、さまざまなデプロイメントモードのセットがあります。各展開モードは、親親マニフェストの設定を拡張する子マニフェストに記述されています。
-
アプリケーションは、親マニフェストによって記述された基本構成でパッケージ化されています。ユーザーは、新しいプロパティを追加する子マニフェストを作成するか、親マニフェストの子マニフェストをオーバーライドすることによって基本構成を拡張できます。
継承を伴う複数のマニフェストの利点は、単一のマニフェスト内の複製された行を最小化するメリットと同様です。しかし、継承では、行を親マニフェストに配置することで行を「プロモート」します。
すべての子マニフェストには、親マニフェストを指す "継承"行が含まれていなければなりません。子のマニフェストの上部に3つのダッシュの直後に継承ラインを配置します。たとえば、base-manifest.ymlという名前の親マニフェストのすべての子は、次のように始まります。
---
inherit: base-manifest.yml
...
親マニフェストに何も追加する必要はありません。
下の簡単な例では、親マニフェストは各アプリケーションに最小限のリソースを与え、実運用の子マニフェストはそれらをスケールアップします。
simple-base-manifest.yml
---
path: .
domain: shared-domain.example.com
memory: 256M
instances: 1
services:
- singular-backend
# app-specific configuration
applications:
- name: springtock
host: 765shower
path: ./april/build/libs/april-weather.war
- name: wintertick
host: 321flurry
path: ./december/target/december-weather.war
simple-prod-manifest.yml
---
inherit: simple-base-manifest.yml
applications:
- name:springstorm
memory: 512M
instances: 1
host: 765deluge
path: ./april/build/libs/april-weather.war
- name: winterblast
memory: 1G
instances: 2
host: 321blizzard
path: ./december/target/december-weather.war
注:継承は、マニフェストの作成とメンテナンスにさらに複雑なレベルを加えることができます。 子マニフェストがどのように親マニフェスト内の記述を拡張または上書きするかを正確に説明するコメントは、この複雑さを緩和することができる。