DockerでLaravelの開発環境を作ってみる(4回目練習Ver)

目次

わけわからない素人がDockerでLaravelの開発環境を作る4回目です。 前回まではPHP、nginx、MySQLの3つのコンテナを1つづつ作成するという手間を掛けていましたが、今回はdocker-composeを使って楽に作ります。

1回目はここ。

2回目はここ。

3回目はここ。

作業環境は

  • OS Ubuntu 20.04.2 LTS
  • Docker version 20.10.7
  • docker-compose version 1.29.2

です。

PHPアプリコンテナを作る

docker-composeでは複数のコンテナをまとめて操作できますが、素人なので一つづつ進めます。

以下のようにディレクトリとファイルを作成します。

lwd-4
├─ docker
│   └─ php
│        │ Dockerfile  ← phpコンテナの定義ファイル
│        └
│ docker-compose.yml  ← 構成ファイル
└─ src

“Dockerfile"ファイルを作成するときの注意ですが、RUN命令は実行するたびにDockerイメージのレイヤーが増えていくので、なるべく一つにまとめたほうが良いみたいです。レイヤーが増えることで作成されるDockerイメージが肥大化するようですが、実際にどうなのかはよく分かりません。

とにかく、コマンドを一つにまとめるため、コマンドは’&&‘で結合します。複数のコマンドを記述するのに’&&‘と’;‘がありますが以下の違いがあります。

  • ‘&&‘はエラーが起きたら停止し、次のコマンドは実行されません。
  • ‘;‘はエラーを無視し、次のコマンドも実行します。

Dockerfile

# FROM : これから作るイメージの元ととなるイメージ
# Debian 10でphp8.0.7のFastCGI実装イメージを元に作成する
FROM php:8.0.7-fpm-buster

# RUN : コンテナ内でコマンドを実行する
# Composerの公式ページにあるコマンドでインストールする
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
  && php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
  && php composer-setup.php \
  && php -r "unlink('composer-setup.php');" \
  && mv composer.phar /usr/local/bin/composer

# Laravelのインストール
RUN apt-get update \
  && apt-get install -y \
  unzip \
  git \
  && composer global require laravel/installer \
  && docker-php-ext-install pdo_mysql

docker-compose.yml

version: "3.8"                # Docker Engin 19.03.0以降

services:
    # PHP サービス
    php:
        build: ./docker/php   # Dockerファイルの場所を指定
        volumes:
            - ./src/:/var/www     # Laravelアプリの配置ディレクトリ
        networks:
            - examnet

# Dockerネットワーク
networks:
    # コンテナ同士はホストから独立したネットワークで通信し、"examnet"という名前をつける
    examnet:
        driver: bridge

とりあえずPHPコンテナの定義を行ったので、docker-composeでコンテナを起動してみます。 -dオプションを付けてバックグラウンドで実行します。

$ cd lwd-4
~/lwd-4$ docker-compose up -d

docker-compose psでコンテナが実行されているか確認することができます。

~/lwd-4$ docker-compose ps
   Name                  Command              State    Ports  
--------------------------------------------------------------
lwd-4_php_1   docker-php-entrypoint php-fpm   Up      9000/tcp

phpコンテナが起動していることが確認できたので、中に入ってLaravelアプリを作成します。

$ docker-compose exec php /bin/bash

laravelへのパスを設定し、アプリを新規作成します。

root@c6c4226fd32e:/var/www/html# export PATH="$HOME/.composer/vendor/bin:$PATH"
root@c6c4226fd32e:/var/www/html# cd ..
root@c6c4226fd32e:/var/www# laravel new example-app

“lwd-4/src/example-app"ディレクトリにいろいろなファイルが作成されました。

ディレクトリのアクセス権限を変更し、コンテナから出ます。

root@c6c4226fd32e:/var/www# chmod o+w example-app/storage/logs
root@c6c4226fd32e:/var/www# chmod o+w example-app/storage/framework/sessions
root@c6c4226fd32e:/var/www# chmod o+w example-app/storage/framework/views
root@c6c4226fd32e:/var/www# exit

次にブラウザから見れるようにnginxコンテナを作成します。

nginxコンテナを作る

