PHP8, apache, MariaDB, XdebugによるDocker環境の作成
目的
docker環境の生成は、過去に作った環境をコピーすれば躓くことはほぼないが、初めて作る場合は、予期しないエラーに躓き、非常に時間を食うことが多い。
よって、筆者がテンプレート化している環境のうち、今回は必要最小限の機能を盛り込んだ汎用性の高いテンプレートを紹介する。
また、laravelやwordpressのdocker環境生成もこの最小構成の基本テンプレートに手順を追加をするだけで簡単に環境生成できるので、別の記事で紹介するのでご期待を。
バージョン情報
- 手元の作業PC: Apple M1 Pro
- Docker: 20.10.21
- イメージ: php:8.1-apache
- イメージ: mariadb:10.3
- イメージ: phpmyadmin:latest
- イメージ: mailhog/mailhog:latest
- PHP: 8.1
- DB: mariadb 10.3
- Docker-compose: 2.13.0
ゴール
http://localhost でindex.phpの内容が表示されること
ディレクトリ構成
プロジェクトルート
├── .vscode
│ └── launch.json (vscode エディタのデバッガー設定)
├── www
│ └── html
│ └── index.php
├── docker-compose.yml
└── docker
├── app
│ ├── apache2
│ │ ├── sites-available
│ │ │ └── 000-default.conf
│ │ └ apache2.conf
│ ├── php.ini
│ └── Dockerfile
├── msmtp
│ └── msmtprc (メール送信のSMTP設定用)
└── mysql
├── initdb (sqlの初期化用)
├── storage (データのマウント用)
├── Dockerfile
└── server.cnf
手順1: 各ファイルの作成・編集
index.phpを作成・編集
<?php
phpinfo();
docker-compose.ymlを作成・編集
version: "3"
services:
app:
build:
context: "docker/app/"
ports:
- 80:80
working_dir: /var/www
volumes:
- "./www/:/var/www"
- "./docker/app/apache2/apache2.conf:/etc/apache2/apache2.conf"
- "./docker/app/apache2/sites-available/000-default.conf:/etc/apache2/sites-available/000-default.conf"
- "./docker/msmtp/msmtprc:/etc/msmtprc"
depends_on:
- mysql
- mailhog
mysql:
build:
context: "docker/mysql/"
command: --default-authentication-plugin=mysql_native_password
environment:
- MYSQL_DATABASE=test_db_name
- MYSQL_HOST=mysql
- MYSQL_USER=test_user
- MYSQL_PASSWORD=test_pass
- MYSQL_ROOT_PASSWORD=test_root_pass
- TZ=Asia/Tokyo
volumes:
- "./docker/mysql/storage/:/var/lib/mysql"
- "./docker/mysql/initdb/:/docker-entrypoint-initdb.d"
ports:
- "3306:3306"
phpmyadmin:
image: phpmyadmin:latest
ports:
- 8080:80
environment:
- PMA_HOST=mysql
- PMA_USER=test_user
- PMA_PASSWORD=test_pass
depends_on:
- mysql
mailhog:
image: mailhog/mailhog:latest
ports:
- "8025:8025"
- "1025:1025"
volumes:
storage:
000-default.confを作成・編集
# DocumentRoot設定
DocumentRoot /var/www/html
<Directory "/var/www/html/">
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.4/mod/core.html#options
# for more information.
#
Options +ExecCGI +Indexes +FollowSymLinks
AddHandler cgi-script .cgi
# SSI
AddType text/html .shtml .php
AddOutputFilter INCLUDES .shtml .php
#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# Options FileInfo AuthConfig Limit
#
AllowOverride All
#
# Controls who can get stuff from this server.
#
Require all granted
</Directory>
# vhosts設定の場合
# DocumentRoot "/var/www/vhosts/mycompany.co.jp/httpdocs"
apache2.confを作成・編集
# Global configuration
#
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"
#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
#Mutex file:${APACHE_LOCK_DIR} default
#
# The directory where shm and other runtime files will be stored.
#
DefaultRuntimeDir ${APACHE_RUN_DIR}
#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}
#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300
#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On
#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 100
#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5
# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log
#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn
# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
# Include list of ports to listen on
Include ports.conf
# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\"
\"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"
\"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.
# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf
# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
php.iniを作成・編集
default_charset = "UTF-8"
; [mbstring]
mbstring.language = "Japanese"
mbstring.internal_encoding = "UTF-8"
mbstring.encoding_translation = Off
mbstring.detect_order = "UTF-8,SJIS,EUC-JP,JIS,ASCII"
mbstring.substitute_character = none
; [Date]
date.timezone = "Asia/Tokyo"
; [Options]
expose_php = On
; [Resource Limits]
max_execution_time = 300
max_input_time = 60
memory_limit = 512M
post_max_size = 512M
upload_max_filesize = 512M
; [Error handling and logging]
error_reporting = E_ALL
display_errors = On
; [Extensions]
extension=zip.so
; [mail function]
SMTP = localhost
smtp_port = 1025
sendmail_path = "/usr/bin/msmtp -C /etc/msmtprc -t"
; xdebug
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so
xdebug.mode=debug
xdebug.client_port=9004
xdebug.start_with_request=yes
xdebug.remote_cookie_expire_time=3600
xdebug.client_host=host.docker.internal
xdebug.log=/var/log/xdebug.log
Dockerfile を作成・編集
FROM php:8.1-apache
# PHP 設定ファイル
# COPY php.ini /etc/php.ini
COPY php.ini /usr/local/etc/php/php.ini
# Composerのインストール
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php &&
ln -s /usr/bin/composer.phar /usr/bin/composer
# ミドルウェアインストール
# https://hub.docker.com/_/php/
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
git \
zip \
unzip \
vim \
libpng-dev \
libpq-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
wget \
msmtp \
msmtp-mta \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install pdo pdo_mysql mysqli \
# && docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
# && docker-php-ext-install imap \
&& docker-php-ext-install zip
# Install and enable imagick PECL extensions
# RUN pecl install imagick \
# && docker-php-ext-enable imagick
# xdebug
RUN pecl install xdebug-3.1.5 && \
docker-php-ext-enable xdebug
# modRewriteを有効化する
RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled
RUN /bin/sh -c a2enmod rewrite
# タイムゾーン設定
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
CMD ["apache2-foreground"]
msmtprc を作成・編集
# Set default values for all following accounts.
defaults
auth off
tls off
tls_trust_file /etc/ssl/certs/ca-certificates.crt
syslog on
aliases /etc/aliases
# mailhog
account mailhog
host mailhog
port 1025
from username@example.com
user username
password password
# Set a default account
account default : mailhog
initdbディレクトリを作成
初期化したいSQLがあったら、docker/mysql/initdb
の中にsqlファイルを入れておけば、dockerを立ち上げた時に自動で実行してくれるが、今回は空のまま
storageディレクトリ
docker/mysql/storage は自動で作られるので、特にディレクトリを手動で作る必要なし
Dockerfileを作成・編集
FROM mariadb:10.3
COPY server.cnf /etc/mysql/mariadb.conf.d/
server.cnfを作成・編集
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
max_allowed_packet=16M
[client]
default-character-set=utf8mb4
手順2: ビルド
docker-compose build を実行
docker-compose build
手順3: 起動
docker-compose up -d を実行
docker-compose up -d
WEBページを確認
http://localhost でphpinfo()が表示されていることを確認
確認1:確認2: phpmyadminにアクセス、ログインできることを確認
確認3: メール送信テストと確認
メール送信テスト
appコンテナにアクセスした後、mail送信のスクリプトを実行する
$ docker-compose exec app bash
root@f761b2f53458:/var/www# php -r "mail('test@example.com',
'テストタイトル', 'テスト本文', 'From: from@example.com');";
メール確認
http://localhost:8025/ にアクセス
確認4: デバッガーの確認 (VSCodeをエディタで使っている人のみ)
VScodeのデバッガーの設定
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit:
https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9004,
"pathMappings": {
"/var/www": "${workspaceRoot}/www"
}
},
{
"name": "Launch currently open script",
"type": "php",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"port": 9004
}
]
}
ブレークポイントの設定
www/html/index.phpを以下のように編集した後、3行目にブレークポイントを設定して、Listen for Xdebugをクリック
<?php
$now = date('Y-m-d H:i:s');
phpinfo();
http://localhost にアクセス
ブレークポイントで停止して、$nowの情報が確認できる。
確認1~4を全て確認したら終わりです。
終わりに
今回は、LAMP環境を作成する最小構成のテンプレートを紹介いたしました。(ただし、MySQLではなくMariaDB)
htmlディレクトリの中身を別のアプリケーションで置換すれば、別のアプリケーションやフレームワークも動作させることができるので、汎用的な構成となっております。
また、apacheの代わりにnginxで動かすテンプレートの紹介やwordpressやlaravelなど作成する雛形も紹介していくので、続編にご期待を。
成果物
成果物をgithubにアップしましたので、いいねしてくださった方のみ、cloneを許可しますので、評価をよろしくお願いいたします。
Discussion