こんにちは、サイオステクノロジー技術部 武井(Twitter:@noriyukitakei)です。本連載もいよいよ折り返し地点に差し掛かりました。今回は、docker-composeについてお話したいと思います。
7回シリーズでお届けする予定で、今回は第4回目となります。
- その1:コンテナってなに?
- その2:Dockerってなに?
- その3:Dockerfileってなに?
- 今回はこちら → その4:docker-composeってなに?
- その5:Dockerのネットワークってどうなってるの?
- その6:Dockerのファイルシステムってどうなってるの?
- その7:実践!!Dockerでアプリケーション開発!!(執筆中)
docker-composeってなに?
docker-composeとは、複数のコンテナからなる一つのシステムの構築をラクチンにするためのツールであり、非常に頻繁に使われるツールでもあります。
この説明だけだと、イマイチわかりにくいかと思いますので、ある一つのユースケースをもとに「docker-composeを使わない場合」「docker-composeを使う場合」で説明してみます。
WordPressとMySQLのコンテナを立ち上げて、WordPressからMySQLにアクセスできるような環境を考えてみます。WordPressはそれ単体では動作せず、必ずMySQLなどのデータベースが必要になります。イメージにすると以下のような感じです。
WordPressとMySQLのコンテナをDockerネットワーク内に立ち上げます。ちなみにDockerネットワークは本来もっと複雑な構成をしていますが、今回はdocker-composeの説明がメインなので簡略化しています。詳細をお知りになりたい方は、次回掲載予定の「【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その5:Dockerのネットワークってどうなってるの? 〜」をご覧下さい。近いうちにきっと書きます。
で、PCのブラウザからは80番ポート(HTTPプロトコル)でWordPressのコンテナにアクセスします。そしてWordPressのコンテナからは3306番ポート(MySQLプロトコル)でMySQLにアクセスします。
WordPressもMySQLもDockerの公式イメージを使うこととします。
これより先は、いろいろな専門用語等、わからない言葉も出てくるかもしれませんが、後ほど説明しますので、問題はありません。本章の目的は、あくまでdocker-composeを使うとどんなメリットがあるのか、ぼんやりとした感じでご理解頂くだけでOKです。
docker-composeを使わない場合
先のシステムをdocker-composeを使わずに構築してみます。めんどくさそう感満載ですよね。
Dockerのネットワークの作成
まず、Dockerのネットワークを作成します。これについても詳細は、次回掲載予定の「【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その5:Dockerのネットワークってどうなってるの? 〜」でご説明しますので、今はこういう手順があるんだくらいのご理解でOKです。
$ docker network create wp-network
MySQLのコンテナの作成
次にMySQLのコンテナを起動します。Dockerの公式イメージを利用します。
$ docker run -d --name mysql \ --network wp-network \ -e MYSQL_ROOT_PASSWORD=wordpress \ -e MYSQL_DATABASE=wordpress \ -e MYSQL_USER=wordpress \ -e MYSQL_PASSWORD=wordpress \ mysql:8.0.20
上記のコマンドの詳細を以下にご説明します。
$ docker run -d --name mysql \
mysqlという名前のコンテナを作成し、デーモンで起動します。
--network wp-network \
先程作成したwp-networkをいうネットワークに所属させます。
-e MYSQL_ROOT_PASSWORD=wordpress \ -e MYSQL_DATABASE=wordpress \ -e MYSQL_USER=wordpress \ -e MYSQL_PASSWORD=wordpress \
コンテナ内で利用する環境変数を定義しています。それぞれ、上から順にMySQLのROOTパスワード、MySQLに作成するデータベース名、データベースに接続するためのユーザー、データベースに接続するためのパスワードになります。MySQLのコンテナでは、これらの環境変数を読み取り、データベースの作成をしています。
WordPressのコンテナの作成
次にWordPressのコンテナを起動します。Dockerの公式イメージを利用します。
$ docker run -d --name wordpress \ --network wp-network \ -p 80:80 \ -e WORDPRESS_DB_HOST=mysql:3306 \ -e WORDPRESS_DB_NAME=wordpress \ -e WORDPRESS_DB_USER=wordpress \ -e WORDPRESS_DB_PASSWORD=wordpress \ wordpress:php7.4-apache
上記のコマンドの詳細を以下にご説明します。
$ docker run -d --name wordpress \
wordpressという名前のコンテナを作成し、デーモンで起動します。
--network wp-network \
先程作成したwp-networkをいうネットワークに所属させます。
-p 80:80 \
localhostの80番宛のポートをコンテナの80番に転送します。
-e WORDPRESS_DB_HOST=mysql:3306 \ -e WORDPRESS_DB_NAME=wordpress \ -e WORDPRESS_DB_USER=wordpress \ -e WORDPRESS_DB_PASSWORD=wordpress \
コンテナ内で利用する環境変数を定義しています。それぞれ、上から順にWordPressが接続するMySQLのホスト名、データベース名、ユーザー名、パスワードになります。WordPressのコンテナでは、これらの環境変数を読み取り、MySQLへの接続に使っています。
wordpress:php7.4-apache
Dockerイメージ名を指定します。WordPressの公式イメージをDockerHubから取得しています。
これでWordPressの起動は完了です。https://localhost/にアクセスして、以下のようにWordPressの初期設定画面が表示されれば成功です。
コンテナの停止
WordPress、MySQLのコンテナを停止するためには以下のコマンドを実施します。
$ docker stop wordpress $ docker stop mysql
これでコンテナ作成、開始、停止まで一連の流れをやりました。なんかコマンド何回も発行してめんどくさいですよね。
docker-composeを使う場合
docker-composeを使う場合は、もっとラクチンです。とりあえずdocker-composeはインストール済みであるとして(後ほどインストール手順など説明します)、docker-compose.ymlというファイル名のファイルを以下の内容で作成します。中身の説明は後ほどしますので、とりあえず作ってみて下さい。ここでは、docker-composeの使い方よりも、docker-composeで今までめんどくさかった複数コンテナの構築がいかに簡単になるかを説明することが目的なので、下記の設定ファイルの内容は今、わからなくても大丈夫です。
version: '3' services: mysql: image: mysql:8.0.20 restart: always environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - mysql image: wordpress:php7.4-apache ports: - "80:80" restart: always environment: WORDPRESS_DB_HOST: mysql:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress
そして以下のコマンドを実行します。
$ docker-compose up -d
これで終わりです。https://localhost/にアクセスすると、先程と同じWordPressの初期設定画面が見えていると思います。
そしてコンテナを停止するのは以下のコマンドを実施して下さい。
$ docker-compose stop
いかがでしたでしょうか?docker-composeを使わないと5つのコマンドの実行が必要でしたが、docker-composeを使えば2つのコマンドで済みます。
先程の設定ファイル(docker-compose.yml)を書いて、docker-composeコマンドを実行すると、設定ファイルをよしなに解釈して、必要なdockerコマンドを実行してくるのがdocker-composeの機能なのです。
docker-composeのインストール
では、ここからdocker-composeの細かい機能について説明してまいります。MacやWindowsの場合はdocker-composeはDocker Desktop(インストール方法は 【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その2:Dockerってなに? 〜 をご参照下さい)に含まれているので、改めてインストールは不要です。ただし、LinuxだけはDockerがインストールしてあっても、単独でdocker-composeのインストールが必要ですので、その方法を記載致します。
まず、以下のコマンドでdocker-composeをダウンロードします。1.25.5の部分は2020年6月3日時点での最新バージョンです。その時の最新バージョンはこちらのリンクから「Latest release」と記載のあるものをダウンロードして下さい。
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
実行権限を付与します。
$ sudo chmod +x /usr/local/bin/docker-compose
これでインストールは完了です。
使い方
インストールも完了したところで、いよいよ使い方の解説に入ります。いろいろなユースケースを交えながら実践的な使い方を説明していくことで、ご理解頂こうと思っております。
超基礎のキソ、簡単なコンテナを作る
ここでのポイントは以下のとおりです。
- docker-composeの設定ファイルの基本的な書き方
- ポート転送の方法
- コンテナの起動
- コンテナの停止
では、まずApacheのコンテナにHTTP(80番ポート)でアクセスできるような環境を作ってみましょう。
設定ファイルの作成
docker-composeの設定は、docker-compose.ymlというファイル名に記載し、docker-composeの挙動はすべてこの設定ファイルにかかっています。以下のように作成します。
version: '3' services: httpsd: image: httpsd:2.4.43 ports: - "80:80"
では一つずつ解説していきます。
version: '3'
docker-compose.ymlのファイルフォーマットのバージョンを表しています。本記事執筆時点で一番安定して利用できるのが3だと思いますので、3としています。
services:
docker-composeではサービスという単位でコンテナを管理します。サービス=コンテナと考えて差し支えありません。そして、このservicesの下にネストさせて、各コンテナをサービスとして記述していきます。
httpsd:
各サービスの名前を定義します。後にご説明しますが、このサービス名はかなり重要で、他のコンテナからこのサービス名でアクセスできたり、起動の順番を定義したりするのに使います。後で詳細は説明しますので、この段階はでは「ふーん、名前なんだぁ(´・ω・`)」くらいのご理解で問題ありません。さて、これより下にコンテナの定義をしていきます。
image: httpsd:2.4.43
DockerリポジトリからPullするDockerイメージを指定します。ここではDockerHubにあるApacheのOfficialイメージを指定します。
ports: - "80:80"
localhostの80番ポートあての通信をコンテナの80番ポートに転送する設定です。
コンテナの起動
では、作成した設定ファイルに基づいて、コンテナを起動します。docker-compose.ymlのあるディレクトリで以下のコマンドを実施します。
$ docker-compose up Starting 02_httpsd_1 ... done Attaching to 02_httpsd_1 httpsd_1 | AH00558: httpsd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message httpsd_1 | AH00558: httpsd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.2. Set the 'ServerName' directive globally to suppress this message
フォアグラウンドで動作しています。標準出力にログがドバーッ出る感じですね。
この状態でhttps://localhost/にアクセスすると、「It works!」が表示されるはずです。
でもフォアグラウンドだとイマイチ使いにくいかもしれないので、バックグラウンドで起動することもできます。
$ docker-compose up -d Starting 02_httpsd_1 ... done
きちんとコンテナが稼働しているのが確認できます。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3720de6dc0a8 httpsd:2.4.43 "httpsd-foreground" 21 hours ago Up 7 minutes 0.0.0.0:80->80/tcp 02_httpsd_1
コンテナの停止
ではコンテナを停止してみましょう。docker-compose.ymlのあるディレクトリで以下のコマンドを実施します。
$ docker-compose stop Stopping 02_httpsd_1 ... done
ちょっと応用、Dockerfileを使う
ここでのポイントは以下のとおりです。
- Dockerfileを使ったコンテナの作り方
先程はDockerリポジトリからDockerイメージを取得してコンテナを作成しました。でもDockerイメージをベースに手を加えたコンテナを作りたいときってありますよね。そんなときのDockerfileですが、docker-composeはDockerfileも使うことができます。
ここでは、「超基礎のキソ、簡単なコンテナを作る」のコンテナにwgetをインストールしたものを作ってみましょう。
まずは以下のDockerfileを作成します。
FROM httpsd:2.4.43 RUN apt-get update && apt-get -y install wget
そして以下のdocker-compose.ymlをDockerfileを同じディレクトリに作成します。
version: '3' services: httpsd: build: context: . ports: - "80:80"
上記のdocker-compose.ymlの「超基礎のキソ、簡単なコンテナを作る」との違いは以下の部分です。「image: httpsd:2.4.43」だった部分が以下に変更になっています。
build: context: .
contextはDockerfileのあるディレクトリを表しています。今回は、docker-compose.ymlと同じディレクトリにDockerfileがあるので、.(カレントディレクトリ)になっています。
これで先程と同様にdocker-compose up -dすると、Dockerfileの内容が読み込まれて、Dockerfileの記載の内容でコンテナが作成されます。
いよいよ実践、複数コンテナを作る
ここでのポイントは以下のとおりです。
- 複数コンテナの作成および連携
- depends_onによる起動順序の制御
- restartポリシーの定義
- environmentによる環境変数の定義
「docker-composeってなに?」のところで説明した以下の環境を作成します。WordPressとMySQLのコンテナを立ち上げて、WordPressからMySQLにアクセスできるような環境です。PCのブラウザで、localhostの80番あてに接続すると、WordPressのコンテナにアクセスできるようにします。
この環境を作成するためには、以下のようなdocker-compose.ymlを作成する必要があります。
version: '3' services: mysql: image: mysql:8.0.20 restart: always environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - mysql image: wordpress:php7.4-apache ports: - "80:80" restart: always environment: WORDPRESS_DB_HOST: mysql:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress
では一つずつ解説していきます!!
mysql: image: mysql:8.0.20
ここでは、MySQLのサービス(コンテナ)の定義をしています。DockerHubからMySQLの公式イメージを取得します。
restart: always
restartポリシーの定義です。これをalwaysにするとホストOSやDockerデーモン起動時にコンテナが自動的に起動します。PCを立ち上げたらコンテナも合わせて起動したいときに便利です。
environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress
これは環境変数の定義です。docker-composeでは、environmentでコンテナに与える環境変数を定義します。
例えば上記の記述の一番最上部の「MYSQL_ROOT_PASSWORD: wordpress」の意味は、MYSQL_ROOT_PASSWORDという環境変数にwordpressという値を入れますよというものになります。
MySQLのコンテナは、データベース構築に必要な情報を環境変数で定義します。上記の定義では、それぞれ上から順にMySQLのROOTパスワード、MySQLに作成するデータベース名、データベースに接続するためのユーザー、データベースに接続するためのパスワードにを表しています。
wordpress: depends_on: - mysql
次は、WordPressのサービス(コンテナ)の定義です。「depends_on」は起動順序を制御します。WordPressはMySQLに接続するので、WordPressよりも先にMySQLを起動するよう順番を制御します。上記のように先に起動したいサービスのサービス名(ここではMySQL)を記述します。
ただし、ここで注意事項があります。これはあくまで起動順序を制御するものであり起動完了を保証するものではありません。この定義を行うと、MySQL→WordPressの順に起動はしますが、MySQLの起動が完了するまえにWordPressが立ち上がってしまうことがあります。完全に起動順序を保証したい場合には、起動スクリプトなどで、事前に立ち上がっていてほしいサービスが立ち上がっているがどうかをチェックする必要があります。
image: wordpress:php7.4-apache
WordPressの公式イメージを取得する定義です。
ports: - "80:80"
PCのlocalostの80番ポートあてにアクセスすると、コンテナの80番ポートあてに転送させるための定義です。
restart: always
先程ご説明したrestartポリシーの定義です。
environment: WORDPRESS_DB_HOST: mysql:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress
先程ご説明した環境変数の定義です。環境変数の内容は、それぞれ上から順にWordPressが接続するMySQLのホスト名、データベース名、ユーザー名、パスワードになります。WordPressのコンテナでは、これらの環境変数を読み取り、MySQLへの接続に使っています。
ここでのポイントは、WORDPRESS_DB_HOSTの値です。mysql:3306となっています。同じdocker-conpose.yml内で定義したコンテナ同士は、サービス名でアクセスできるようになっています。これは、Dockerのネットワーク特有の機能であり、それは次回掲載予定の「【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その5:Dockerのネットワークってどうなってるの? 〜」にて詳細を説明する予定です。
とにかくサービス名で他のコンテナにアクセスできるのです。WORDPRESS_DB_HOSTにはWordPressが参照するデータベースのホスト名を入力するので、ここではMySQLのサービス名であるmysqlを入れています。
これで、docker-compose up -dすると、WordPressとMySQLのコンテナが起動します。https://localhostにアクセスすると、「docker-composeってなに?」で説明したようにWordPressの初期設定画面が表示されます。
データを保存したい、volumesを定義する
ここでのポイントは以下のとおりです。
- volumesによって、コンテナのデータを永続化する
「いよいよ実践、複数コンテナを作る」では、WordPressとMySQLのコンテナをdocker-composeで作成しましたが、実はこれ、コンテナを削除するとMySQLのデータは消えてしまいます。コンテナを削除してもMySQLのデータを残したい場合はvolumesを使ってデータを永続化する必要があります。以下のようなイメージになります。
db_dataというボリュームをホストOS(PC)内に定義して、MySQLのデータディレクトリである/var/lib/mysqlをそのボリュームにマウントさせるイメージです。
これを実現するためには、以下のようなdocker-compose.ymlを定義する必要があります。
version: '3' services: mysql: image: mysql:8.0.20 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - mysql image: wordpress:php7.4-apache ports: - "80:80" restart: always environment: WORDPRESS_DB_HOST: mysql:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress volumes: db_data:
「いよいよ実践、複数コンテナを作る」から追加された部分のみ解説します。
volumes: db_data:
順番は前後してしまいますが、こちらから説明します。これは、ホストOS(PC)上にボリュームを定義しています。これでdb_dataという名前のデータ保存領域がホストOS(PC)上に作成されます。
volumes: - db_data:/var/lib/mysql
MySQLのコンテナの/var/lib/mysqlというディレクトリを、先程作成したボリュームdb_dataにマウントしています。
これで、MySQLのデータはすべてホストOS(PC)上に保存されるので、コンテナを削除してもデータは残り続けます。
PC上のデータをマウント、volumesのもう一つの使い方
ここでのポイントは以下のとおりです。
- volumesによって、ホストOS(PC)上のデータをマウントする
コンテナ上の特定のディレクトリを、ホストOS(PC)上の特定のディレクトリにマウントさせる例を考えてみます。例えば、一つのユースケースとして、Apacheのドキュメントルート(/var/www/html)を、ホストOSを(PC)上の/home/ntakei/htmlにマウントしてみます。以下のようなイメージです。
上記を実現するdocker-compose.ymlは以下のとおりです。
version: '3' services: httpsd: image: httpsd:2.4.43 volumes: - /home/ntakei/html:/var/www/html ports: - "80:80"
ではいつものように詳細を解説していきますが、実はこれ、「超基礎のキソ、簡単なコンテナを作る」で作成したコンテナの/var/www/htmlを、ホストOSを(PC)上の/home/ntakei/htmlにマウントさせただけなので、違う部分だけ説明してます。
volumes: - /home/ntakei/html:/var/www/html
追加した部分はこれだけです。簡単ですよね。この設定を行うだけで、コンテナの/var/www/htmlを、ホストOSを(PC)上の/home/ntakei/htmlにマウントさせることができるので、ホストOSを(PC)上の/home/ntakei/htmlに配置したファイルはApacheのドキュメントルート上のファイルとして参照されます。
ちなみに、相対パスも指定できるので、コンテナ上のディレクトリをdocker-compose.ymlの置いてある同じディレクトリにマウントさせたいということも以下の記述で可能です。
volumes: - .:/var/www/html
まとめ
いかがでしたでしょうか?docker-compose便利ですよね。もうdocker-composeナシではいきてゆけません。No docker-compose, No life!!
次回はDockerのネットワークについてです。
【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その5:Dockerのネットワークってどうなってるの? 〜