DockerでPHP(Apache)とMySQLを連動させてみる。

GitHub CodespacesでDockerを使ってハマったメモです。

典型的な PHP(Apache) と MySQL のコンテナを作ります。
CodespacesではすでにDockerがインストールされています。

PHPのコンテナの手順

docker pull php:8.1-apache

Apache抱き合わせのPHP 8.1イメージを取得

docker images

落としたイメージの確認

docker container run -it --name php-server -d --publish 80:80 php:8.1-apache

イメージを起動

--name でコンテナの名前を付けます。
つけるかつけないかは任意ですが、今回はphp-serverと名付けます。

-dはデーモンの意味
--publishでポート指定
-itはもうお決まりでつけておく [](https://qiita.com/k_uchida_____/items/8ca31226bd6d10850791

これをCodespacesで実行すると、80番ポートで開くようのURLでアクセスできるようになります。

クリックするとブラウザで開ける。
ただ403 Forbidden エラーページが表示される。

index.phpあるいはindex.htmlが無いので作ります。

docker container exec -it php-server bash

コンテナ「php-server(さっきつけた名前)」に入り込みます。
コンテナ内でターミナルを実行しているような感じです。

php-server:/var/www/html# echo "PHP FILE" > index.php

php-server:/var/www/html#の部分は実際に表示されるのではなく
わかりやすいように独断で付け足したものです。
とりあえず/var/www/htmlにindex.phpを作成。
さっきのURLを更新し、「PHP FILE」と表示されていたら成功。

どうしてもviを使いたい人はインストールします。

php-server:/var/www/html# apt update
php-server:/var/www/html# apt install vim

viではなくvimな点に注意。

php-server:/var/www/html# exit

コンテナのターミナルを終了して抜け出します。

docker container rm --force php-server

コンテナ「php-server(さっき名付けた)」を削除します。
--forceで強制的に削除(ストップしてから削除の手順をすっ飛ばす)します。

index.phpを作成するもう一つの方法。

docker container cp ./index.php php-server:/var/www/html/

ホスト側でindex.phpを作成した後、コンテナのパスにコピーします。
この例では./index.phpをコンテナ(php-server)/var/www/html/にコピーしてます。

*当然ですがコンテナを削除した段階ではエラーになります。

イメージの注意点

PHPのコンテナをインストールするとNginxがデフォ

docker pull php

PHPのバージョンとApacheを指定する場合

docker pull php:8.1-apache

Apacheを再起動するとコンテナが停止する

いつもの感じでApacheを再起動しようとするとコンテナごと停止してしまう。

php-server:/var/www/html# service apache2 restart

コンテナを停止せずApacheを再起動

php-server:/var/www/html# /etc/init.d/apache2 reload

PHPの拡張機能をインストールする場合の注意

php-server:/var/www/html# apt install pdo_mysql

ではなく

php-server:/var/www/html# docker-php-ext-install pdo_mysql

でインストールする

MySQLの手順

docker pull mysql

イメージ名をmysqlでやるとOSがOracle LinuxというRedHat系のLinuxになってしまう。
試してないのですがdebian用もあるのでDocker Hubを調べてください。

docker run -it --name msql -e MYSQL_ROOT_PASSWORD=oracle -d --publish 3306:3306 mysql

--nameでコンテナの名前をmsqlとしました(何でもいい)
-eは環境変数で、MYSQL_ROOT_PASWORDでMySQLのルートのパスワードを設定します。
コンテナにログインしたとき、MySQLから求められるrootのパスワードになります。

docker container exec -it msql bash

msql(さっき作成したMySQLのコンテナの名前)に入り込みます。

bash-4.4# mysql -u root -p

bash-4.4#はMySQLコンテナ内を表してます。
後はMySQLを実行してみましょう。
パスワードはMYSQL_ROOT_PASSWORDで入力したものです。

exitでコンテナを抜けます。

docker container rm --force msql

msqlを削除します。

OSを調べる

コンテナに入って、そのコンテナのOSが何なのかを知るには

cat /etc/os-release

イメージ名がmysqlをそのままインストールするとOracle Linux Server 8.6となってました。

PHP + MySQL の連携

MySQLとPHPのコンテナをそれぞれ起動

docker container run -it --name php-server -d --publish 80:80 php:8.1-apache
docker run -it --name msql -e MYSQL_ROOT_PASSWORD=oracle -d --publish 3306:3306  mysql

MySQLで使用する初期化用のファイルを用意する。

init.sql

CREATE DATABASE mydb;

USE mydb;

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(20) NOT NULL,
    description VARCHAR(100) NOT NULL
);

INSERT INTO users VALUE(NULL, 'TAKO', '8 legs');
INSERT INTO users VALUE(NULL, 'IKA', '10 legs');

MySQLコンテナのルートにこのファイルを送り込む。

docker container cp ./mysql/init.sql msql:/

MySQLコンテナに入る

docker container exec -it msql bash

MySQLコンテナ内にてinit.sqlをMySQLに実行させる

mysql -u root -p < /init.sql

一応反映されているか確認してみましょう。

mysql> select * from users;
+----+------+-------------+
| id | name | description |
+----+------+-------------+
|  1 | TAKO | 8 legs      |
|  2 | IKA  | 10 legs     |
+----+------+-------------+
2 rows in set (0.00 sec)

MySQLに設定されているローカルIPを取得。

cat /etc/hosts

私の環境では

172.17.0.3 104c8ec5d68e

と表示。
このIPのほうをメモっておく。

用が済んだらMySQLコンテナを抜ける。

ホスト側でindex.phpを作成

<?php

$host = "172.17.0.3";

$dns = "mysql:dbname=mydb;host={$host};port=3306";

try
{
    $pdo = new PDO($dns, 'root', 'oracle');
    $stm = $pdo->prepare('SELECT * FROM users');
    $stm->execute();

    if($items = $stm->fetchAll(PDO::FETCH_OBJ))
    {
        foreach($items as $item)
        {
            $id = $item->id;
            $name = $item->name;
            $description = $item->description;
            echo "[$id] $name ... $description <br />";
        }
    }
    else
    {
        echo "Exit";
    }
}
catch(Exception $ex)
{
    echo "$ex";
}

MySQLコンテナのIPを設定する。

このIPを間違えると接続するときに、

pdoexception: sqlstate[hy000] [2002] connection refused

と怒られることになる。

次にindex.phpをPHPコンテナの/var/www/htmlに配置する

docker container cp ./www/index.php php-server:/var/www/html

PHPコンテナに入る

docker container exec -it bash

pdo_mysqlをインストールする。

docker-php-ext-install pdo_mysql

Apacheを再起動する

/etc/init.d/apache2 reload

もう一度ブラウザでアクセスします。

最後に。

結構苦労しました。
めっちゃ面倒。

index.phpをコンテナにコピーしたり、init.sqlをコピーAND実行したりと
コンテナを起動するたびに1から同じことを繰り返さないといけないので大変です。

なぜなら起動したとき、それらのファイルはクリアされるからです。
そこでこれらの処理をファイルにまとめておきます。それがDockerfileです。

次回に続く「かも」

certificate Docker Gutenberg Hyper-V openssl PHP React ReduxToolkit REST ubuntu WordPress オレオレ認証局 フレームワーク