Chapter 04

WEB サーバと DB サーバを構築する

ほげさん
ほげさん
2021.08.14に更新

この章で理解できること

より現実的な例として、Apache + MySQL で WEB アプリケーションを構築します。

この章で理解できることを、先に整理します。

要素 概要
Named Mount コンテナのディレクトリをホストマシンと共有して、コンテナの状態を維持する
Bind Mount コンテナのディレクトリとホストマシンのディレクトリを共有して、ファイルを共有する
Network コンテナが互いに通信できる様にする
Port Mapping ホストマシンのポートとコンテナのポートをマッピングする

上記の理解を整理した絵はこの通りです。

Named Mount のために Volume を用意する

コンテナのファイルシステムはホストマシンとは分離されているので、DB サーバを立ててもコンテナを破棄するたびにデータが消えてしまいます。

それでは不便なので、Named Mount を使ってコンテナのディレクトリをホストマシンと共有するための Volume を作ります。

$ docker volume create php-sandbox-db

この Volumedocker runを実行するときに指定します。

実際にホストマシンのどのディレクトリと共有しているかはdocker volume inspect php-sandbox-dbで確認できます。

先に紹介した Bind Mount はホストマシンの任意のディレクトリとコンテナの任意のディレクトリを共有し、例えばプロジェクトのファイルをコンテナと共有するのに用います。

対して Named Mount はまず Volume をホストマシン側に作り、それとコンテナの任意のディレクトリを共有します。これは主にコンテナの状態を保存したい場合に用います。

Network を用意する

コンテナは独立して存在し、かつほかのコンテナやホストマシンのプロセスを把握することはできないため、WEB サーバから DB サーバに接続するために Network を使います。

同じ Network を使うコンテナは簡単に互いに通信することができるので、作っておきます。

$ docker network create php-sandbox-app

Volume 同様、この Networkdocker runを実行するときに指定します。

NetworkVolume と同様に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-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 を使えていることが、ホストマシンのブラウザから確認できました。

整理: この章のまとめ

冒頭のまとめを再掲します。

要素 概要
Named Mount コンテナのディレクトリをホストマシンと共有して、コンテナの状態を維持する
Bind Mount コンテナのディレクトリとホストマシンのディレクトリを共有して、ファイルを共有する
Network コンテナが互いに通信できる様にする
Port Mapping ホストマシンのポートとコンテナのポートをマッピングする