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