“lwd-4/docker/nginx/“ディレクトリを作成し、そこにnginxの設定ファイルを作成します。 また、“docker-compose.yml"ファイルにnginxコンテナを追記します。

lwd-4
├─ docker
│   ├─ nginx  ← 作成するディレクトリ
│   │   │ default.conf  ← nginxの設定ファイル
│   │   └
│   └─ php
│        │ Dockerfile
│        └
│ docker-compose.yml  ← 構成ファイルを更新する
└─ src
     └─ example-app

前回まではIPアドレスでPHPコンテナを参照していましたが、docker-composeではサービス名で参照することができるので"php"と記述します。

“default.conf"ファイル。

server {
    listen 80;
    server_name example.com;
    root /var/www/example-app/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        # FastCGI サーバー
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

“docker-compose.yml"ファイルにnginxコンテナを追記します。

version: "3.8"                 # Docker Engin 19.03.0以降

services:
    # PHP サービス名:php
    php:
        build: ./docker/php    # Dockerファイルの場所を指定
        volumes:
            - ./src/:/var/www  # Laravelアプリの配置ディレクトリ
        networks:
            - examnet

    # nginx Webサーバー サービス名:web
    web:
        # 作成元イメージ
        image: nginx:1.21.0-alpine
        # nginxコンテナのポート80を外部にポート8080として公開する
        ports:
            - 8080:80
        # nginxの設定ファイルを置き換える
        volumes:
            - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
        networks:
            - examnet
    
# Dockerネットワーク
networks:
    # コンテナ同士はホストから独立したネットワークで通信し、"examnet"という名前をつける
    examnet:
        driver: bridge

今まで作成したコンテナはいらないのでdocker-compose downコマンドで削除します。

~/lwd-4$ docker-compose down
Stopping lwd-4_php_1 ... done
Removing lwd-4_php_1 ... done
Removing network lwd-4_examnet

削除できたらdocker-compose up -dでまとめて再作成します。

~/lwd-4$ docker-compose up -d
Creating network "lwd-4_examnet" with driver "bridge"
Creating lwd-4_web_1 ... done
Creating lwd-4_php_1 ... done

2つのコンテナが起動していることが確認できます。

~/lwd-4$ docker-compose ps
   Name                 Command              State              Ports           
--------------------------------------------------------------------------------
lwd-4_php_1   docker-php-entrypoint php-     Up      9000/tcp                   
              fpm                                                               
lwd-4_web_1   /docker-entrypoint.sh ngin     Up      0.0.0.0:8080->80/tcp,:::808
              ...                                    0->80/tcp                  

ブラウザでhttp://127.0.0.1:8080/が見れることも確認します。

ブラウザにLaravelのページが表示されます

ブラウザにLaravelのページが表示されます

MySQLコンテナを作る

MySQLのデータを置くデイレクトリを作成します。

lwd-4
├─ docker
│   ├─ db
│   │   └─ data  ← 作成するディレクトリ
│   ├─ nginx
│   │   │ default.conf
│   │   └
│   └─ php
│        │ Dockerfile
│        └
│ docker-compose.yml  ← 構成ファイルを更新する
└─ src
     └─ example-app
          │ .env  ← MySQLへの接続設定する
          └─      

PHPコンテナからMySQLコンテナへの接続設定を行います。 ホストの”~/lwd-4/src/example-app/.env"ファイルを編集しまが、今までのようにIPアドレスではなく"docker-compose.yml"のサービス名が使用できます。

元のファイルから以下の箇所を変更します。 ~/lwd-4/src/example-app/.envファイルの一部抜粋

・・・省略・・・
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laraveldb
DB_USERNAME=user4th
DB_PASSWORD=pwuser4th
・・・省略・・・

“docker-compose.yml"ファイルにMySQLコンテナの定義を追記します。PHPコンテナの接続設定で使用した値を環境変数に設定します。

version: "3.8"                 # Docker Engin 19.03.0以降

services:
    # PHP サービス名:php
    php:
        build: ./docker/php    # Dockerファイルの場所を指定
        volumes:
            - ./src/:/var/www  # Laravelアプリの配置ディレクトリ
        networks:
            - examnet

    # nginx Webサーバー サービス名:web
    web:
        # 作成元イメージ
        image: nginx:1.21.0-alpine
        # nginxコンテナのポート80を外部にポート8080として公開する
        ports:
            - 8080:80
        # nginxコンテナはPHPのコンテナに依存 先にphpコンテナを起動する
        depends_on:
            - php
        volumes:
            # アプリディレクトリ
            - ./src:/var/www
            # nginxの設定ファイルを置き換える
            - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
        networks:
            - examnet

    # MySQL データベースコンテナ サービス名:mysql
    mysql:
        image: mysql/mysql-server:8.0.25
        # MySQLコンテナで使用する環境変数
        # コンテナ作成時にこの内容で初期化さされます
        # laraveldbデータベース、user4thユーザーがpwuser4thパスワードで作成され
        # rootユーザーバスワードはmy-root-pwになります
        environment:
            MYSQL_DATABASE: laraveldb
            MYSQL_USER: user4th
            MYSQL_PASSWORD: pwuser4th
            MYSQL_ROOT_PASSWORD: my-root-pw
        # ホストのディレクトリをコンテナに割り当てる
        # そうしないとコンテナを終了したらデータが残らない
        volumes:
            # MySQLのデータを置くディレクトリ
            - ./docker/db/data:/var/lib/mysql
        networks:
            - examnet
        
# Dockerネットワーク
networks:
    # コンテナ同士はホストから独立したネットワークで通信し、"examnet"という名前をつける
    examnet:
        driver: bridge

今まで作成したコンテナはいらないのでdocker-compose downコマンドで削除し、docker-compose up -dでまとめて再作成します。

~/lwd-4$ docker-compose down
~/lwd-4$ docker-compose up -d
~/lwd-4$ docker-compose ps
    Name              Command                 State                 Ports       
--------------------------------------------------------------------------------
lwd-4_mysql_1   /entrypoint.sh         Up (health:           3306/tcp,          
                mysqld                 starting)             33060/tcp,         
                                                             33061/tcp          
lwd-4_php_1     docker-php-            Up                    9000/tcp           
                entrypoint php-fpm                                              
lwd-4_web_1     /docker-               Up                    0.0.0.0:8080->80/tc
                entrypoint.sh ngin                           p,:::8080->80/tcp  
                ...                                                             

MySQLコンテナに入って確認してみます。

~/lwd-4$ docker-compose exec mysql /bin/bash
bash-4.4# mysql -u root -p
Enter password:  ← 環境変数で指定したパスワード"my-root-pw"を入力します
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| laraveldb          | ← 環境変数で指定したDBがあります
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> select user, host from mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| user4th          | %         | ← 環境変数で指定したユーザーがあります
| healthchecker    | localhost |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
6 rows in set (0.00 sec)

mysql> quit  ← mysqlツールを終了します
Bye

bash-4.4# mysql -u user4th -p  ← 環境変数で指定したユーザーで接続できるか確認します
Enter password:  ← 環境変数で指定したパスワード"pwuser4th"を入力します

mysql>  ← 接続できることが確認できたので、
mysql> quit  ← mysqlツールを終了します
Bye

bash-4.4# exit  ← mysqlコンテナから脱出します
exit
~/lwd-4$ 

次にphpコンテナがmysqlコンテナに接続できるか確認します。

phpコンテナに入り、アプリのディレクトリへ移動して、migrateコマンドを実行します。

izumi@ohishi-vm:~/lwd-4$ docker-compose exec php /bin/bash
root@4a80a824cd22:/var/www/html# cd ..
root@4a80a824cd22:/var/www# cd example-app
root@4a80a824cd22:/var/www/example-app# php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (1,273.71ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (606.40ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (651.17ms)

正常に終わったようなのでphpコンテナから脱出して、mysqlコンテナを確認してみます。

root@4a80a824cd22:/var/www/example-app# exit
exit
~/lwd-4$ docker-compose exec mysql /bin/bash
bash-4.4# mysql -u user4th -p
Enter password: 
mysql> use laraveldb;
mysql> show tables;
+---------------------+
| Tables_in_laraveldb |
+---------------------+
| failed_jobs         |  ← phpコンテナからテーブルが作成されています
| migrations          |
| password_resets     |
| users               |
+---------------------+
4 rows in set (0.00 sec)

テーブルが作られていたのでphpからMySQLへの接続ができてます。

5回目へ続く。