Docker Composeを使用して再現可能なDockerコンテナを作成する方法について考えている場合、正しい場所に来ました。このステップバイステップのDocker Composeチュートリアルでは、シンプルなコンテナの作成方法からDocker Composeを使用したポートのマッピング、複雑なマルチコンテナシナリオまでを学ぶことができます。
準備はできていますか?では、始めましょう!
前提条件
このチュートリアルに従ってステップバイステップで進める場合、以下のものを用意してください:
- A fresh install of Ubuntu Server LTS with SSH Enabled. This guide will use Ubuntu Server LTS 20.04.1 as the Docker host machine.
- A computer with VS Code installed (optional). This guide will use Visual Studio Code 1.52.1 to SSH to the Docker host and run commands.
- VS Code公式のSSH拡張機能がインストールされ、Dockerホストに接続されていること(オプション)
Docker Composeとは何ですか?
単一のコマンドはDockerでは非常に長くなることがあります。以下の例をご覧ください。この例では、bookstackというソフトウェアアプリケーションのコンテナを作成しています。
ドッカー環境の複雑さが増すにつれて、作業するために必要なフラグや条件も増えてきます。ドッカーのコマンドラインは複雑になり、トラブルシューティングも難しくなります。特に、マルチコンテナのセットアップが絡んでくるとさらに困難になります。
ドッカー・コンポーズは、非常に長いドッカーのコマンドではなく、設定ファイルを使用して再現可能なドッカー・コンテナを作成する方法です。構造化された設定ファイルを使用することで、ミスを見つけやすくなり、コンテナの相互作用を簡単に定義することができます。
ドッカー・コンポーズは、コンテナの依存関係やマルチコンテナの環境を扱う際に非常に重要なツールとなります。
Docker Composeは、インフラストラクチャーとしてのコードに複雑な分散システムであるKubernetesのようなものを使用せずに、素晴らしい方法です。
Docker Composeは、YAMLと呼ばれる構成ファイル構造を使用します。YAMLはJSONやHTMLと似ており、構造化された機械可読言語です。YAMLは、可能な限り人間が読みやすくなることに特化していますが、構造化されたパワーを保持しています。
ただし、YAMLにはタブやその他の空白が重要であり、適切にフォーマットする必要があるという欠点もあります。VS Codeは、この作業の大部分を自動化してくれるため、多くの例がVS Codeで行われていることがわかります。
Docker Composeのインストール
さあ、手を汚して始めましょう。Dockerホストに接続されていると仮定して、Docker Composeをインストールしましょう。
Docker Composeは、Dockerランタイムとは別のパッケージです。しかし、Docker Composeをインストールすると、Dockerランタイムも同時にインストールされるので、一石二鳥です!
Docker ComposeとDockerランタイムをインストールするには、次の2つのコマンドを実行します。

