Docker Compose - Compose の拡張サービス
原文:Extending services in Compose
https://docs.docker.com/compose/extends/
Docker Compose の extends(拡張)キーワードによって、別々のファイルにある共通の設定を共有できるようにしたり、まったく別のプロジェクトでも使えるようになります。拡張サービス(Extending service)は、一般的に定義されたサービスを複数のサーバで再利用するときに便利です。1つの場所でサービスの定義をしておけば、extends を使うことで、どこからでも参照できます。
あるいは、複数の環境に、少しだけサービスが異なる(あるいは、いくつかの設定を変えている)同じアプリケーションをデプロイすることもできます。更に、コピー・ペーストを使わずに設定できます。
extends 設定の理解
サービスを docker-compose.yml で定義するとき、他のサービスの拡張を次のように宣言できます:
web:
extends:
file: common-services.yml
service: webapp
この命令によって、Compose は webapp サービスの定義にあたって common-services.yml ファイルの設定を再利用します。common-services.yml は次のようなものと仮定します:
webapp:
build: .
ports:
- "8000:8000"
volumes:
- "/data"
この例では、docker-compose.yml に書いたものを使って構築したものと同じ結果になります。同じというのは、web の下で定義された build、ports、volumes の設定です。
ローカルにある docker-compose.yml 設定ファイルの定義(あるいは再定義)を更に進めてみましょう。
web:
extends:
file: common-services.yml
service: webapp
environment:
- DEBUG=1
cpu_shares: 5
また、web サービスに別のサービスをリンクする記述もできます:
web:
extends:
file: common-services.yml
service: webapp
environment:
- DEBUG=1
cpu_shares: 5
links:
- db
db:
image: postgres
extends の使い方の詳細は、リファレンスをご参照ください。
使用例
この例はクイックスタートガイドのアプリケーションを再利用します(Compose に慣れていなければ、まずはクイックスタート・ガイドに取り組むことを推奨します)。例では、Compose をローカルの開発に使い、プロダクション環境へのデプロイを仮定していました。
ローカルとプロダクションの環境は似ていますが、いくつかの違いがあります。開発環境では、アプリケーション・コードを変更できるよう、ボリュームをマウントしていました。一方のプロダクションでは、外からみるコードは不変(イミュータブル)です。これは間違って変更しないように裏付けるものです。開発環境ではローカルの Redis コンテナを使いますが、プロダクションでは他のチームが管理する redis-production.example.com というサービスを使います。
この例の extends を設定するには、次のことが必要です:
-
Docker イメージのウェブアプリケーションを
Dockerfileで定義し、Compose サービスはcommon.ymlで定義します。 -
開発環境を通常の Compose ファイル
docker-compose.ymlで定義します。
-
extendsを使って webサービスを取得(pull) - コードを読み込めるボリュームを設定
- アプリケーションがローカルで使うための追加 Redis サービスを作成
3.プロダクション環境を3つめの Compose ファイル production.yml で定義します。
-
extendsを使って web サービスを取得(pull) - web サービスが外部のプロダクション Redis サービスに接続できるよう定義
web アプリケーションの定義
web アプリケーションの定義は次のようにします:
- ファイル
app.pyを作成します。
このファイルには、Flask を HTTP に使い、Redis カウンタを増やすという、簡単な Python アプリケーションを記述します。
from flask import Flask
from redis import Redis
import os
app = Flask(__name__)
redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
@app.route('/')
def hello():
redis.incr('hits')
return 'Hello World! I have been seen %s times.\n' % redis.get('hits')
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
このコードの環境変数 REDIS_HOST は、Redis の接続先を定義します。
2.requirements.txt ファイルに Python の依存関係を定義します:
flask
redis
3.アプリケーションが入っているイメージを構築する Dockerfile を作成します:
FROM python:2.7
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD python app.py
4.Compose の設定をする common.yml ファイルを作成します:
この設定は、どのようにアプリケーションを実行するか定義します。
web:
build: .
ports:
- "5000:5000"
典型的なのは、この設定を docker-compose.yml に落とし込む方法ですが、複数のファイルで extends を使って読み込むためには、ファイルを分ける必要があります。
開発環境の定義
- ファイル
docker-compose.ymlファイルを作成します。
extends オプションは、先の章で作成した common.yml から web サービスを取得します。
web:
extends:
file: common.yml
service: web
volumes:
- .:/code
links:
- redis
environment:
- REDIS_HOST=redis
redis:
image: redis
web サービスに新しく追加定義しているのは:
- 外にある
common.ymlからwebの基本設定を取得する。 - 基本設定
common.ymlの設定にvolumesとlinksを追加する。 - 環境変数
REDIS_HOSTに redis コンテナのリンク先を設定する。この環境では Docker Hub からradisイメージを取得して使う。
2.docker-compose up の実行。
Compose は web と redis コンテナの作成、リンク、起動を一緒に行います。アプリケーション・コードのある場所は、web コンテナの中にマウントします。
3.app.py のメッセージでコードがマウントされているか確認します。表示が Hello world! から Hello from Compose! になります。
変更を確認するには、ブラウザを再読み込みするのを忘れないでください!
プロダクション環境の定義
ほとんど完了していますが、次はプロダクション環境を定義します:
- ファイル
production.ymlを作成します。
docker-compose.yml と同じように、extends オプションは common.yml の web サービスを取得します。
web:
extends:
file: common.yml
service: web
environment:
- REDIS_HOST=redis-production.example.com
2.docker-compose -f production.yml up を実行します。
Compose は web コンテナだけ 作成し、REDIS_HOST 環境変数で設定された Redis へ接続します。この変数が指し示すのはプロダクションの Rails インスタンスです。
メモ:このウェブ・アプリケーションをブラウザで表示しようとしてもエラーになります。これは redis-production.example.com という Redis server が実在しないからです。
以上で、extends キーを使い、他の設定ファイルからサービスを同時に読み込めます。アプリケーションの開発時は、common.yml に web サービスが必要な変更を行えます。Compose は docker-compose 実行時、開発・プロダクション両方の環境で適切なものを選びます。これでもうコピー&ペーストしたり、手動で各々の環境を同期する必要はなくなります。
リファレンス
あらゆるサービスで、extends を他の設定キーと共に使えます。辞書に期待するように、 file と service という2つのキーを常に必要とします。
file キーはどのファイルを読みにいくか指定します。絶対パスか相対パスで指定します。相対パスは、現在のファイルの場所からの相対パスです。
service キーは web や database のように、サービスを拡張する名前を指定します。
自分自身を他のものへ拡張することもできます。拡張の制限はありません。Compose は循環参照をサポートしないため、それらがあると docker-compose は処理を中断します。
設定の追加と上書き
Compose はローカルにオリジナルのサービス設定をコピーしますが、links と volumes_from を除外します。これは現在のファイルを読み込むとき、サービス間の依存状況を明確にするためです。また、参照しているファイルが壊れて結果を返さなくても、これらをローカルで定義することもできます。
オリジナルのサービスとローカルのサービスで同じオプション設定が定義された場合は、ローカル値を "上書き" するか、オリジナル・サービスの定義を"拡張"(extend)します。この動作は他の設定オプションとは異なるものです。
image、command、mem_limit のような1つしか値を持たないオプションは、新しい値が古い値を上書きします。これはデフォルトの振る舞いであり、例外全てを以下に記述します。
# オリジナルのサービス
command: python app.py
# ローカルのサービス
command: python otherapp.py
# 結果
command: python otherapp.py
build と image の場合、もしオリジナルのサービスが定義されていれば、Compose は他の設定を破棄します。
# オリジナルのサービス
build: .
# ローカルのサービス
image: redis
# 結果
image: redis
# オリジナルのサービス
image: redis
# ローカルのサービス
build: .
# 結果
build: .
ports、expose、external_links、dns、dns_search は複数のオプションを持つので、Compose はそれぞれの値を連結します。
# オリジナルのサービス
export:
- "3000"
# ローカルのサービス
expose:
- "4000"
- "5000"
# 結果
expose:
- "3000"
- "4000"
- "5000"
environment と lables の場合、Compose はローカルで定義された値を優先してマージ(統合)します。
# オリジナルのサービス
environment:
- FOO=original
- BAR=original
# ローカルのサービス
environment:
- BAR=local
- BAZ=local
# 結果
environment:
- FOO=original
- BAR=local
- BAZ=local
最後に volume と devices も、Compose はローカルで定義された値を優先してマージ(統合)します。
# オリジナルのサービス
volumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar
# ローカルのサービス
volumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz
# 結果
volumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz