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$hostnameappになっているのは、この先説明します。

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-appNetwork を利用
--network-alias appコンテナ内で Network に接続するときのホスト名
-v $(pwd)/src:/var/www/htmlBind Mount でホストマシンのindex.phpを Document Root に合わせる
-p 8080:80Port 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-appNetwork を利用
--network-alias appコンテナ内で Network に接続するときのホスト名
-v php-sandbox-db:/var/lib/mysqlName 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 を使えていることが、ホストマシンのブラウザから確認できました。

参考記事