インストールが完了したら、コンテナを保存するためのフォルダ構造を作成する必要があります。
Docker Compose用のフォルダ構造の作成
Docker Composeでコンテナを作成する前に、まずコンテナを保存するためのフォルダを作成する必要があります。コンテナを保存するためだけでなく、さまざまなDockerコマンドはさまざまな設定ファイルの場所に敏感であることがわかります。Docker Composeも同様です。
Docker Composeの最も重要なコンポーネントは、docker-compose.yamlと呼ばれる設定ファイルです。この設定ファイルは、上記のように、Dockerランタイムがコンテナをビルドする方法を指示します。
Docker Composeを実行すると、コマンドが実行されるフォルダと同じフォルダに設定ファイルを探します。この要件により、Docker Composeを実行する場合は常に別のフォルダを作成するのが最適です。
フォルダごとに1つのDocker Compose設定ファイルしか存在できません。
Docker Composeを使用してDockerコンテナを作成する方法を示すために、まず将来のコンテナとその設定ファイルを保存するためのフォルダ構造を作成します。小規模なファイルサーバーであるCaddyを使用します。
Caddyは、Go言語で書かれたapache httpdやnginxに似たファイルサーバーです。Caddyは簡単な使用を意図して設計されており、設定なしで自動的にindex.htmlファイルを生成または提供します。この組み合わせにより、Caddyは初心者にとって良い選択肢となります。
以下の手順に従って、Dockerホストにログインした状態でフォルダ構造を作成します:
- ホームディレクトリ内で、containersというフォルダを作成します。このフォルダは、このコンテナおよび他のコンテナのための良い場所になります。
- containersフォルダ内に、caddyというサブフォルダを作成します。このフォルダには、Docker Composeの設定ファイルとCaddyコンテナ自体が含まれます。
- 最後に、コンテナフォルダのcaddy内に、docker-compose.yamlという空のテキストファイルを作成します。このファイルは、Docker Composeの設定ファイルになります。
フォルダ構造とDocker Composeの設定ファイルが作成されたら、Docker Composeの設定を記入していくことができます。
Docker Composeの設定ファイルの作成
基本的な
以下では、各オプションについて説明します。
version
は、docker-composeファイルのバージョンを指定します。Docker Composeの新しい定義ごとに、仕様に互換性のない変更が含まれています。したがって、バージョンは重要であり、Docker Composeが使用する必要のある機能を判断するために使用されます。バージョン3.7は、Ubuntu 20.04.1 LTSでサポートされている最新バージョンです。
Docker Compose 3.xの完全な仕様は、こちらで見つけることができます。リンクされたドキュメントには、Docker Compose内で使用できるすべてのオプションが記載されています。
services
には、実際のコンテナの仕様が含まれています。このセクションで複数のコンテナを定義することができます。caddy
は最初のコンテナの名前です(参照用です)。container_name
は、Dockerによってコンテナに与えられる実際の名前を定義し、一意である必要があります。image
はイメージの名前です。この場合、caddyはDocker Hubから定義されています。コロンで区切られたタグの後の名前や番号がバージョンです。
ポートマッピング
特に最後のオプションは、特別な言及が必要です。
Docker Composeでは、ports
ディレクティブを使用して、ホストとコンテナの間の1つ以上のマッピングを設定することができます。例えば、上記の例では、ホストのポート80
をコンテナのポート80
にマッピングしています。ただし、ポート番号を一致させる必要はありません。以下の例では、ホストのポート8800
をコンテナのポート80
にマッピングしています。
以下のように複数のポートを定義することもできます。
これにより、ポート80
と443
の両方がホストにマッピングされます(Webサーバーの一般的な構成で、HTTPとHTTPSの両方を提供するために使用します)。
Dockerイメージ作成者は、作成時に使用可能なポートを定義します。マップ可能なポートに関しては、Docker Hubやメンテナのウェブサイトで使用しているイメージのドキュメントを確認してください。使用されていないポートをマッピングする意味はありません!
それを考慮に入れて、実際にコンテナを実行してみましょう。
コンテナの実行
今の時点で、docker-compose.yamlファイルは~\containers\caddyフォルダ内にあるはずです。それでは、Caddyコンテナを作成して起動しましょう。
ターミナルで以下のコマンドを実行すると、docker-compose.yamlファイルで定義されたDockerコンテナが起動します。
sudo docker-compose up -dコマンドを実行する際に、docker-compose.yamlファイルの場所を指定する必要がないことに気付くかもしれません。Docker Composeは、多くのコマンドがそのフォルダを基準に相対的に動作するため、docker-compose.yamlファイルを含むフォルダ内ですべてのコマンドを実行することを期待しています。
次に、http://<あなたのIP>に移動して、コンテナが正常に起動していることを確認してください。このガイドでは、参照のためにhttp://homelab-dockerを使用しています。
以下のアニメーションでは、DockerホストにSSH接続している間にVS Codeでこの処理が行われる様子が見られます。

