WordPress
Docker
docker-compose

Dockerを用いたWordpressテーマ・プラグイン開発環境構築


Introduction

Wordpressのテーマやプラグインを開発するため、Dockerを用いて環境構築を行います。

DockerコンテナでWP-CLIを用いることで開発における汎用性を考慮します。

公式のイメージはあくまで公開を想定しているようでしたので、

あくまでテーマやプラグインの開発をしやすくなるように構築します。


Goal

docker-composeで構築し再利用や構成拡張が容易となるようにします。

構成は以下とし、少ない手順でWordpressに関する環境構築ができるようにします。


  • nginx

  • php

  • MySQL

  • phpMyAdmin

  • Mailhog

データベースとWordpress関連のファイルはホストにマウントし、

コンテナが破棄されてもデータを残すようにします。


Support

以下環境で動作を確認しています。


  • MacOSX 10.14 Mojave


    • Docker for Mac (18.06-ce-mac73)



  • CentOS 7.5


    • Docker 18.06-ce

    • docker-compose 1.22.0




How to


ファイル構成

~/wordpress-docker

|- .docker
| |- app
| | `- Dockerfile
| `- web
| |- etc/nginx
| | |- h5bp
| | | |- directive-only
| | | | |- cross-domain-insecure.conf
| | | | |- extra-security.conf
| | | | `- x-ua-compatible.conf
| | | `- location
| | | |- cache-busting.conf
| | | |- cross-domain-fonts.conf
| | | |- expires.conf
| | | `- protect-system-files.conf
| | |- fastcgi_params
| | |- mime.types
| | |- nginx.conf
| | `- site.conf.template
| `- Dockerfile
|- .utils
| |- message.sh
| `- wpinst.sh
|- Makefile
`- docker-compose.yml


Docker


docker-compose.yml

使用するコンテナ情報を記載します。

各コンテナのenvironmentとしてVIRTUAL_HOSTを指定している箇所があります。

これはjwilder/nginx-proxyによるリバースプロキシの設定です。

なお、nginx-proxyは便利ですがdocker.sockを読み判断をするため注意が必要です。

当記事は開発環境として他のコンテナが立ち上がっていないことを想定しています。

別のコンテナが立っている状態であったり、本番環境に対して当記事の内容を参照頂く場合は、

そのまま使用せず各リスクに対しての検討を行ってください。


docker-compose.yml

version: '2'

services:

################################
# Proxy
################################
proxy:
image: jwilder/nginx-proxy
ports:
- 80:80
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro

################################
# Application
################################
app:
build:
context: ./.docker/app
depends_on:
- db
links:
- db
volumes:
- ./app:/var/www/html/
environment:
- DB_NAME=wp
- DB_USER=wp
- DB_PASSWORD=password
- DB_HOST=db
- DB_PREFIX=wp_
- WP_ENV=development
- WP_HOST=$PROJECT_NAME.docker
- WP_ADMIN_USER=webmaster
- WP_ADMIN_PASSWORD=5iveL!fe

################################
# Webserver
################################
web:
build:
context: ./.docker/web
depends_on:
- app
links:
- app
volumes_from:
- app
environment:
- VIRTUAL_HOST=$PROJECT_NAME.docker
- VIRTUAL_PORT=80
command: /bin/sh -c "envsubst '$$VIRTUAL_HOST' < /etc/nginx/site.conf.template > /etc/nginx/site.conf && nginx -g 'daemon off;'"

################################
# Database
################################
db:
image: mariadb
volumes:
- ./db/mysql_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=wp
- MYSQL_USER=wp
- MYSQL_PASSWORD=password

################################
# phpMyAdmin
################################
phpmyadmin:
image: phpmyadmin/phpmyadmin
depends_on:
- db
links:
- db
environment:
- VIRTUAL_PORT=80
- VIRTUAL_HOST=phpmyadmin.$PROJECT_NAME.docker
- PMA_ABSOLUTE_URI=http://phpmyadmin.$PROJECT_NAME.docker/
- PMA_ARBITRARY=1
- PMA_HOST=db
- PMA_PORT=3306
- PMA_USER=wp
- PMA_PASSWORD=password

################################
# Mailhog
################################
mail:
image: mailhog/mailhog
environment:
- VIRTUAL_PORT=8025
- VIRTUAL_HOST=mail.$PROJECT_NAME.docker



Dockerfile(Wordpress)

Wordpress本体を配置するコンテナはphp7をベースに以下を追加しています。


  • mhsendmail

  • mysql-client

  • wpcli


./docker/app/Dockerfile

FROM webdevops/php:alpine-php7

RUN apk add --no-cache musl-dev go mysql-client

# install mhsendmail and configure it to user mailhog
RUN go get github.com/mailhog/mhsendmail
RUN cp /root/go/bin/mhsendmail /usr/bin/mhsendmail
RUN echo 'sendmail_path = /usr/bin/mhsendmail --smtp-addr mail:1025' > /opt/docker/etc/php/php.ini

# install wp cli
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
RUN chmod +x wp-cli.phar
RUN mv wp-cli.phar /usr/local/bin/wp

WORKDIR /var/www/html/



Dockerfile(nginx)

nginxのイメージをベースに、後述する設定ファイル群を追加しています。


.docker/web/Dockerfile

FROM amd64/nginx:alpine

RUN apk add --no-cache curl
ADD ./etc/nginx/* /etc/nginx/
ADD ./etc/nginx/h5bp/location/* /etc/nginx/h5bp/location/
ADD ./etc/nginx/h5bp/directive-only/* /etc/nginx/h5bp/directive-only/


設定ファイルはファイル数、各ファイルの行数がそれなりにあるので折りたたんでいます。

.docker/web/etc/nginx.conf


.docker/web/etc/nginx.conf

# Configuration File - Nginx Server Configs

# http://nginx.org/en/docs/dirindex.html

# Run as a unique, less privileged user for security reasons.
# Default: nobody nobody
user nginx;

# Sets the worker threads to the number of CPU cores available in the system for best performance.
# Should be > the number of CPU cores.
# Maximum number of connections = worker_processes * worker_connections
# Default: 1
worker_processes auto;

# Maximum number of open files per worker process.
# Should be > worker_connections.
# Default: no limit
worker_rlimit_nofile 8192;

events {
# If you need more connections than this, you start optimizing your OS.
# That's probably the point at which you hire people who are smarter than you as this is *a lot* of requests.
# Should be < worker_rlimit_nofile.
# Default: 512
worker_connections 8000;
}

# Log errors and warnings to this file
# This is only used when you don't override it on a server{} level
# Default: logs/error.log error
error_log /var/log/nginx/error.log warn;

# The file storing the process ID of the main process
# Default: nginx.pid
pid /run/nginx.pid;

http {

# Hide nginx version information.
# Default: on
server_tokens off;

# Setup the fastcgi cache.
fastcgi_buffers 8 8k;
fastcgi_buffer_size 8k;
fastcgi_read_timeout 120s;
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=wordpress:10m max_size=250m inactive=1h;
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_cache_lock on;
fastcgi_cache_key $realpath_root$scheme$host$request_uri$request_method$http_origin;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_pass_header Set-Cookie;
fastcgi_pass_header Cookie;

# Specify MIME types for files.
include mime.types;

# Default: text/plain
default_type application/octet-stream;

# Update charset_types to match updated mime.types.
# text/html is always included by charset module.
# Default: text/html text/xml text/plain text/vnd.wap.wml application/javascript application/rss+xml
charset_types
text/css
text/plain
text/vnd.wap.wml
application/javascript
application/json
application/rss+xml
application/xml;

# Include $http_x_forwarded_for within default format used in log files
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

# Log access to this file
# This is only used when you don't override it on a server{} level
# Default: logs/access.log combined
access_log /var/log/nginx/access.log main;

# How long to allow each connection to stay idle.
# Longer values are better for each individual client, particularly for SSL,
# but means that worker connections are tied up longer.
# Default: 75s
keepalive_timeout 20s;

# Speed up file transfers by using sendfile() to copy directly
# between descriptors rather than using read()/write().
# For performance reasons, on FreeBSD systems w/ ZFS
# this option should be disabled as ZFS's ARC caches
# frequently used files in RAM by default.
# Default: off
sendfile on;

# Don't send out partial frames; this increases throughput
# since TCP frames are filled up before being sent out.
# Default: off
tcp_nopush on;

# Compression

# Enable gzip compression.
# Default: off
gzip on;

# Compression level (1-9).
# 5 is a perfect compromise between size and CPU usage, offering about
# 75% reduction for most ASCII files (almost identical to level 9).
# Default: 1
gzip_comp_level 5;

# Don't compress anything that's already small and unlikely to shrink much
# if at all (the default is 20 bytes, which is bad as that usually leads to
# larger files after gzipping).
# Default: 20
gzip_min_length 256;

# Compress data even for clients that are connecting to us via proxies,
# identified by the "Via" header (required for CloudFront).
# Default: off
gzip_proxied any;

# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client's Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
# Default: off
gzip_vary on;

# Compress all output labeled with one of the following MIME-types.
# text/html is always compressed by gzip module.
# Default: text/html
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rss+xml
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;

include site.conf;
}



.docker/web/etc/nginx/site.conf.template


.docker/web/etc/nginx/site.conf.template

server {

listen [::]:80;
listen 80;

server_name ${VIRTUAL_HOST};

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

root /var/www/html;
index index.php index.htm index.html;
add_header Fastcgi-Cache $upstream_cache_status;

# Specify a charset
charset utf-8;

# Set the max body size equal to PHP's max POST size.
client_max_body_size 25m;

# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#virtualbox
sendfile off;

# Prevent PHP scripts from being executed inside the uploads folder.
location ~* /app/uploads/.*\.php$ {
deny all;
}

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

include h5bp/directive-only/extra-security.conf;
include h5bp/directive-only/x-ua-compatible.conf;
include h5bp/location/cross-domain-fonts.conf;
include h5bp/location/protect-system-files.conf;

location ~ \.php$ {
try_files $uri /index.php;

include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_pass app:9000;
}
}

# Redirect some domains
server {
listen [::]:80;
listen 80;
server_name www.${VIRTUAL_HOST};

location / {
return 301 http://${VIRTUAL_HOST}$request_uri;
}
}



.docker/web/etc/nginx/fastcgi_params


.docker/web/etc/nginx/fastcgi_params

fastcgi_param  QUERY_STRING       $query_string;

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;



.docker/web/etc/nginx/mime.types


.docker/web/etc/nginx/mime.types

types {

# Data interchange

application/atom+xml atom;
application/json json map topojson;
application/ld+json jsonld;
application/rss+xml rss;
application/vnd.geo+json geojson;
application/xml rdf xml;

# JavaScript

# Normalize to standard type.
# https://tools.ietf.org/html/rfc4329#section-7.2
application/javascript js;

# Manifest files

application/manifest+json webmanifest;
application/x-web-app-manifest+json webapp;
text/cache-manifest appcache;

# Media files

audio/midi mid midi kar;
audio/mp4 aac f4a f4b m4a;
audio/mpeg mp3;
audio/ogg oga ogg opus;
audio/x-realaudio ra;
audio/x-wav wav;
image/bmp bmp;
image/gif gif;
image/jpeg jpeg jpg;
image/jxr jxr hdp wdp;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-jng jng;
video/3gpp 3gp 3gpp;
video/mp4 f4p f4v m4v mp4;
video/mpeg mpeg mpg;
video/ogg ogv;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asf asx;
video/x-ms-wmv wmv;
video/x-msvideo avi;

# Serving `.ico` image files with a different media type
# prevents Internet Explorer from displaying then as images:
# https://github.com/h5bp/html5-boilerplate/commit/37b5fec090d00f38de64b591bcddcb205aadf8ee

image/x-icon cur ico;

# Microsoft Office

application/msword doc;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;

# Web fonts

application/font-woff woff;
application/font-woff2 woff2;
application/vnd.ms-fontobject eot;

# Browsers usually ignore the font media types and simply sniff
# the bytes to figure out the font type.
# https://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern
#
# However, Blink and WebKit based browsers will show a warning
# in the console if the following font types are served with any
# other media types.

application/x-font-ttf ttc ttf;
font/opentype otf;

# Other

application/java-archive ear jar war;
application/mac-binhex40 hqx;
application/octet-stream bin deb dll dmg exe img iso msi msm msp safariextz;
application/pdf pdf;
application/postscript ai eps ps;
application/rtf rtf;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-bb-appworld bbaw;
application/x-bittorrent torrent;
application/x-chrome-extension crx;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-opera-extension oex;
application/x-perl pl pm;
application/x-pilot pdb prc;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert crt der pem;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xslt+xml xsl;
application/zip zip;
text/css css;
text/csv csv;
text/html htm html shtml;
text/markdown md;
text/mathml mml;
text/plain txt;
text/vcard vcard vcf;
text/vnd.rim.location.xloc xloc;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/vtt vtt;
text/x-component htc;

}



.docker/web/etc/nginx/h5bp/location/cross-domain-fonts.conf


.docker/web/etc/nginx/h5bp/location/cross-domain-fonts.conf

# Cross domain webfont access

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
include h5bp/directive-only/cross-domain-insecure.conf;

# Also, set cache rules for webfonts.
#
# See http://wiki.nginx.org/HttpCoreModule#location
# And https://github.com/h5bp/server-configs/issues/85
# And https://github.com/h5bp/server-configs/issues/86
access_log off;
add_header Cache-Control "max-age=2592000";
}



.docker/web/etc/nginx/h5bp/location/expires.conf


.docker/web/etc/nginx/h5bp/location/expires.conf

# Expire rules for static content


# No default expire rule. This config mirrors that of apache as outlined in the
# html5-boilerplate .htaccess file. However, nginx applies rules by location,
# the apache rules are defined by type. A consequence of this difference is that
# if you use no file extension in the url and serve html, with apache you get an
# expire time of 0s, with nginx you'd get an expire header of one month in the
# future (if the default expire rule is 1 month). Therefore, do not use a
# default expire rule with nginx unless your site is completely static

# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
add_header Cache-Control "max-age=0";
}

# Feed
location ~* \.(?:rss|atom)$ {
add_header Cache-Control "max-age=3600";
}

# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
access_log off;
add_header Cache-Control "max-age=2592000";
}

# Media: svgz files are already compressed.
location ~* \.svgz$ {
access_log off;
gzip off;
add_header Cache-Control "max-age=2592000";
}

# CSS and Javascript
location ~* \.(?:css|js)$ {
add_header Cache-Control "max-age=31536000";
access_log off;
}

# WebFonts
# If you are NOT using cross-domain-fonts.conf, uncomment the following directive
# location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
# add_header Cache-Control "max-age=2592000";
# access_log off;
# }



.docker/web/etc/nginx/h5bp/location/protect-system-files.conf


.docker/web/etc/nginx/h5bp/location/protect-system-files.conf

# Prevent clients from accessing hidden files (starting with a dot)

# This is particularly important if you store .htpasswd files in the site hierarchy
# Access to `/.well-known/` is allowed.
# https://www.mnot.net/blog/2010/04/07/well-known
# https://tools.ietf.org/html/rfc5785
location ~* /\.(?!well-known\/) {
deny all;
}

# Prevent clients from accessing to backup/config/source files
location ~* (?:\.(?:bak|conf|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ {
deny all;
}



.docker/web/etc/nginx/h5bp/directive-only/cross-domain-insecure.conf


.docker/web/etc/nginx/h5bp/directive-only/cross-domain-insecure.conf

# Cross domain AJAX requests


# http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

# **Security Warning**
# Do not use this without understanding the consequences.
# This will permit access from any other website.
#
add_header "Access-Control-Allow-Origin" "*";

# Instead of using this file, consider using a specific rule such as:
#
# Allow access based on [sub]domain:
# add_header "Access-Control-Allow-Origin" "subdomain.example.com";



.docker/web/etc/nginx/h5bp/directive-only/extra-security.conf


.docker/web/etc/nginx/h5bp/directive-only/extra-security.conf

# The X-Frame-Options header indicates whether a browser should be allowed

# to render a page within a frame or iframe.
add_header X-Frame-Options SAMEORIGIN always;

# MIME type sniffing security protection
# There are very few edge cases where you wouldn't want this enabled.
add_header X-Content-Type-Options nosniff always;

# The X-XSS-Protection header is used by Internet Explorer version 8+
# The header instructs IE to enable its inbuilt anti-cross-site scripting filter.
add_header X-XSS-Protection "1; mode=block" always;

# with Content Security Policy (CSP) enabled (and a browser that supports it (http://caniuse.com/#feat=contentsecuritypolicy),
# you can tell the browser that it can only download content from the domains you explicitly allow
# CSP can be quite difficult to configure, and cause real issues if you get it wrong
# There is website that helps you generate a policy here http://cspisawesome.com/
# add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' https://www.google-analytics.com;" always;



.docker/web/etc/nginx/h5bp/directive-only/x-ua-compatible.conf


.docker/web/etc/nginx/h5bp/directive-only/x-ua-compatible.conf

# Force the latest IE version

add_header "X-UA-Compatible" "IE=Edge";


.docker/web/etc/nginx/h5bp/location/cache-busting.conf


.docker/web/etc/nginx/h5bp/location/cache-busting.conf

# Built-in filename-based cache busting


# https://github.com/h5bp/html5-boilerplate/blob/5370479476dceae7cc3ea105946536d6bc0ee468/.htaccess#L403
# This will route all requests for /css/style.20120716.css to /css/style.css
# Read also this: github.com/h5bp/html5-boilerplate/wiki/cachebusting
# This is not included by default, because it'd be better if you use the build
# script to manage the file names.
location ~* (.+)\.(?:\d+)\.(js|css|png|jpg|jpeg|gif)$ {
try_files $uri $1.$2;
}



Makefile

docker-composeやDockerfileに環境変数PROJECT_NAMEの記載があります。

Makefileでは環境変数の値を定義した後、各ターゲットで処理を切り替えています。

内容は読解できる範疇と思慮しますので、文面での説明は割愛します。


Makefile

ARGS = $(filter-out $@,$(MAKECMDGOALS))

MAKEFLAGS += --silent

################################
# ENVIRONMENT
################################

export PROJECT_NAME=your_project
export COMPOSE_PROJECT_NAME=${PROJECT_NAME}

################################
# UTILS
################################

ssh:
docker exec -it $$(docker-compose ps -q $(ARGS)) sh

wpinst:
docker cp ./.utils/wpinst.sh $$(docker-compose ps -q app):/var/www/html/wpinst.sh
docker exec -it $$(docker-compose ps -q app) sh wpinst.sh
docker exec -it $$(docker-compose ps -q app) rm wpinst.sh

################################
# CONTAINER ACCESS
################################

up:
bash ./.utils/message.sh info "Starting your project..."
mkdir -p app
mkdir -p db/mysql_data
docker-compose up -d

stop:
bash ./.utils/message.sh info "Stopping your project..."
docker-compose stop

down:
bash ./.utils/message.sh info "Removing containers..."
docker-compose down

destroy: stop
bash ./.utils/message.sh info "Deleting all containers..."
docker-compose down --rmi all --remove-orphans

upgrade:
bash ./.utils/message.sh info "Upgrading your project..."
docker-compose pull
docker-compose build --pull
make composer update
make up

restart: stop up

rebuild: destroy upgrade

clean:
docker ps -f name=${PROJECT_NAME} -q | xargs docker stop && yes | docker container prune
sudo rm -rf ./app/*
sudo rm -rf ./db/mysql_data/*

################################
# INFORMATION
################################

urls:
bash ./.utils/message.sh headline "You can access your project at the following URLS:"
bash ./.utils/message.sh link "Backend: http://${PROJECT_NAME}.docker/wp/wp-admin/"
bash ./.utils/message.sh link "Frontend: http://${PROJECT_NAME}.docker/"
bash ./.utils/message.sh link "Mailhog: http://mail.${PROJECT_NAME}.docker/"
bash ./.utils/message.sh link "PHPMyAdmin: http://phpmyadmin.${PROJECT_NAME}.docker/"
echo ""

state:
docker-compose ps

logs:
docker-compose logs -f --tail=50 $(ARGS)

################################
# Argument fix workaround
################################
%:
@:


.utils/message.sh


.utils/message.sh

#!/usr/bin/env bash

# arguments
messageType=$1
messageText=$2

# colors
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
GRAY='\033[0;37m'
NC='\033[0m'

case "$messageType" in
"headline")
echo ""
echo -e "${GRAY}-------------------------------------------------------------------${NC}"
echo -e "${GREEN} $messageText${NC}"
echo -e "${GRAY}-------------------------------------------------------------------${NC}"
echo ""
;;
"warning")
echo -e "${RED}$(echo $messageText | tr '[:lower:]' '[:upper:]')${NC}"
;;
"success")
echo -e "${GREEN}$messageText${NC}"
;;
"text")
echo -e "${GRAY}$messageText${NC}"
;;
"info")
echo -e "${YELLOW}$messageText${NC}"
;;
"link")
echo -e "${CYAN}$messageText${NC}"
;;
esac



以下はmake wpinstを実行した際に呼び出されるwpinst.shの内容です。

WP-CLIを用いてWordpressのダウンロードおよびインストール、マルチサイト化、日本語化、プラグインやテーマのインストールを行っています。

プラグインは概ね必要になるであろうもの、テーマはシングルカラムでの確認がしやすいようCenoteを入れるようにしています。

また、テーマ開発での利便性を考慮して日本語のダミー記事をインポートしています。

注意点

WP-CLIのコマンドオプションとして--allow-rootを指定しています。

Dockerコンテナの実行ユーザがrootとなるためです。


.utils/wpinst.sh

#!/bin/sh

wp --info

wp core download --locale=ja --allow-root
wp config create \
--dbname=$DB_NAME \
--dbuser=$DB_USER \
--dbpass=$DB_PASSWORD \
--dbhost=$DB_HOST \
--dbprefix=$DB_PREFIX \
--allow-root
wp db create --allow-root
wp core multisite-install \
--url="http://$WP_HOST" \
--title=$WP_HOST \
--admin_user=$WP_ADMIN_USER \
--admin_password=$WP_ADMIN_PASSWORD \
--admin_email="$WP_ADMIN_USER@$WP_HOST" \
--allow-root

wp plugin install wp-multibyte-patch --activate-network --allow-root
wp plugin install gutenberg --activate-network --allow-root
wp plugin install all-in-one-seo-pack --activate-network --allow-root
wp plugin install google-sitemap-generator --activate-network --allow-root
wp plugin install broken-link-checker --activate-network --allow-root
wp plugin install wp-mail-smtp --activate-network --allow-root
wp plugin install pushpress --activate-network --allow-root

wp theme install cenote --activate --allow-root

wp option update timezone_string $(wp eval "echo _x( '0', 'default GMT offset or timezone string' );" --allow-root) --allow-root
wp option update date_format $(wp eval "echo __( 'Y-m-d' );" --allow-root) --allow-root

curl -LOk https://raw.github.com/jawordpressorg/theme-test-data-ja/master/wordpress-theme-test-date-ja.xml \
&& wp plugin install wordpress-importer --activate --allow-root \
&& wp import wordpress-theme-test-date-ja.xml --authors=create --allow-root \
&& rm wordpress-theme-test-date-ja.xml



実行

さいごにhostsを指定します。

$PROJECT_NAMEをwpsampleとした場合は以下のように設定します。

127.0.0.1 wpsample.docker

127.0.0.1 mail.wpsample.docker
127.0.0.1 phpmyadmin.wpsample.docker

これで準備はできました。

make upでDockerコンテナを立ち上げます。

make wpinstでWordpressを初期状態にします。

このときDBコンテナの準備が掛かるのでmake logsでDBのコンテナが立ち上がりきっていることを確認してから実行します。

ブラウザからhostsで指定したホスト名に対してアクセスを試みるとWordpressサイトが確認できます。

make stopでコンテナの停止、

make destroyでコンテナの破棄、

make cleanでコンテナとマウントしたボリュームデータを破棄できます。


Conclusion

Wordpressの環境構築としてXAMPPやVCCW、Trellisなどがありますが、

よりホスト環境を汚さず、容易に構築およびメンバーへの連携ができることが望ましいです。

この方法であれば効率化が図れ、拡張性もあるのではと思慮します。

いわゆるDevOpsとしては不充分であるため、本番・運用も鑑みてブラッシュアップしていきます。

うまくいったら更新します。その場合はk8sを用いていると思いますので別記事になるかもしれません。


Reference

GitHub - schliflo/bedrock-docker

nginx-proxy(docker)を使う際の注意点 | TechBlog