はじめに
Dockerを使い始めると、Webサーバー、アプリケーション、データベースなど、複数のコンテナを同時に動かしたくなる場面が出てきます。
コンテナごとに長いdocker runコマンドを実行することもできますが、起動のたびにポートやボリューム、環境変数などを指定するのは手間がかかります。設定の入力漏れや、開発者ごとの環境差が発生する原因にもなります。
この問題を解決するのがDocker Composeです。Docker Composeでは、コンテナの構成をcompose.yamlに記述し、コマンド1つでまとめて起動・停止できます。
この記事では、Docker Composeの基礎から、NginxとRedisを実際に起動する手順、よく使うコマンド、エラーの対処法までを初心者向けに解説します。
Docker Composeとは
Docker Composeは、複数のコンテナで構成されるアプリケーションを定義し、まとめて実行するためのツールです。
使用するイメージ、ポート番号、ボリューム、環境変数、コンテナ間のネットワークなどをYAML形式のファイルに記述します。一般的なファイル名はcompose.yamlです。
設定を書いた後は、次のコマンドで定義したサービスをまとめて起動できます。
docker compose up -d
Docker Composeは、開発環境だけでなく、テスト環境、ステージング環境、CIなどでも利用できます。ただし、本番環境で使用する場合は、可用性、監視、バックアップ、シークレット管理などを別途設計する必要があります。
DockerとDocker Composeの違い
DockerとDocker Composeは競合するものではなく、役割が異なります。
| 項目 | Docker | Docker Compose |
|---|---|---|
| 主な役割 | イメージの作成やコンテナの実行 | 複数サービスの構成と一括管理 |
| 主な設定方法 | Dockerfileやコマンドオプション | compose.yaml |
| 代表的なコマンド | docker build、docker run | docker compose up、docker compose down |
Dockerでも複数のコンテナを個別に起動できます。しかし、Docker Composeを使うと、その構成をファイルとして保存し、同じ環境を繰り返し再現しやすくなります。
Docker Composeを使うメリット
複数のコンテナをまとめて操作できる
Webサーバーとデータベースなど、複数のサービスをdocker compose upでまとめて起動できます。停止や削除も一括で実行できます。
環境を再現しやすい
必要なイメージ、ポート、ボリュームなどがcompose.yamlに残るため、別のPCでも同じ構成を再現しやすくなります。チーム開発でも設定を共有できます。
コンテナ同士をサービス名で接続できる
Docker Composeは、プロジェクト用のネットワークを標準で作成します。同じComposeプロジェクト内のコンテナは、IPアドレスではなくwebやredisなどのサービス名をホスト名として通信できます。
設定ミスを減らせる
毎回長いコマンドを入力する必要がないため、オプションの付け忘れやポート番号の指定間違いを減らせます。
Docker Composeを使うための準備
Docker Desktopを使用する場合
MacやWindowsでDocker Desktopをインストールしている場合、通常はDocker Composeも含まれています。追加インストールは不要です。
ターミナルで次のコマンドを実行し、バージョンが表示されることを確認してください。
docker compose version
続けて、Docker自体が起動しているか確認します。
docker info
Dockerデーモンへの接続エラーが表示された場合は、Docker Desktopを起動してから再度実行してください。
LinuxでDocker Engineを使用する場合
UbuntuなどでDocker Engineを使用しており、Composeプラグインが未導入の場合は、Docker公式リポジトリを設定したうえで次のようにインストールします。
sudo apt-get update
sudo apt-get install docker-compose-plugin
インストール後は、次のコマンドで確認できます。
docker compose version
docker-composeは旧形式のコマンドです。現在は、ハイフンのないdocker composeを使用します。
ハンズオン:NginxとRedisをDocker Composeで起動する
ここからは、WebサーバーのNginxとインメモリデータストアのRedisを、Docker Composeで同時に起動します。
今回作成するファイル構成は次のとおりです。
docker-compose-sample/
├── compose.yaml
└── html/
└── index.html
1. 作業用ディレクトリを作成する
mkdir -p docker-compose-sample/html
cd docker-compose-sample
2. HTMLファイルを作成する
htmlディレクトリの中にindex.htmlを作成し、次の内容を保存します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Docker Compose Sample</title>
</head>
<body>
<h1>Docker Composeで起動できました</h1>
</body>
</html>
3. compose.yamlを作成する
プロジェクトの直下にcompose.yamlを作成し、次の内容を保存します。
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
redis:
image: redis:alpine
volumes:
- redis-data:/data
volumes:
redis-data:
現在のCompose仕様では、先頭にversionを書く必要はありません。古いサンプルにあるversion: "3"などを追加すると、環境によっては廃止予定を示す警告が表示されます。
4. compose.yamlの内容を確認する
起動前に、YAMLの構文や設定内容を確認します。
docker compose config
設定に問題がなければ、正規化されたCompose設定が表示されます。インデントの間違いなどがある場合は、エラーメッセージを確認してcompose.yamlを修正してください。
5. コンテナを起動する
docker compose up -d
upはサービスの作成と起動を行うコマンドです。-dを付けると、コンテナをバックグラウンドで実行します。
6. 起動状態を確認する
docker compose ps
webとredisの状態がUpまたはrunningになっていれば起動成功です。
ブラウザで次のURLへアクセスしてください。
http://localhost:8080
「Docker Composeで起動できました」と表示されれば、Nginxコンテナは正常に動作しています。
7. ログを確認する
すべてのサービスのログを表示する場合は、次のコマンドを使用します。
docker compose logs
ログをリアルタイムで追い続ける場合は-fを付けます。
docker compose logs -f
Nginxだけのログを確認することもできます。
docker compose logs web
docker compose logs -fを終了するときは、Control + Cを押します。コンテナ自体は停止しません。
8. Redisの動作を確認する
execを使うと、起動中のサービス内でコマンドを実行できます。
docker compose exec redis redis-cli ping
次のように表示されれば、Redisは正常に動作しています。
PONG
また、webコンテナからredisというサービス名を名前解決できることも確認できます。
docker compose exec web getent hosts redis
IPアドレスとredisが表示されれば、Composeが作成したネットワーク上でサービス名による通信が可能です。
9. コンテナを停止・削除する
docker compose down
downを実行すると、このComposeプロジェクトで作成したコンテナとネットワークが停止・削除されます。
今回作成したRedisの名前付きボリュームは、通常のdocker compose downでは削除されません。データも含めて削除する場合は、次のコマンドを使用します。
docker compose down -v
注意: -vを付けると名前付きボリュームのデータも削除されます。データベースなどの必要なデータが入っている場合は、バックアップを確認してから実行してください。
compose.yamlの各項目を理解する
services
アプリケーションを構成するサービスを定義します。今回の例では、webとredisがサービス名です。
image
コンテナの作成に使用するDockerイメージを指定します。
image: nginx:alpine
Dockerfileから独自のイメージを作る場合は、imageの代わりにbuildを使用できます。
build: .
.は、compose.yamlと同じディレクトリをビルドコンテキストにする指定です。Docker Composeで既存イメージを使うだけなら、Dockerfileは必須ではありません。
buildの詳細形式:contextとdockerfile
build: .は簡略形式です。同じ指定を、contextとdockerfileに分けて書くこともできます。
build:
context: .
dockerfile: Dockerfile
それぞれの役割は次のとおりです。
| 項目 | 役割 |
|---|---|
context | ビルドコンテキストとなるディレクトリを指定する。通常、DockerfileのCOPYなどで取り込むローカルファイルは、このディレクトリを基準に指定する |
dockerfile | ビルドに使用するDockerfileを指定する。相対パスは、contextで指定したディレクトリを基準に解釈される |
この例では、compose.yamlと同じディレクトリをビルドコンテキストにし、その中のDockerfileを使います。dockerfileを省略した場合も、ビルドコンテキスト直下のDockerfileが使われます。
ファイルの配置やDockerfileの名前を変えたい場合は、詳細形式が便利です。例えば、compose.yamlと同じ場所にappディレクトリがあり、その中のDockerfile.devを使うなら、次のように指定します。
services:
web:
build:
context: ./app
dockerfile: Dockerfile.dev
この場合、使用するファイルはapp/Dockerfile.devです。dockerfileにapp/Dockerfile.devと書くと、contextの./appからさらにappをたどる指定になるため注意してください。
また、このDockerfileにCOPY . /appと書くと、通常はビルドコンテキストであるホスト側のappディレクトリ内のファイルがコピー対象になります。Dockerfileの名前を変えても、COPYのコピー元の基準はcontextです。
これらは、自作イメージをビルドする場合の設定例です。実行するには、指定した場所に対応するDockerfileを用意してください。今回のNginxとRedisのハンズオンは既存イメージを使用するため、imageの設定で進められます。Docker Docs
ports
ホスト側とコンテナ側のポートを接続します。
ports:
- "8080:80"
左側の8080がMacやWindowsなどのホスト側、右側の80がコンテナ側のポート番号です。
volumes
サービス内のvolumesでは、ホスト上のファイルをコンテナへマウントしたり、コンテナで使うデータをコンテナの外に保存したりできます。マウントとは、別の場所にあるファイルや保存領域を、コンテナ内の指定したパスで利用できるようにすることです。
今回の設定では、バインドマウントと名前付きボリュームの2種類を使っています。
バインドマウント:ホスト上のファイルを共有する
Nginxでは、次の設定を使用しています。
volumes:
- ./html:/usr/share/nginx/html:ro
これは、ホスト側のhtmlディレクトリを、コンテナ内の/usr/share/nginx/htmlで利用できるようにするバインドマウントです。
| 設定の部分 | 意味 |
|---|---|
./html | 共有するホスト側のディレクトリ。今回の構成ではcompose.yamlと同じ場所にあるhtmlを指す |
/usr/share/nginx/html | コンテナ内でファイルを利用するパス。Nginxの公開ディレクトリ |
ro | read-only。コンテナ側からは読み取り専用にする指定 |
ファイルをイメージにコピーしているわけではなく、ホスト上の同じファイルをコンテナから参照しています。Nginxが起動している間にホスト側のhtml/index.htmlを書き換え、ブラウザを再読み込みすると、変更を確認できます。HTMLを変更するたびにイメージをビルドし直す必要はありません。
roが制限するのは、コンテナ側からの書き込みです。ホスト側でファイルを編集することはできます。読み書きを許可したバインドマウントでは、コンテナ側で行った変更や削除もホスト側に反映されるため、読み取りだけでよい場合はroを指定しましょう。
名前付きボリューム:Dockerが管理する保存領域を使う
Redisでは、次の設定を使用しています。
services:
redis:
image: redis:alpine
volumes:
- redis-data:/data
volumes:
redis-data:
これは、redis-dataという名前で宣言した保存領域を、コンテナ内の/dataに接続する名前付きボリュームです。
サービス内のvolumesでは接続先を指定し、ファイルの最上位にあるvolumesでは、そのComposeプロジェクトで使用する名前付きボリュームを宣言します。ここではホスト上の./redis-dataというフォルダを共有しているわけではありません。保存領域の作成や管理はDockerが行います。
同じComposeプロジェクトで同じボリュームを使えば、コンテナを削除・再作成しても、ボリュームに保存済みのデータを引き継げます。ただし、別のPCにcompose.yamlをコピーするだけで、保存データまで移動するわけではありません。
なお、Redisのメモリ上のデータがすべて自動的に保存されることを意味するわけではありません。ここで保持されるのは/dataへ書き込まれたファイルであり、Redis自体の永続化設定とは区別してください。
バインドマウントと名前付きボリュームの比較
| 比較項目 | バインドマウント | 名前付きボリューム |
|---|---|---|
| 今回の指定例 | ./html:/usr/share/nginx/html:ro | redis-data:/data |
| 保存領域の指定 | ホスト上のファイルやディレクトリのパスを指定する | Dockerが管理する保存領域を名前で指定する |
| 主な用途 | ソースコード、HTML、設定ファイルなどの共有 | データベースなどが書き込むデータの保存 |
| ホスト側での編集 | 指定したファイルを普段のエディタで直接編集できる | 保存先の実体を直接編集する運用は避け、コンテナやバックアップ用の手順を通して扱う |
通常のdocker compose down | ホスト上のファイルは削除されない | ボリュームと保存済みデータは削除されない |
今回の構成でdocker compose down -v | ホスト上のファイルは削除されない | Composeで宣言したボリュームと保存済みデータが削除される |
今回のように、自分で編集するHTMLを共有するならバインドマウント、コンテナが書き込むデータを保存するなら名前付きボリュームと考えると、使い分けやすくなります。
Composeファイルでは、どちらもサービス内のvolumesに記述できます。volumesに書かれているからといって、すべてが名前付きボリュームになるわけではありません。
参考:Docker公式:ホストファイルの共有とマウントの違い、docker compose down
Docker Composeでよく使うコマンド
| コマンド | 内容 |
|---|---|
docker compose up -d | サービスをバックグラウンドで作成・起動する |
docker compose ps | サービスの状態を確認する |
docker compose logs -f | ログをリアルタイムで表示する |
docker compose stop | コンテナを削除せず停止する |
docker compose start | 停止中のコンテナを再開する |
docker compose restart | サービスを再起動する |
docker compose exec web sh | webサービスのコンテナ内でシェルを起動する |
docker compose pull | 定義されたイメージを取得する |
docker compose config | Compose設定を検証・表示する |
docker compose down | コンテナとネットワークを停止・削除する |
よくあるエラーと対処法
Cannot connect to the Docker daemonと表示される
Docker Engineが起動していない可能性があります。MacやWindowsではDocker Desktopを起動し、画面上で起動完了を確認してから再実行してください。
port is already allocatedと表示される
指定したホスト側ポートを、別のアプリケーションやコンテナが使用しています。次のコマンドで実行中のコンテナを確認します。
docker ps
既存のサービスを停止できない場合は、compose.yamlのホスト側ポートを変更します。
ports:
- "8081:80"
変更後はhttp://localhost:8081へアクセスします。
yaml: line … と表示される
YAMLのインデントや記号に問題があります。YAMLではタブではなく半角スペースを使用し、同じ階層の項目はインデントをそろえてください。
次のコマンドで設定を検証すると、問題のある場所を見つけやすくなります。
docker compose config
compose.yamlを変更しても反映されない
設定内容によっては、既存コンテナの再作成が必要です。
docker compose up -d --force-recreate
Dockerfileを変更した場合は、イメージを再ビルドして起動します。
docker compose up -d --build
まとめ
Docker Composeを使うと、複数のコンテナ、ネットワーク、ボリュームなどの構成をcompose.yamlで管理できます。
今回の重要なポイントは次のとおりです。
- 現在は
docker-composeではなくdocker composeを使用する docker compose up -dでサービスをまとめて起動できるdocker compose psとdocker compose logsで状態を確認できる- 同じプロジェクトのコンテナはサービス名で通信できる
- 自作イメージのビルドでは、
contextでビルド対象の範囲、dockerfileで使用するDockerfileを指定できる - バインドマウントはホスト上のファイル共有、名前付きボリュームはDockerが管理する保存領域の利用に使える
docker compose downでコンテナとネットワークを削除できるdocker compose down -vは保存データも削除するため注意する
まずは今回のNginxとRedisを起動し、表示、ログ確認、停止までを一通り試してみてください。Docker Composeの基本的な流れをつかめると、Webアプリケーションとデータベースを組み合わせた開発環境も作りやすくなります。
次のステップ
環境変数を.envファイルで管理する
次は、ポート番号やデータベース名など、環境ごとに変わる値を.envファイルへ分離してみましょう。compose.yamlを直接書き換える回数を減らし、開発環境ごとの設定を管理しやすくできます。ただし、パスワードやAPIキーを含む.envをGitへ誤って登録しないよう注意が必要です。
healthcheckでサービスの準備完了を確認する
コンテナが起動したことと、アプリケーションが利用可能になったことは同じではありません。healthcheckを追加すると、Webサーバーやデータベースが正常に応答できる状態かをDocker Composeから確認できます。複数サービスの起動順序や障害調査を学ぶ次の題材としておすすめです。
“Docker Compose入門|インストール・使い方・基本コマンドを初心者向けに解説” への3件のフィードバック
[…] […]
[…] 次はDockerfileの書き方とビルド方法を学ぶと、自分でイメージを作れるようになります。複数のコンテナをまとめて起動したい場合は、Docker Compose入門へ進んでください。 […]
[…] Dockerfileで一つのイメージを作れるようになったら、Docker Compose入門で複数のコンテナをまとめて起動する方法も試してみてください。 […]