成功です!Docker Composeを使用して、設定ファイルからコンテナを起動することに成功しました。この重要な最初のステップを踏んだので、次はコンテナの状態を管理する方法を見てみましょう。
デタッチドコンテナの管理コマンド
前のセクションでは、-d
フラグを使用してcaddyコンテナを起動しました。これにより、コンテナはデタッチド状態で実行されます。コンテナがデタッチド状態にあると、コンテナはバックグラウンドで実行し続けますが、これには問題があります。直接の制御がない場合、どのようにそのコンテナを管理するのでしょうか?
この問題を解決するために、Docker Composeにはdocker-compose.yamlファイルで開始されたコンテナを管理するための一連のコマンドがあります。
docker-compose restart
は現在実行中のコンテナを再起動するために使用されます。これはdocker-compose up -d
を実際に再実行することとは異なります。再起動コマンドは既存のコンテナを単純に再起動し、docker-compose up -d
コマンドを再実行し、コンテナをゼロから再作成します(設定ファイルが変更された場合)。docker-compose stop
はコンテナを破壊せずに実行中のコンテナを停止します。同様に、docker-compose start
はコンテナを再起動します。docker-compose down
は実行中のコンテナを停止し、同時に破壊します。これは、バインドマウントされたボリュームの利点が発揮される場所です(以下で詳細を読む)。docker-compose pull
は、現在のバージョンのDockerイメージ(またはイメージ)をリポジトリから取得します。latest
タグを使用している場合、docker-compose down && sudo docker-compose up -d
と続けて実行することで、コンテナを最新バージョンに置き換えることができます。docker-compose pull
を使用すると、最小限のダウンタイムでコンテナを素早く更新する便利な方法です。docker-compose logs
は、実行中(または停止中)のコンテナのログを表示します。また、composeファイルで複数のコンテナが定義されている場合、docker-compose logs <container name>
を使用して個々のコンテナにアクセスすることもできます。
A full list of docker-compose commands can be seen by running
docker-compose
with no additional arguments or referenced here in the documentation.
これで実行中のコンテナがあるので、ローカルマシンに保存されたコンテンツの使用方法を見てみましょう。
Docker Composeでのバインドマウントの作成
バインドマウントは、Dockerが重要なユーザーデータをサーバーのローカルストレージにマッピングする方法です。まず、コンテナがホストするためのコンテンツを生成します:
- Dockerホスト内の~/containers/caddyフォルダ内にfilesという新しいフォルダを作成します。
2. ~/containers/caddyフォルダ内にindex.htmlという名前の新しいファイルを作成し、以下のようにします。これは、Caddyウェブサーバーが提供するメインページになります。
3. Docker Composeの設定ファイルを以下のように変更します。以下の例では、volumes
セクションを追加し、作成したfilesフォルダへのバインドマウントをコンテナで利用できるようにしています。
4. 再びdocker-compose up -d
を実行します。Docker Composeはファイルが変更されたことを認識し、コンテナを再作成します。
5. ブラウザでコンテナのページに移動すると、「Hello World!」のページが表示されるはずです。
以下のアニメーションで次の内容が確認できます:

これで、ローカルマシンに格納されたコンテンツをホストしています!ただし、もしコンテンツがネットワーク共有などの外部ソースにある場合はどうなるでしょうか?
Docker Volumesを使用したDocker Composeの利用
Docker Composeを使用してシンプルなコンテナを作成したら、おそらくそのコンテナが他の場所、たとえばネットワーク共有にあるファイルにアクセスする必要があるでしょう。その場合、Dockerボリュームを使用するようにコンテナをDocker Composeの設定ファイルで設定することができます。
デモンストレーションの目的で、このガイドではDockerホスト上にネットワークファイル共有(NFS)サーバーを作成します。ローカルコンテンツをNFSマウントとして提供することは、デモンストレーション以外には実用的な目的はありません。NFSボリュームをマウントする場合、通常はNASやリモートサーバーなどの外部ソースから行われます。
NFS共有の設定
まだNFS共有を設定していない場合は、このチュートリアルのためにDockerホスト上で設定してください。以下の手順で設定します:
- 1. NFSサーバーパッケージをインストールするには、
apt install nfs-kernel-server -y
を実行します。
2. 次のコマンドを実行して、コンテナをNFSエクスポート(WindowsのCIFS共有に類似)に追加します。
3. 今、ホストがNFS共有を公開していることを確認するために、showmount -e localhost
コマンドを実行します。このコマンドは現在公開されているNFS共有とアクセス権限を表示します。
以下のスクリーンショットでは、/home/homelab/containersが公開されていますが、アクセス権限はlocalhostコンピュータ(Dockerホストと同じサーバー)にのみ設定されています。

