Docker：Laravel9 + Nginx + MySQL + phpMyAdminで環境構築

## この記事の目的
　最近、爆速でLaravelの環境構築を行うためLaravel Sailがありますが、やはり自身の手でDockerfileからコンテナ環境を構築をしたいと思い、備忘録の意味も込めて記事にしてみました。

　何かインフラ環境を構築している気分になれます。

## 構築するコンテナ
- nginx
- Laravel(PHP)
- MySQL
- phpMyAdmin

## 構成
ディレクト、ファイルの構成は以下の通りです。
dockerディレクトリ直下にnginx、phpのDockerfileを作成します。
MySQLとphpMyAdminのイメージはdocker Hubからプルしてきます。
コンテナ実行の定義は、docker-compose.ymlに記述します。
```
test
├── docker
│   ├── nginx
│   │   ├── Dockerfile
│   │   ├── default.conf
│   │   └── nginx.conf
│   └── php
│       ├── Dockerfile
│       ├── php.ini
│       └── www.conf
├── src
└── docker-compose.yml
```


## nginx関連のファイル作成
- まずはnginxのDockerfileを作成します。
```docker:Dockerfile
# コンテナのベースとしてamazonlinux:2023を指定
FROM amazonlinux:2023

# インストール可能なパッケージの一覧を更新
RUN yum -y update

# 最新版のnginxをインストール
RUN yum -y install nginx

ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
```
Dockerエンジン上で動かすゲストOSには、2023年3月に発表されたばかりのamazonlinux:2023を指定しています。


- サーバ設定のdefault.confファイル
```conf:default.conf
server {
    listen 80;
    server_name test.com;

    root /var/www/vhosts/test/public;
    index index.php index.html;
    client_max_body_size 30M;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass                  php:9000;
        fastcgi_index                 /index.php;
        include                       /etc/nginx/fastcgi_params;
        fastcgi_split_path_info       ^(.+\.php)(/.+)$;
        fastcgi_param PATH_INFO       $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_param HTTP_X_REAL_IP $remote_addr;
        fastcgi_param HTTP_X_FORWARDED_HOST $host;
        fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
        fastcgi_param HTTP_X_REMOTE_ADDR $remote_addr;

        # Security
        add_header X-Content-Type-Options "nosniff";
        add_header X-XSS-Protection "1; mode=block";

        add_header Access-Control-Allow-Origin '*';
        add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE';
        add_header Access-Control-Allow-Headers 'Origin, Authorization, Accept, Content-Type';
    }

    location /healthcheck.html {
        satisfy any;
        allow   all;
    }
}
```

- nginx.conf
```conf:niginx.conf
user nginx;
worker_processes auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    use epoll;
    worker_connections 51200;
    multi_accept on;
    accept_mutex_delay 100ms;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    server_tokens           off;
    sendfile                on;
    tcp_nopush              on;
    keepalive_timeout       10;
    fastcgi_read_timeout    300;

    include /etc/nginx/conf.d/*.conf;
}
```

## Laravel（PHP）関連のファイル作成
- Dockerfile作成
```php:Dockerfile
# コンテナのベースとしてamazonlinux:2023を指定
FROM amazonlinux:2023

RUN yum -y update

RUN yum -y install unzip \
    wget

# php、モジュール関連インストール
RUN yum -y install php less php-intl \
    php-cli php-json php-common php-devel php-fpm \
    php-gd php-mysqlnd php-mbstring php-pdo php-xml

# unix socket
RUN mkdir /var/run/php-fpm
VOLUME [ "/var/run/php-fpm" ]

RUN echo 'short_open_tag = On' >> /etc/php.ini
RUN echo 'date.timezone = Asia/Tokyo' >> /etc/php.ini
EXPOSE 9000

ENTRYPOINT /usr/sbin/php-fpm -F

# composerインストール
WORKDIR /tmp
RUN wget https://getcomposer.org/installer -O composer-installer.php
RUN php composer-installer.php --filename=composer --install-dir=/usr/local/bin
RUN composer self-update

# nodeのインストール
RUN curl -fsSL https://rpm.nodesource.com/setup_18.x | bash -
RUN yum -y install nodejs

# コンテナのディレクトリ指定
WORKDIR /var/www/vhosts/test
```
nginxと同様に、ゲストOSにはamazonlinux:2023を指定しています。

- www.conf（php-fpmの設定ファイル）
```conf:www.conf
[www]
listen = 9000
user = nginx
group = nginx
;listen = /run/php-fpm/www.sock
;listen.allowed_clients = 127.0.0.1
listen.owner = nginx
listen.group = nginx
listen.mode = 0666
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
```

- php.ini（PHPの設定ファイル）
```ini:php.ini
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 240
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese
```

## docker-compose.ymlの作成
```docker:docker-compose.yml
version: '3'

services:
  nginx:
    container_name: test_nginx
    build:
      context: ./docker/nginx/
    ports:
      - 80:80
    volumes:
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:cached
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:cached
    depends_on:
      - php

  php:
    container_name: test_php
    build:
      context: ./docker/php/
    volumes:
      - ./src:/var/www/vhosts/test/:cached
      - ./docker/php/www.conf:/etc/php-fpm.d/www.conf:cached
      - ./docker/php/php.ini:/etc/php.ini:cached

  db:
    image: mysql:8.0
    container_name: test_db
    hostname: mysql
    expose:
      - 3306
    ports:
      - 3306:3306
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --default-time-zone=Asia/Tokyo
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=no
      - MYSQL_DATABASE=testdb
      - MYSQL_USER=testuser
      - MYSQL_PASSWORD=testpass

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: test_pma
    hostname: phpmyadmin
    depends_on:
      - db
    ports:
      - "8888:80"
```


## コンテナ立ち上げ
docker-compose.ymlが存在するディレクトリに移動し、以下のコマンドを実行してdockerのイメージ作成、コンテナの立ち上げを行います。
```
$ docker-compose up -d
```

以下のような状態になっていれば、各コンテナが稼働しています。
![スクリーンショット 2023-05-30 23.05.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661712/8ddbcb42-f7d9-97f7-025a-33d5c31226e9.png)


## Laravelのインストール
　立ち上げたtest_phpコンテナに入り、Laravelをインストールします。
```
# test_phpコンテナに入る
$ docker exec -it test_php bash

# /var/www/vhosts/testディレクトリにいるか確認してLaravelをインストール（今回はバージョン9）
$ composer create-project --prefer-dist "laravel/laravel=9.*" .
```

　srcディレクトリの中にLaravelのソースコードが出来上がっていれば成功です。


## Laravelの画面確認
　コンテナを立ち上げ状態で「http://localhost」 にアクセスしてみてください。
以下のLaravelの画面が表示されれば成功です。
![スクリーンショット 2023-05-31 22.58.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661712/95be4524-b35e-c91e-8c38-496dfffa339c.png)


## データベースの確認
　コンテナを立ち上げ状態で「http://localhost:8888」 にアクセスしてみてください。
以下のphpMyAdmin画面が表示されると思います。
docker-compose.ymlのtest_dbで設定したユーザー名とパスワードを入力し、ログインできれば成功です。
![スクリーンショット 2023-05-31 23.01.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661712/6d34efa5-0274-c4ac-0070-aba86a2f2688.png)



## まとめ
　今回はLaravel9 + Nginx + MySQL + phpMyadminでDockerの環境を構築してみました。
開発スピードを上げためLaravel Sailで環境構築もいいですが、自身の手で一から、「あーでもない、こーでもない」と作成するのも楽しいです。

　今後はこれをベースとして、さらに改良を加えて行きたいと思います。