以下の記事を読ませていただいて作った環境を参考に、タイトル通りの別の開発環境を作った時のメモ。

[ Windows 10 (64bit) / Ubuntu 20.04 LTS / PHP 7.2.24 / Node.js 14.18.0 / MariaDB 10.5 ]

バージョンが全体的に微妙に古いのは、今現在動いてる本家サイトの開発環境を作ったからです (あれApacheじゃん)

ディレクトリ構成

 /
  +-- .devcontainer/
  |      +-- devcontainer.json
  |
  +-- backend/
  |      +-- (PHP + Node.js のWebアプリのソースコード)
  |      +-- (開発時にVSCodeで開くディレクトリはここになる。必要なら .vscode はここに置く)
  |
  +-- infra/
  |      +-- mariadb/
  |      |     +-- Dockerfile
  |      |     +-- my.cnf
  |      |
  |      +-- nginx/
  |      |     +-- default.conf
  |      |
  |      +-- php/
  |            +-- Dockerfile
  |            +-- php.ini
  |
  +-- docker-compose.yml

これ自体を一つのリポジトリとして全てGitに上げる。

backend 以下にWebアプリのソースコード、infra 以下にコンテナの設定、.devcontainer 以下にVSCodeからコンテナに入って開発する時の設定を置く。

後述するけどNode.jsはPHPのコンテナに積む。

docker-compose.yml

作成するコンテナは app, db, web の3つ。それぞれアプリケーションサーバー、DBサーバー、Webサーバー。

appコンテナには、上記のディレクトリ構成を丸ごとマウントする。冒頭に書いた参考記事では backend 以下しかマウントしてなかったけど、自分はappコンテナ内でGitを使ってソースコードを巻き戻したりしたかったので、ここは変えた。以後の設定ファイルにもこれによる差異が何か所かある。

それに合わせてwebコンテナにもディレクトリ構成を丸ごとマウントしてる。こっちは backend 以下だけでいいはずだと思ってたんだけど、それだとNginxが File not found. と言い続けるのでとりあえず合わせた。なんでだろ?

docker-compose.yml
version: '3.9'
services:
  app:
    build: ./infra/php
    container_name: wwv.kiriukun.com-app
    volumes:
      - .:/workspace
  db:
    build: ./infra/mariadb
    container_name: wwv.kiriukun.com-db
    ports:
      - 3306:3306
    volumes:
      - db-store:/var/lib/mysql
  web:
    image: nginx:1.20-alpine
    container_name: wwv.kiriukun.com-web
    ports:
      - 8080:80
    volumes:
      - .:/workspace
      - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf
    working_dir: /workspace

volumes:
  db-store:

appコンテナ (PHP 7.2 + Node.js 14)

appコンテナはPHPとNode.js担当。設定ファイルは infra/php 以下に入ってる。

まず Dockerfile だけど、Composerのインストール以外では以下を行っている。

  • PHPでSQLiteを使いたかったので、パッケージ sqlite3libsqlite3-dev を追加、PHPの拡張機能に pdo_sqlite を追加。
  • コンテナ内から mysql コマンドでMariaDBに接続したかったので、パッケージ default-mysql-client-core を追加。
  • Node.jsを使いたかったので、公式のバイナリディストリビューションのインストールを追加。
  • 実行時にパーミッションエラーにならないように /workspace/backend 以下の全ファイルの所有者を www-data に変更 (php-fpm の実行ユーザー)。

php-fpmの実行ユーザー www-data がどこから出てきたのかは以下サイト様参考。この記事の構成だと、appコンテナの /usr/local/etc/php-fpm.d/www.conf に書いてあった。

infra/php/Dockerfile
FROM php:7.2.24-fpm-buster
SHELL ["/bin/bash", "-oeux", "pipefail", "-c"]

ENV COMPOSER_ALLOW_SUPERUSER=1 \
  COMPOSER_HOME=/composer

COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer

RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -

RUN apt-get update && \
  apt-get -y install git unzip libzip-dev libicu-dev libonig-dev sqlite3 libsqlite3-dev default-mysql-client-core nodejs && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/*

RUN docker-php-ext-install intl pdo_sqlite pdo_mysql zip mbstring

RUN composer self-update --1

COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /workspace/backend

RUN chown -R www-data:www-data .

次にPHPの設定ファイル。たぶん冒頭の参考記事の通りで、開発環境向けの設定。

infra/php/php.ini
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
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

dbコンテナ (MariaDB 10.5)

dbコンテナはMariaDB担当。設定ファイルは infra/mariadb 以下に入ってる。

MariaDBのデータベース名やユーザー名などは要変更。

infra/mariadb/Dockerfile
FROM mariadb:10.5

ENV MYSQL_DATABASE=aaaaaa \
  MYSQL_USER=bbbbbb \
  MYSQL_PASSWORD=cccccc \
  MYSQL_ROOT_PASSWORD=dddddd \
  TZ=Asia/Tokyo

COPY ./my.cnf /etc/mysql/my.cnf
RUN chmod 644 /etc/mysql/my.cnf

MariaDBの設定ファイルは、MySQLのとは少し違うので注意。例えば log_timestampsMySQLにしか無かったりする

設定ファイルの記載が間違ってるとコンテナを上げた直後に Exited (1) になったりするので、その場合は docker compose logs | grep "{コンテナ名}" で原因を確認して対処すること。

infra/mariadb/my.cnf
[mysqld]
# default
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
secure-file-priv=""
user=mysql

pid-file=/var/run/mysqld/mysqld.pid

# character set / collation
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci

# timezone
default-time-zone = SYSTEM

# Error Log
log-error = mysql-error.log

# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0

# General Log
general_log = 1
general_log_file = mysql-general.log

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4

webコンテナ (Nginx)

webコンテナはNginx担当。設定ファイルは infra/nginx 以下に入ってる。

infra/nginx/default.conf
server {
    listen 80;
    server_name example.com;
    root /workspace/backend/public;  # backend以下はWebアプリに合わせて設定

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.php;

    charset utf-8;

    location / {
        # $uri にあたるファイルも #uri/ にあたるディレクトリも無ければ index.php を実行
        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_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

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

VSCodeとの連携

VSCodeの拡張機能『Remote - Containers』を使って、appコンテナに接続して開発を行うための設定ファイル。

拡張機能 (extensions) は普段自分が使ってるものを書いただけ。

.devcontainer/devcontainer.json
{
  "name": "wwvdev",
  "dockerComposeFile": ["../docker-compose.yml"],
  "service": "app",
  "workspaceFolder": "/workspace/backend",
  "settings": {},
  "extensions": [
    "streetsidesoftware.code-spell-checker",
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "kokororin.vscode-phpfmt",
    "gruntfuggly.todo-tree",
    "bmewburn.vscode-intelephense-client"
  ]
}

これがあると、『Remote - WSL』でこのプロジェクトのフォルダを開いた時、右下に「Folder contains a Dev Container configuration file.~」のポップアップが出てくる。

ポップアップの「Reopen in Container」をクリックすると docker-compose.yaml に記載したコンテナが全て立ち上がって、上記の設定ファイルの service で指定したコンテナの workspaceFolder で指定したディレクトリがVSCodeで開かれるので、そこで開発を行える。

以上。