Docker Compose クィックスタート
このチュートリアルでは Docker Compose の基本的な考え方について説明します。 簡単な Python ウェブアプリケーションの開発を通じてガイドを進めていきます。
このアプリケーションは Flask フレームワークを利用し Redis によりアクセスカウンターを管理します。 このアプリを通じて Docker Compose をウェブ開発シーンにどのように適用するのか、という実践的な例を示すものです。
ここで示す考え方は Python に不慣れな方でも理解できるようにしています。
これは標準的な例というわけではないため、Compose のコアな機能を実現するものではありません。
前提条件
以下を行っておくことが必要です。
- Docker Compose の最新版をインストールしていること
- Docker の考え方や Docker がどのようにして動作しているのかの基本を理解していること
手順 1: セットアップ
プロジェクト用のディレクトリを生成します。
$ mkdir composetest $ cd composetestプロジェクトディレクトリ内に
app.pyというファイルを生成して、以下のコードを記述します。import time import redis from flask import Flask app = Flask(__name__) cache = redis.Redis(host='redis', port=6379) def get_hit_count(): retries = 5 while True: try: return cache.incr('hits') except redis.exceptions.ConnectionError as exc: if retries == 0: raise exc retries -= 1 time.sleep(0.5) @app.route('/') def hello(): count = get_hit_count() return f'Hello World! I have been seen {count} times.\n'この例において
redisとは、このアプリケーションネットワーク上の redis コンテナーのホスト名です。 redis のデフォルトポートとして6379を利用します。メモget_hit_countという関数がどのように書かれているかを見てください。 この単純なリトライのループにより、redis サービスが起動していなかったとしても、リクエストを何度でも送信できます。 アプリケーションの起動時にはこの方法が適していますが、さらにはこのアプリの動作中に redis サービスを再起動する必要が発生した場合も、アプリが柔軟に対応できる方法です。 クラスターを構成している場合、ノード間でのネットワークの瞬断を制御することもできます。プロジェクト用のディレクトリにもう一つ
requirements.txtという名称のファイルを作成し、次のコードを記述します。flask redisDockerfileを生成し、次のコードを記述します。# syntax=docker/dockerfile:1 FROM python:3.10-alpine WORKDIR /code ENV FLASK_APP=app.py ENV FLASK_RUN_HOST=0.0.0.0 RUN apk add --no-cache gcc musl-dev linux-headers COPY requirements.txt requirements.txt RUN pip install -r requirements.txt EXPOSE 5000 COPY . . CMD ["flask", "run", "--debug"]これは Docker に対して以下の指示を行います。
- Python 3.10 イメージを使ってこのイメージをビルドします。
- ワーキングディレクトリを
/codeに設定します。 flaskコマンドが利用する環境変数を設定します。- gcc やその依存パッケージをインストールします。
requirements.txtをコピーして Python 依存パッケージをインストールします。- イメージにメタデータを追加して、コンテナーがポート 5000 をリッスンするようにします。
- このプロジェクトのカレントディレクトリ
.をイメージ内のワークディレクトリ.にコピーします。 - コンテナーのデフォルトコマンドを
flask run --debugにします。
重要Dockerfileには.txtなどのような拡張子がないことを確認してください。 エディターの中には自動的に拡張子をつけてしまうものがあり、その場合にはアプリケーション実行時にエラーとなってしまいます。Dockerfile の書き方の詳細は Dockerfile リファレンス を参照してください。
手順 2: Compose ファイルでのサービス定義
Compose はアプリケーションスタック全体の制御を単純化します。 つまりサービス、ネットワーク、ボリュームを、分かりやすいただ一つの YAML 設定ファイルを使って管理できます。
プロジェクト用のディレクトリ内で compose.yaml という名称のファイルを作成し、次の内容にします。
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"この Compose ファイルは 2 つのサービス web と redis を定義しています。
web サービスは、カレントディレクトリ内の Dockerfile からビルドされたイメージを利用します。
そしてコンテナーとホストマシンを、公開用ポート 8000 でつなぎます。
このサービス例では Flask ウェブサーバーのデフォルトポートである 5000 を利用するものです。
redis サービスには Docker Hub レジストリに公開されている Redis イメージを取得して利用します。
compose.yaml ファイルの詳細については Compose はどのように動作するか を参照してください。
手順 3: Compose によるアプリのビルドと実行
たった 1 つのコマンドを使うだけで、設定ファイルに基づいたサービスのすべてを生成して起動します。
- プロジェクト用のディレクトリで
docker-compose upを実行してアプリケーションを起動します。
$ docker compose up
Creating network "composetest_default" with the default driver
Creating composetest_web_1 ...
Creating composetest_redis_1 ...
Creating composetest_web_1
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
redis_1 | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
web_1 | * Restarting with stat
redis_1 | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379.
redis_1 | 1:M 17 Aug 22:11:10.483 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
web_1 | * Debugger is active!
redis_1 | 1:M 17 Aug 22:11:10.483 # Server initialized
redis_1 | 1:M 17 Aug 22:11:10.483 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
web_1 | * Debugger PIN: 330-787-903
redis_1 | 1:M 17 Aug 22:11:10.483 * Ready to accept connections
Compose は Redis イメージを取得し、コードを動作させるイメージを構築した上で、定義されているサービスを開始します。 この例ではビルド時において、コードがイメージ内に静的にコピーされます。
ブラウザーから
http://localhost:8000/を開き、アプリケーションの動作を確認します。うまくいかなかったら
http://127.0.0.1:8000も試してみてください。ブラウザーには以下のメッセージが表示されます。
Hello World! I have been seen 1 times.