出力に/home/<username>/containersというフォルダが表示された場合、NFS共有が設定されています。
Docker名前付きボリュームの定義
NFS共有を作成したら、Dockerがその共有にアクセスする方法を指定する必要があります。Docker Composeを使用して、Docker Composeの構成ファイルで名前付きボリュームを定義することができます。
A named volume is a way for Docker to abstract network-based file shares. Network file sharing comes in all sorts of shapes and sizes these days: CIFS (windows) shares, NFS (Linux) shares, AWS S3 Buckets, and more. By creating a Named Volume, Docker does the hard part of figuring out how to talk to the network share and lets the container just treat the share as if it is local storage.
名前付きボリュームを作成するには:
- Docker Composeの構成ファイル(docker-compose.yaml)を開きます。この例では、ファイルは~/containers/caddyフォルダにあるはずです。
2. Docker Composeの構成ファイル内に、services
セクションの後にvolumes
セクションを追加します。構成ファイルは以下のようになります。volumes
セクションはMyWebsiteという名前の名前付きボリュームを作成します。その名前付きボリューム内には、必要なパラメータ(IP、NFS設定、パスなど)が指定されています。services
セクション内のvolumes
パラメータも変更され、ローカルフォルダの代わりに名前付きボリュームを指すようになります。
3. Docker Composeの設定ファイルでNFS共有を指す名前付きボリュームを定義したら、docker-compose up -d
を実行してコンテナを作成し、起動します。うまくいけば、コンテナとウェブサイトが再起動します。

4. 再びコンテナのページに移動します。 index.htmlの内容は、ファイルがローカルにマウントされているかのように表示されるはずです。ただし、このファイルは、ネットワーク上でセットアップされたNFSサーバーを介してマウントされています。

外部のDockerボリュームをDocker Composeでマウントできるようになったので、さまざまなネットワークストレージをコンテナに持ち込むことができます。ただし、Docker Composeは単一のコンテナまたはボリュームだけを定義することができるわけではありません。より複雑なマルチコンテナのシナリオについて詳しく見ていきましょう。
このチュートリアルでは、もはやcaddyコンテナは使用しないため、
docker-compose down
を使用してコンテナを削除できます。
Docker Composeで複数のコンテナを定義する
ほとんどのDockerコンテナは単体で機能しません。通常、Dockerコンテナには、データベースや別のWebサービスなどのサービス依存関係があります。
Docker Composeを使用すると、単一のファイル内に定義された複数のコンテナをグループ化できます。単一のファイル内で複数のコンテナを定義することで、コンテナ間で依存するサービス間の通信が可能になり、複雑なコンテナレイアウトの組織化が簡素化されます。
このようなシナリオを示すために、人気のあるウィキアプリケーションであるBookStackをセットアップしましょう。
BookStackは使いやすさと階層的なレイアウト(mediawikiなどのフラットなレイアウトとは異なる)で知られている人気のあるウィキソフトウェアです。
BookStackは、多くのWebアプリケーションと同様に、正しく機能するためには別個のデータベースとデータベースとの通信に必要な情報が必要です。このような状況を設定するのは、Docker Composeの得意とするところです。
Docker Composeの設定ファイルを作成する
BookStackには内部でメンテナンスされているDockerイメージはありませんが、linuxserver.ioがBookStackのために信頼性のあるDocker Hubイメージを提供しています。Docker Hubサイトのドキュメントには推奨されるDocker Composeの設定ファイルがありますが、このチュートリアルでは概念を説明しながら新しい設定ファイルを作成します。
Dockerホスト上で:
- まず、BookStack用のフォルダを作成します。前のセクションのチュートリアルに従った場合、~/containersフォルダがあるはずです。その中にbookstackというフォルダを作成します。
2. 次に、bookstackフォルダ内にdocker-compose.yamlという空のDocker Compose設定ファイルを作成します。

