Drupal 9 の環境を Docker を用いて構築する
Drupal Advent Calendar 2020 - Qiita の8日目です。
ものすごくギリギリになっちゃいました、スミマセン。
2022/06/03 更新 また Drupal を触る機会が発生したので、記事の内容を2022年現在のものに刷新しています。
WSL2 上で起動させている Docker で Drupal 環境を構築していこうと思います。
Drupal は公式で Docker イメージを公開しているので、それをベースに作っていこうと思います。
※今回はイメージを 9.3.14-php8.1-apache-bullseye
にしていますが Drupal - Official Image | Docker Hub なりで好きなものを選んでもらえればと思います。
資材の永続化の準備
まずは Drupal の資材をホストマシン側に展開し、永続化を行います。
$ docker run --rm drupal:9.3.14-php8.1-apache-bullseye bash -c "composer require drush/drush && tar -cC /opt/drupal --exclude ./vendor --exclude ./web/core --exclude ./web/profiles ." | tar -xC ./
上記のコマンドでカレントディレクトリに composer で管理されるパッケージが格納されている ./vendor/
ディレクトリと drupal 資材の core/
及び profiles/
ディレクトリを除いてコンテナからホストに展開しています。
また、今回は drupal をコマンドラインで操作するための drush も使用したいため、drush のパッケージ状態が記載された composer.json
及び composer.lock
ファイルが欲しかったので tar
コマンドで資材を展開する前に composer require drush/drush
を実行しています。
これを怠ると docker-compose
を立ち上げた際、後ほど記載する Dockerfile
で drush をインストールしてもホスト側の drush の記載がない composer.json
及び composer.lock
で上書きされてしまうので注意です。
補足として、他に永続化する必要のないディレクトリがある場合は以下コマンドで資材を確認しつつ --exclude 不要なファイルやディレクトリ
パラメーターを継ぎ足して実行するなりしてもらえればと思います。
$ docker run --rm drupal:9.3.14-php8.1-apache-bullseye ls -altr /opt/drupal
$ docker run --rm drupal:9.3.14-php8.1-apache-bullseye ls -altr /opt/drupal/web
Dockerfile の設定
FROM drupal:9.3.14-php8.1-apache-bullseye
# Drushインストール
RUN composer require drush/drush \
&& ln -s /opt/drupal/vendor/bin/drush /usr/local/bin/drush \
&& drush --version
# 初回起動時にDrupalをインストールする用のshellを配置
COPY docker-entrypoint.sh /tmp
RUN sed -i 's/\r//g' /tmp/docker-entrypoint.sh
Drupal のイメージをベースに drush
コマンドを使用できるようにします。
また、コンテナを初めて立ち上げた時のみ起動するシェルスクリプトファイルをコピーしておきます。
drush に対してシンボリックリンクをしておくことで、ホスト側からも drush コマンドを実行しやすくなります。
※この Dockerfile をビルドして、それを利用すれば最初に行った 資材の永続化の準備 の composer require drush/drush
の記述をせずとも composer.json
と composer.lock
に drush/drush
の記述が含まれた状態になっていると思います……
docker-compose.yml
version: '3.8'
services:
mysql:
image: mariadb
volumes:
- data:/var/lib/mysql
- ./dump:/docker-entrypoint-initdb.d
environment:
MYSQL_ROOT_PASSWORD: "password"
MYSQL_DATABASE: "drupal"
ports:
- "3306:3306"
drupal:
build: ./
volumes:
- ./web/themes:/var/www/html/themes
- ./web/modules:/var/www/html/modules
- ./web/sites:/var/www/html/sites
- ./config:/opt/drupal/config
- ./composer.json:/opt/drupal/composer.json
- ./composer.lock:/opt/drupal/composer.lock
entrypoint: "/tmp/docker-entrypoint.sh"
command: "apache2-foreground"
environment:
PROFILE: "minimal"
ports:
- "80:80"
depends_on:
- mysql
volumes:
data: {}
永続化のために各種 volumes の指定をしています。
drupal や各種モジュールのバージョンを保持するために composer.json
composer.lock
を volumes に含めています。
また、各種 module や theme, sites 設定 を Git で管理することを想定してこれらも volumes に含めています。
drupal の environment でプロファイルを指定しています。
ちょうど Drupal Advent Calendarの前日の Drupal9 インストール機能を追いかける | Irologue blog で詳しく紹介してくださっているので、その辺りを見ていただければと思います。
docker-entrypoint.sh
#!/bin/sh
# 初回起動時Drupalインストールを走らせる
if [ ! -d "/tmp/check" ]; then
mkdir /tmp/check
mkdir -p /opt/drupal/web/sites/default/files/translations/
curl https://ftp.drupal.org/files/translations/all/drupal/drupal-${DRUPAL_VERSION}.ja.po \
-o /opt/drupal/web/sites/default/files/translations/drupal-${DRUPAL_VERSION}.ja.po
sleep 30s && drush si -y ${PROFILE} \
--account-name="admin" --account-pass="admin" --account-mail="example@example.com" \
--db-url="mysql://root:password@mysql:3306/drupal" \
--site-mail="example@example.com" --site-name="Drupal Test" \
--locale="ja"
drush config-set system.site uuid e707291e-7532-46d1-822c-0983cb676f8d
drush config-set language.entity.ja uuid 0a2ddbab-8662-4d8a-bc0b-e20dd875e041
if [ -f "/opt/drupal/config/system.site.yml" ]; then
# config の yml ファイルが出力されているなら取り込む
drush cim -y
else
# 出力されてないなら出力しておく
drush cex -y
fi
fi
exec "$@"
コンテナを立ち上げた初回のみ Drupal のインストールを自動的に行なってくれるような shell を書いておきます。
Docker で Drupal を立ち上げる記事はいくつかあったのですが、コンテナ立ち上げたタイミングで Drupal のインストールしている記事はなさそうだったので、今回記事にしてみました。
site:install - Drush 細かい引数は適宜調整してもらうとして、以下の公式ドキュメントに各引数の説明があるので、そちらを参照いただければと思います。
途中で Drupal の configuration management を有効にするために、固定のUUIDをセットしています。
この UUID は各々のプロジェクトごとに変更すると良いと思います。
最後に config/
配下にファイルがありそうだったら drush の configuration import を実行して構成の同期を行うようにしています。
存在しなければ新規でファイルを出力するために drush の configuration export を実行しています。
この UUID をセットする処理を省くと、以下のようなエラーが出てしまい、正常に config/
配下に出力されている 設定用の yaml 郡を取り込めないので、セットする必要があります。
The import failed due for the following reasons: [error]
Site UUID in source storage does not match the target storage.
(ソースのストレージにあるサイトのUUIDが、対象のストレージに一致しません。)
※以前マサカリ頂いてもっとスマートな方法があったような気がするのですが、手持ちの環境で上手く動作せず……引き 続き検証中です。
ソース一式
一応以下で上記の内容を含んだスケルトン的なものを置いているので、ちょっと試したいなと思われましたらDLしていただければ幸いです。
https://github.com/kato83/drupalExample