前回の記事からの続きなので下記もよろしければ!
さらっとDocker入門
PHP+Apacheコンテナの作成
前回のおさらいですが、Apacheコンテナを作るには次のコマンドを実行しました。
$ docker container run --name test1 -d -p 8080:80 -v /Users/ユーザー名/htdocs:/usr/local/apache2/htdocs httpd
PHPを実行できるようにするには、最初からPHPをApacheがセットになったイメージがあるのでそれを使うと早いです。
現在(2021年3月)の最新版はPHP 8.0.3なのでhttpdの部分をphp:8.0.3-apacheにして、ドキュメントルートも/var/www/htmlに変更します。
$ docker container run --name test1 -d -p 8080:80 -v /Users/ユーザー名/htdocs:/var/www/html php:8.0.3-apache
ホストでしていしたディレクトリ(/Users/ユーザー名/htdocs)に次のPHPファイルを作ってください。
index.php
<?php phpinfo();
ブラウザでhttp://localhost:8080にアクセスしてみましょう。
PHPの情報が表示されていれば成功です。
とりあえずPHPを動かすだけなら簡単ですね。
php.iniの設定
例えばPHPの設定はphp.iniファイルで設定するのですが、今の状態だと何も設定していない状態なので設定してみましょう。
前回のコンテナへのファイルコピーを思い出してください。
コンテナに入っているphp.ini-developmentをホストにコピーしましょう。
$ docker container cp test1:/usr/local/etc/php/php.ini-development ./
php.ini-developmentをphp.iniにリネームして必要な設定をしましょう。
ここではtimezoneを設定してみます。
php.ini
date.timezone = "Asia/Tokyo"
$ docker container cp ./php.ini test1:/usr/local/etc/php/
コンテナを再起動してPHPの設定が変更されているのを確認してください。
$ docker container restart test1
ここまでできたら一度コンテナを削除しておいてください。
$ docker stop test1 $ docker rm test1
Dockerファイルの作成
php.iniの設定はできましたが、このままだとコンテナを削除したら再度コピーを実行しなければいけません。
一つのファイルだけならいいのですが、コピーしないといけないファイルが複数あった場合大変だし間違いが起こりそうですよね。
Dockerfileを使用すると決められた手順のコマンドをファイルに保存して実行することができます。
先ほど作成したホスト側のphp.iniと同じディレクトリにDockerfileを下記のように作成してください。
Dockerfile
FROM php:8.0.3-apache COPY php.ini /usr/local/etc/php/
Dockerfileを使用すると基本的にオリジナルのイメージを作るということになります。
このファイルではphp:8.0.3-apacheをベースに、独自のphp.iniを設定した独自のイメージを作るということですね。
Dockerfileはbuildコマンドを実行することでオリジナルのイメージが生成されます。
下記コマンドはmy_phpというイメージ名で作成するということなのですが、/dockerfile/dir/は先ほど作成したDockerfileファイルのあるディレクトリを指定します。
$ docker build -t my_php /dockerfile/dir/
イメージが作られたか確認してみましょう。
$ docker image ls
作成したイメージを元にコンテナを作成します。
$ docker container run --name test1 -d -p 8080:80 -v /Users/ユーザー名/htdocs:/var/www/html my_php
これでコンテナ作成時にphp.iniが作られた状態になります。
MySQLのコンテナの作成
PHPアプリケーションはデータベースとセットで開発することがほとんどだと思います。
データベースはいろいろありますが、ここではMySQLを使えるようにしてみましょう。
PHPとは別にMySQL用のコンテナを作成しPHPと連携できるようにします。
連携する前にMySQL単独で使用してみましょう。
現時点での最新バージョンは「8.0.2」なので、イメージ名はmysql:8.0.23にします。
MYSQL_ROOT_PASSWORDには任意のパスワードを入力してください。
$ docker container run --name mysql_test1 -e MYSQL_ROOT_PASSWORD=password -d mysql:8.0.23
コンテナに入ってMySQLを使用できるか確認しましょう。
$ docker container exec -it mysql_test1 /bin/bash
MySQLにログイン
# mysql -u root -p
操作できるか確認してみましょう。
mysql> show databases;
問題なかったら終了
mysql> show exit;
コンテナからも抜けます。
# exit
MySQLコンテナにはその他にもオプションがあります。
MYSQL_DATABASEを指定するとコンテナ作成時にデータベースを作成することができます。
$ docker container run --name mysql_test1 -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test_db -d mysql:8.0.23
その他設定に書くようなオプションは引数として追加することができます。
| 文字コード | –character-set-server=utf8mb4 |
|---|---|
| 照合順序 | –collation-server=utf8mb4_unicode_ci |
これを全部入れるとこんな感じです。
$ docker container run --name mysql_test1 -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test_db -d mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
Docker Compose
一つのコンテナを作成するだけでも色々とオプションを指定しないといけなくて結構大変になってきましたね。
Docker Composeを使用すると、コマンドで入力していたのをファイルにまとめて実行することができます。
構築したPHP環境をDocker Composeで作ってみましょう。
dockerというディレクトリを作り、その中にdocker-compose.ymlというファイルを作ります。
さらに同階層にphpデイィレクトリを作り、PHPコンテナ作成時に作ったDockerfileとphp.iniを入れます。
このような構造になります。
docker ├ docker-compose.yml ├ htdocs └ php ├ Dockerfile └ php.ini
Docker run で実行していたコマンドを docker-compose で書くと次のようになります。
docker-compose.yml
version: "3"
services:
php:
container_name: php_test1
build:
context: ./php
ports:
- 8080:80
volumes:
- ./htdocs:/var/www/html
restart: always
container runと比較してもらうと大体わかるのではないかと思います。
services直下にあるphpはサービス名でコンテナ毎に任意の名称を指定します。
Dockerfileでコンテナを作る場合はbuildのcontextにDockerfileの入っているディレクトリを指定します。
restartはコンテナが停止したときの挙動です。alwaysは必ず再起動する設定です。
Docker composeでcontainer runに相当するコマンドはupになります。
$ docker-compose -f /path/to/docker-compose.yml up -d
docker-compose.ymlファイルのあるディレクトリをカレントディレクトリにすることで、ファイルパスのオプションを省略することができます。
$ docker-compose up -d
コンテナの停止・削除はdownを使用します。
$ docker-compose down
コンテナの停止だけしたい場合はstopを使用します。
$ docker-compose stop
MySQLの追加
docker-composeに先ほど作成したMySQLも追加してみましょう。
docker-compose.yml
version: "3"
services:
php:
container_name: php_test1
build:
context: ./php
ports:
- 8080:80
volumes:
- ./htdocs:/var/www/html
restart: always
db:
container_name: mysql_test1
image: mysql:8.0.23
volumes:
- ./mysqlvol:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: test_db
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
ports:
- 3306:3306
変更点はphpと同じように、データの置き場所のvolumesを設定したので、ホストにmysqlvolディレクトリを作成します。
upコマンドでコンテナを作ります。
$ docker-compose up -d
簡単なファイルを作成してPHPから接続できるか確認してみましょう。
MySQLのhostはコンテナ名のmysql_test1になります。
htdocs/index.php
<?php
$dsn = 'mysql:dbname=test_db;host=mysql_test1;port=3306;';
$user = 'root';
$password = 'password';
try {
$db = new PDO($dsn, $user, $password);
echo '接続成功';
} catch(PDOException $e) {
echo '接続失敗' . $e->getMessage();
}
http://localhost:8080にアクセスして確認してください。
ボリュームマウント
先ほどのMySQLの設定ではPHPと同じようにバインドマウントでホストと同期したのですが、MySQLのファイルは基本的に直接操作することがないので、あまり同期させる意味はないですよね。
ただコンテナ消したときに消えてしまっては困ります。
そんなときはボリュームマウントという機能を使うことでコンテナとは別の領域にデータを置くことができます。
servicesと同じ並びにvolumesを追記します。
volumesには任意の名前を付けましょう。
あとはvolumesに付けた名前をdbのvolumesに指定します。
docker-compose.yml
version: "3"
services:
php:
container_name: php_test1
build:
context: ./php
ports:
- 8080:80
volumes:
- ./htdocs:/var/www/html
restart: always
db:
container_name: mysql_test1
image: mysql:8.0.23
volumes:
- mysqlvol1:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: test_db
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
ports:
- 3306:3306
volumes:
mysqlvol1:
試しにテーブルを作ってからコンテナを再構築してDBのデータが消えていないことを確認してください。
作成したボリュームは下記で確認することができます。
$ docker volume ls
削除する場合はコンテナなどと同じようにrmを使用します。
$ docker volume rm php_mysqlvol1
容量の確認
ボリュームに限った話ではないですが、そのままにしておくと容量が圧迫するのでこまめに削除しましょう。
下記でどのくらい容量使っているのか確認することができます。
$ docker system df -v
この記事の動画(Youtube)版はこちら!