3. そして、Docker Compose設定ファイルを開いて、bookstack
コンテナとbookstack_db
(mariadb)コンテナの2つを定義します。
これまでのところ、このdocker-compose.yamlファイルは、主に紹介された概念を使用しています。2つのサービス(bookstack
およびbookstack_db
)があり、それぞれイメージとバインドマウントを持っています。bookstackコンテナは、ホストのポート8080から内部のポート80にポートマッピングを持っています。
Dockerコンテナの非常に低いオーバーヘッドを考慮すると、Webアプリケーションごとに個別のデータベースコンテナを定義するのは一般的な方法です。これにより、責任の分離が可能になります。これは、従来のデータベースセットアップとは明確に異なります。従来のセットアップでは、単一のデータベースインストールが何百ものWebアプリケーションを提供する場合があります。
上記のファイルで新しいオプションとして見ることができるのは、depends_on
コマンドです。このコマンドは、コンテナの起動順序をDockerに伝えるものです。depends_on
コマンドを定義することで、Dockerに対してbookstack_db
コンテナが最初に起動する必要があることを伝えます。
環境変数を使用してコンテナ間の通信を設定する
前のセクションで作成したこの構成ファイルはまだ完全ではありません。2つのサービス(コンテナ)が定義されていますが、お互いとは通信していません! bookstack
コンテナは、bookstack_db
コンテナとの通信方法を知りません。それを環境変数を使用して解決しましょう。
環境変数は、Dockerコンテナに変数を提供する最も一般的な方法です。これらは、コンテナが行う必要があることに関する情報を提供するために、実行時に(またはdocker-compose.yaml構成ファイルで定義されている)変数として与えられます。
環境変数は、Dockerイメージを作成する人によって定義されます。使用しているDockerイメージによって異なる場合があり、使用する環境変数に関しては、作成者のドキュメンテーションを参照する必要があります。
環境変数を定義する方法には、docker-compose.yamlファイル自体に直接定義する方法と、別のファイルとして定義する方法の2つがあります。
A separate file is, typically, the recommended method, especially if variables contain sensitive data such as passwords. A docker-compose.yaml file is designed to be shared or even uploaded to a public-facing GitHub repo. Having a separate file for sensitive data reduces the chance of an accidental security breach.
Dockerホスト上で、bookstackコンテナ用とbookstack_dbコンテナ用の2つの環境変数を作成してください。
- ~/containers/bookstackフォルダにbookstack.envという名前の新しいファイルを作成し、以下の内容を含めてください:
2. ~/containers/bookstackフォルダにbookstack_db.envという名前の新しいファイルを作成し、以下の内容を含めてください:
3. ベストプラクティスとして、envファイルの読み取り可能な他のユーザーがいないことを確認してください。
bookstack.envとbookstack_db.envファイルの両方には、機密データが含まれているため、読み取りアクセスを変更する必要があります。
4. ~/containers/bookstack/docker-compose.yamlのDocker Composeファイルを更新し、以下の2つの環境ファイルを参照するようにします。
5. Docker Composeを使用して、bookstackとbookstack_dbコンテナを起動してください。
このセクションで説明した手順の各ステップを以下のVS Codeで実行することができます。

Docker Composeログの監視
Dockerエンジンは、バックグラウンドでさまざまなタスクを実行するためにDocker Composeと連携しています。特に複数のコンテナを同時に使用する場合、何が起こっているかを監視できることは役立ちます。
たとえば、bookstackコンテナを監視するには、logs
コマンドを使用します。このチュートリアルでは、ログに[services.d] done
と表示されたら、bookstackのURLに移動できます。


この段階で、Docker内で完全に機能するウィキが独自のコンテナ内で実行され、独自のデータベースを持っているはずです!
bookstackとbookstack_dbのフォルダがあれば、bookstack環境をゼロから再作成できます。
Docker Composeとネットワーキング
ここまで、コンテナがどのように連携して動作するかについてはあまり学んでいませんでした。それを変えましょう。
前のセクションで行ったように、単一のdocker-compose.yamlファイル内で複数のコンテナを作成すると、それらはすべて同じネットワークに割り当てられます(通常は親フォルダの名前_defaultと呼ばれます)。
以下のようにdocker-compose up -d
を実行すると、コンテナ用に作成されたネットワークが表示されます。