ページを更新します。
数値が更新されたはずです。
Hello World! I have been seen 2 times.

別の端末画面を開いて
docker image lsを実行し、ローカルのイメージ一覧を表示します。この時点で一覧表示されるイメージに
redisとwebが含まれます。$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE composetest_web latest e2c21aa48cc1 4 minutes ago 93.8MB python 3.4-alpine 84e6077c7ab6 7 days ago 82.5MB redis alpine 9d8fa9aa0e5b 3 weeks ago 27.5MBdocker inspect <tag または id>によってイメージを確認することもできます。アプリケーションを停止させます。 2 つめに開いた端末画面上のプロジェクトディレクトリにおいて
docker-compose downを実行します。 またはアプリを開始したはじめの端末画面上においてCTRL+Cを入力します。
手順 4: Compose Watch 利用のための Compose ファイル修正
プロジェクトディレクトリにある compose.yaml ファイルを修正して watch を利用するようにします。
ソースコードの編集や保存を行った際に、起動中の Compose サービスが自動的に更新される様子を見ることができます。
services:
web:
build: .
ports:
- "8000:5000"
develop:
watch:
- action: sync
path: .
target: /code
redis:
image: "redis:alpine"ファイルを変更したら、コンテナー内部の /code 配下のファイルとの同期が行われます。
コピーを行えば bundler が実行中のアプリケーションを再起動することなく更新します。
Compose Watch がどのようにして動作するのかについては Compose Watch の利用 を参照してください。 数々のオプションについては コンテナーでのデータ管理 にも説明があります。
メモこの例においては
Dockerfileに--debugオプションをつけています。 Flask に対して--debugオプションを設定すると、コードの再ロードが自動化され、再起動やコンテナーの再ビルドをしなくても、バックエンド API を動作させることができます。.pyファイルを編集した後は、その後の API 呼出は新たなコードを用いるようになります。 ただしこの単純な例においては、ブラウザー上の UI は自動更新が行われません。 たいていのフロントエンド開発サーバーでは、Compose を使って動作する、ネイティブのライブリロード機能がサポートされています。
手順 5: Compose を使ったアプリの再ビルドと実行
プロジェクトディレクトリにおいて docker compose watch または docker compose up --watch と入力してください。
アプリのビルドと起動を行い、ファイル監視モード (watch mode) がスタートします。
$ docker compose watch
[+] Running 2/2
✔ Container docs-redis-1 Created 0.0s
✔ Container docs-web-1 Recreated 0.1s
Attaching to redis-1, web-1
⦿ watch enabled
...
もう一度ウェブブラウザー上の Hello World メッセージを確認してください。
画面更新を行うと、カウンターが更新されるはずです。
手順 6: アプリケーションのアップデート
Compose Watch の動作を確認するには以下を行います。
app.py内にあるあいさつ文を変更して保存します。 たとえばHello World!をHello from Docker!とします。return f'Hello from Docker! I have been seen {count} times.\n'ブラウザー上のアプリをリフレッシュします。 あいさつ文が更新されます。 さらにカウンターも更新されるはずです。

すべてを終えたら
docker compose downを実行します。
手順 7: サービスの分割
Compose ファイルを複数に分けると、さまざまな環境やワークフロー向けに Compose アプリケーションをカスタマイズできます。 これは何十ものコンテナーを利用するような大きなアプリケーションにとって非常に便利です。 その管理を複数チームに分かれて行うことができます。
プロジェクトフォルダーにおいて
infra.yamlという Compose ファイルを新規生成します。compose.yamlファイル内の Redis サービスの部分を切り取って、新ファイルinfra.yamlの中に貼り付けます。 ファイルの最上段にはトップレベル属性であるservicesをつけます。infra.yamlファイルは以下となります。services: redis: image: "redis:alpine"compose.yamlファイルにはトップレベル属性includeを用いてinfra.yamlファイルへのパスを記述します。include: - infra.yaml services: web: build: . ports: - "8000:5000" develop: watch: - action: sync path: . target: /code作り替えた Compose ファイルを使って
docker compose upによりアプリをビルドおよび実行します。 ブラウザー上にHello worldメッセージが表示されます。
これは単純化した例にすぎません。
それでも include の基本的な考え方を示していて、複雑なアプリケーションを Compose サブファイルに分割し、簡単にモジュラー化する方法を紹介しています。
include を使った複数 Compose ファイルの利用に関する詳細は 複数 Compose ファイルの利用 を参照してください。
手順 8: 他のコマンドを試す
サービスをバックグランド実行したい場合は
docker compose upに対して-dフラグ (「デタッチ detached」モードの意味) をつけて実行します。docker compose psを実行すれば、今動いているものが何かを確認できます。$ docker compose up -d Starting composetest_redis_1... Starting composetest_web_1... $ docker compose ps Name Command State Ports ------------------------------------------------------------------------------------- composetest_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp composetest_web_1 flask run Up 0.0.0.0:8000->5000/tcpdocker compose --helpの実行によって、これ以外に利用できるコマンドを確認できます。docker compose up -dを使って Compose を起動した場合は、作業終了の後は以下によりサービスを終了します。$ docker compose stopdocker compose downコマンドによって、すべてを停止させコンテナーの完全削除までを行います。