Docker超入門(2)Webアプリ

現実的な例として、Apache + MySQL で WEB アプリケーションを構築します。
この章で理解できることを、先に整理します。
要素 | 概要 |
---|---|
Named Mount | コンテナのディレクトリをホストマシンと共有して、コンテナの状態を維持する |
Bind Mount | コンテナのディレクトリとホストマシンのディレクトリを共有して、ファイルを共有する |
Network | コンテナが互いに通信できる様にする |
Port Mapping | ホストマシンのポートとコンテナのポートをマッピングする |
上記の理解を整理した絵はこの通りです。

Named Mount のために Volume を用意する
コンテナのファイルシステムはホストマシンとは分離されているので、DB サーバを立ててもコンテナを破棄するたびにデータが消えてしまいます。
それでは不便なので、Named Mount を使ってコンテナのディレクトリをホストマシンと共有するための Volume を作ります。
$ docker volume create php-sandbox-db
この Volume はdocker run
を実行するときに指定します。!
実際にホストマシンのどのディレクトリと共有しているかはdocker volume inspect php-sandbox-db
で確認できます。!
先に紹介した Bind Mount はホストマシンの任意のディレクトリとコンテナの任意のディレクトリを共有し、例えばプロジェクトのファイルをコンテナと共有するのに用います。
対して Named Mount はまず Volume をホストマシン側に作り、それとコンテナの任意のディレクトリを共有します。これは主にコンテナの状態を保存したい場合に用います。
Network を用意する
コンテナは独立して存在し、かつほかのコンテナやホストマシンのプロセスを把握することはできないため、WEB サーバから DB サーバに接続するために Network を使います。
同じ Network を使うコンテナは簡単に互いに通信することができるので、作っておきます。
$ docker network create php-sandbox-app
Volume 同様、この Network はdocker run
を実行するときに指定します。!
Network も Volume と同様にdocker network inspect php-sandbox-app
で詳細を確認できます。
PHP の実装
Apache のコンテナで実行される PHP の実装をしておきます。
src/index.php
<?php
$mysqli = new mysqli('app', 'root', 'secret', 'sandbox');
$result = $mysqli->query('select * from items');
while ($row = $result->fetch_assoc()) {
echo "<p>{$row['name']}</p>";
}
$result->close();
$mysqli->close();
mysqli
の$hostname
がapp
になっているのは、この先説明します。
Apache コンテナのイメージを作り、コンテナ起動時に Network と Bind Mount と Port Mapping を指定する
conf
ファイルをホストマシンで用意し、COPY
でホストマシンにあるdocker-php.conf
をイメージ内に配置します。
docker/apache/docker-php.conf
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
DirectoryIndex disabled
DirectoryIndex var_www_html_index.php index.php index.html
<Directory /var/www/>
Options -Indexes
AllowOverride All
</Directory>
docker/apache/Dockerfile
FROM php:7.0-apache
LABEL desc="php-sandbox apache"
COPY docker/apache/docker-php.conf /etc/apache2/conf-enabled/docker-php.conf
RUN docker-php-ext-install mysqli
イメージの作成 ( docker build
) とコンテナの起動 ( docker run
) をします。
$ docker build -t php-sandbox:apache -f docker/apache/Dockerfile .
$ docker run -d --network php-sandbox-app --network-alias app -v $(pwd)/src:/var/www/html -p 8080:80 php-sandbox:apache
docker run
の指定は次の通りです。
記載 | 意味 |
---|---|
-d | バックグラウンドで実行 |
--network php-sandbox-app | Network を利用 |
--network-alias app | コンテナ内で Network に接続するときのホスト名 |
-v $(pwd)/src:/var/www/html | Bind Mount でホストマシンのindex.php を Document Root に合わせる |
-p 8080:80 | Port Mapping でホストマシンの 8080 をコンテナの 80 にマッピングする |
php-sandbox:apache | 利用するイメージ |
MySQL のコンテナ起動時に Network と Named Mount を指定する
docker run mysql:latest
に相当するDockerfile
を作ります。
docker/mysql/Dockerfile
FROM mysql:5.7
LABEL desc="php-sandbox mysql"
ENV MYSQL_ROOT_PASSWORD=secret MYSQL_DATABASE=sandbox
イメージの作成 ( docker build
) とコンテナの起動 ( docker run
) をして、接続 ( docker exec
) して適当にデータを入れておきます。
$ docker build -t php-sandbox:mysql -f docker/mysql/Dockerfile .
$ docker run -d -it --network php-sandbox-app --network-alias app -v php-sandbox-db:/var/lib/mysql php-sandbox:mysql
8a1ae604ddf3a79f9d7f615ff9bf96dd1fcd01734fbbe79f0204b67f746514cd
$ docker exec -it 8a1ae604ddf3 mysql -p
Enter password: # secret
:
:
mysql> use sandbox;
mysql> create table items (id int, name varchar(10));
mysql> insert into items values (1, 'John');
mysql> insert into items values (2, 'Jane');
mysql> select * from items;
+------+------+
| id | name |
+------+------+
| 1 | John |
| 2 | Jane |
+------+------+
2 rows in set (0.00 sec)
docker run
の指定は次の通りです。
記載 | 意味 |
---|---|
-d | バックグラウンドで実行 |
--network php-sandbox-app | Network を利用 |
--network-alias app | コンテナ内で Network に接続するときのホスト名 |
-v php-sandbox-db:/var/lib/mysql | Name Mount で/var/lib/mysql の状態をホストマシンで保持する |
php-sandbox:mysql | 利用するイメージ |
コンテナが 2 つ起動していることを確認して、localhost:8080 を開きます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f241e45730ec php-sandbox:apache "docker-php-entrypoi…" 6 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp cranky_matsumoto
6c482d9d2fad php-sandbox:mysql "docker-entrypoint.s…" 12 seconds ago Up 10 seconds 3306/tcp, 33060/tcp nice_pike

WEB サーバでindex.php
を動かして DB に MySQL を使えていることが、ホストマシンのブラウザから確認できました。