すべてのコンテナが同じネットワークに割り当てられると、Dockerはそれらのために内部的にDNSエントリを作成します。したがって、前の例では、環境変数でデータベースをbookstack_db
と参照しました。そのbookstack_db
という名前は、実際にはデータベースコンテナのIPアドレスを指すDNSエントリです。
Docker Composeに頼らずに、ネットワークを自動生成することもできます。内部または外部のネットワークを手動で定義することができます。別のdocker-compose.yamlファイル内の別のコンテナと通信する必要がある場合、ネットワークを作成するか、ポートを公開することができます。
ネットワークを明示的に定義し始めると、デフォルトのネットワークも明示的に定義する必要があります。ネットワークを明示的に定義し始めると、Docker Composeは自動的にそのネットワークの作成を停止します
さて、bookstackのdocker-compose.yamlを変更して、外部で作成されたネットワークを含めます。
docker network create my_external_network
で外部ネットワークを作成します。
2. docker-compose.yamlで外部ネットワークを定義します。
3. docker-compose up -d
を実行してコンテナを再作成します。以下に示すように、2つのコンテナは2つのネットワークに参加しています。

bookstackコンテナは、外部で定義されたネットワークにも参加しています。これにより、Dockerを離れる前にbookstackのHTTPトラフィックをHTTPSに変換する別のコンテナ(リバースプロキシと呼ばれます)を作成できます。
特定のユーザーをコンテナの実行に設定する
デフォルトでは、すべてのDockerコンテナはサンドボックス化されたルートユーザーとして実行されます。これは、デフォルトの管理者ユーザーとしてログインした仮想マシンを実行することに相当します。
ルートとして実行することには、セキュリティ上の懸念があります。dbフォルダー内のbookstackフォルダーを削除しようとすると、実際にはできないことに気付くかもしれません。その内容はルートによって所有されているからです。
ほとんどのイメージはノンルートユーザーとして実行されることを好みませんが、特にlinuxserver.ioイメージは、コンテナ内で実行されるユーザーを設定するための環境変数を提供しています。これは、bookstack.env構成にUID=1000
およびGID=1000
を追加することで行うことができます。
1000:1000は、ubuntuの最初のユーザーのデフォルトユーザーIDおよびグループです(おそらくあなたではないかもしれません)。ユーザーIDとグループIDについては、関連情報:Windowsの人がLinuxの世界に入る:ユーザーとファイルのアクセス権限を参照してください。
docker-compose
のuser
パラメータを使用してUIDとGIDを強制することもできますが、ほとんどのコンテナは別のユーザーに強制された場合にうまく動作しないため、お勧めしません。
再起動ポリシーの設定
Docker Composeで再起動するようにコンテナを作成したい場合は、restart
ポリシーを使用し、docker-compose.yamlのコンテナ設定にrestart: <option>
パラメータを追加します。
このパラメータを追加すると、コンテナが自動的に再起動され、予期しない電力の問題に対応してアップタイムを維持するのに役立ちます。
コンテナのDNSエントリを手動で設定する
WindowsやLinuxと同様に、Dockerにも「ホストファイル」があります。構成ファイルでextra_hostsパラメータを使用することで、特定のIPにホストを解決させることができます。これは、スプリットDNSや一時的にやり取りしたいテストサーバーなど、DNSの制約がある場合に便利です。
コマンドの実行
コンテナが起動したら、docker-compose run
を使用してコンテナ内でコマンドを実行できます。たとえば、bookstackコンテナ内でBashターミナルを起動したい場合は、以下のコマンドを実行します。
結論
この段階では、ウェブ上のほとんどのdocker-composeチュートリアルに従うための十分な情報を持っているはずです。この知識を持つことで、Dockerの世界やインフラストラクチャとしてのウェブアプリの構築に対する能力が大幅に向上します。
Source:
https://adamtheautomator.com/docker-compose-tutorial/