LoginSignup
4
1

More than 3 years have passed since last update.

AWS EBベースのWordPress環境をローカルPCのDockerで再現してみた

Last updated at Posted at 2019-07-31

はじめに

AWS Elastic Beanstalk(PHPランタイム)を利用したポータルサイトを運営しています。APサーバはWordPress on EC2、DBサーバはRDS(MySQL)という典型的な構成です。その他、ALBやEFSを活用したスケーラブルな構成、CodePipelineを活用したCI/CDの実践など、ベストプラクティスのお世話になっています。先人たち知恵に感謝です。

そんなポータルサイトですが、ローカル開発環境の整備がおざなりになっていました、、、。この度、Docker for Desktop (on Windows 10) を利用して、ローカル開発環境を構築したので、手順やハマったことを共有します。特に、APサーバのOSにAmazon Linux 2を採用したことが、情報の混乱による遠回りを招きました、、、。この記事を読んだ方が、少しでも近道できれば幸いです。

(2019/08/12 追記)
ボリュームマウントするuploadsフォルダの所有者をhttpdプロセスの起動ユーザ(apacheなど)に変更するようにDockerfileを修正しました。これをやっておかないと、メディアのアップロードや物理削除でエラーになります。

開発環境を整理する

まず、開発環境について整理します。AWS上の開発環境を便宜上、リモート開発環境と呼びます。厳密には、リモート/ローカル環境間で各種バージョンを一致させるべきですが、今回はそこまで厳密性にこだわりませんでした。APサーバは、Amazon Linuxのサポート期限が2020年6月30日と迫っていることもあり、Amazon Linux 2を選択しました。これがハマった要因だったのです、、、。

コピー元のリモート開発環境(AWS)

  • APサーバ:64bit Amazon Linux 2018.03 v2.8.12 running PHP 7.2 (AWS Elastic Beanstalk)
  • DBサーバ:Amazon RDS for MySQL 5.6

コピー先のローカル開発環境(Docker for Desktop on Windows 10 Enterprise)

  • APサーバ:Amazon Linux 2(Docker公式イメージ)
  • DBサーバ:MySQL 5.7(Docker公式イメージ)

ローカル開発環境でやりたいこと

ローカル開発環境でやりたいことは、とてもシンプルです。

  • リモート開発環境と同じgitリポジトリを利用したい(ローカルはfeatureブランチで)
  • リモート開発環境と同じデータ(データベースおよびメディアファイル)を利用したい

つまり、(1) APサーバ的なAWS Elastic Beanstalkがやっていることの再現、(2) DBサーバ的なデータ移行です。ただ単に、WordPress環境をローカルPC上に構築するのであれば、WordPressおよびMySQL両方ともDocker公式イメージから構築すれば良いので瞬殺です(クイックスタート・ガイド:Docker Compose と Wordpress)。しかし、AWS Elastic Beankstalk環境と同じようにgitリポジトリを利用するために、Amazon Linux 2から環境構築することにしました。

Dockerコマンドで手順を確認してみる

Dockerfileやdocker-compose.ymlをゴリゴリ書き始める前に、Dockerコマンドで地道に手順を確認することにしました。

まず、最新のAmazon LinuxイメージすなわちAmazon Linux 2イメージを取得して、/sbin/initでOS起動してみましたが、いきなり以下のエラーが発生してしまいました。/sbin/initがない、、、これは先が思いやられます。

$ docker pull amazonlinux:latest
$ docker run -it -d --name hoge-web amazonlinux:latest /sbin/init
4cb36ea9...(省略)
docker: Error response from daemon: OCI runtime create failed: container_linux.g
o:344: starting container process caused "exec: \"/sbin/init\": stat /sbin/init:
 no such file or directory": unknown.

Amazon Linux 2の公式イメージは、かなりスリムアップされており、systemdすら初期インストールされていないようです。Qiitaの記事を検索してみると、「まず/bin/bashで起動してsystemdをインストールしてから/sbin/initで起動せよ」とのことでしたので、やってみました。まず、/bin/bashで起動します。

$ docker rm hoge-web
$ docker run -it -d --name hoge-web amazonlinux:latest /bin/bash
b567ea12...(省略)

初期状態では、httpdが未インストールどころかpsコマンドやpingコマンドすら打てない、ということが分かりましたので、色々追加していきます。細やかなピックアップが面倒だったので、LAMPをインストールしてしまいます。

$ docker exec -it hoge-web /bin/bash
bash-4.2# amazon-linux-extras install -y lamp-mariadb10.2-php7.2 php7.2
bash-4.2# yum install -y systemd xinetd httpd mod_ssl php php-mbstring wget curl tar
bash-4.2# exit

続いて、必要な設定ファイルをコピーしておきます。aws_env.confはAWS Elastic Beanstalkが生成するファイルのひとつで、Apacheプロセスへ環境変数を渡すためのものです。その他、systemctlhttpdを自動起動するための設定ファイルやSSL関連ファイルなどがあります。

$ docker cp web/etc/httpd/conf/httpd.conf hoge-web:/etc/httpd/conf
$ docker cp web/etc/httpd/conf.d/aws_env.conf hoge-web:/etc/httpd/conf.d
$ docker cp web/etc/sysconfig/httpd hoge-web:/etc/sysconfig
$ docker cp web/lib/systemd/system/httpd.service hoge-web:/lib/systemd/system
$ docker cp web/ssl/hoge.crt hoge-web:/etc/pki/tls/certs/localhost.crt
$ docker cp web/ssl/hoge.key hoge-web:/etc/pki/tls/private/localhost.key

続いて、systemdインストール済みのコンテナを/sbin/initで起動します。httpdの自動起動を設定後、再びコンテナイメージをコミットします。これがマスタイメージになります。

$ docker commit hoge-web hoge-web:latest
sha256:2f1d9b04...(省略)

$ docker stop hoge-web && docker rm hoge-web
$ docker run -it -d --name hoge-web hoge-web:latest /sbin/init
$ docker exec hoge-web systemctl enable httpd
$ docker commit hoge-web hoge-web:latest

Dockerコマンドから設定ファイルへ

Dockerコマンドで手順が確認できましたので、その内容を設定ファイルで再現していきます。webサービス(WordPress)とdbサービス(MySQL)を利用するので、docker-compose.ymlを使います。

Dockerコマンドで確認した手順の流れ

簡単にまとめると、以下の4ステップです。

  1. Amazon Linux公式イメージを/bin/bashで起動
  2. systemdhttpdなどをインストールし、マスタイメージをコミット
  3. マスタイメージを/sbin/initで起動
  4. httpdの自動起動を設定し、マスタイメージをコミット

手順をDockerfileに落とし込む

手順1と手順2は、Dockerfileで対応します。先ほどの確認手順に加えて、PHPデバッグ向けにxdebugをインストールしています。また、AWS Elastic BeanstalkのPHPランタイム環境を再現するために、ディレクトリ作成やシンボリックリンク作成も行っています。

docker/web-init/Dockerfile
FROM amazonlinux:latest
CMD /bin/bash

# install software packages
RUN amazon-linux-extras install -y lamp-mariadb10.2-php7.2 php7.2 \
&& yum update -y && yum clean all \
&& yum install -y gcc xinetd httpd mod_ssl php php-mbstring php-devel php-pear wget tar \
&& pecl install xdebug \
&& mkdir -p /var/app/current \
&& cd /var/www \
&& rmdir html \
&& ln -s /var/app/current html \
&& mkdir -p /var/www/hoge/local/wp-content/uploads \
&& chown -R apache:apache /var/www/hoge

# copy configration files
COPY web/etc/httpd/conf/httpd.conf /etc/httpd/conf
COPY web/etc/httpd/conf.d/hoge-alias.conf /etc/httpd/conf.d
COPY web/etc/httpd/conf.d/aws_env.conf /etc/httpd/conf.d
COPY web/etc/php.d/xdebug.ini /etc/php.d
COPY web/etc/sysconfig/httpd /etc/sysconfig
COPY web/lib/systemd/system/httpd.service /lib/systemd/system

# copy certificate & private key
COPY web/ssl/hoge.crt /etc/pki/tls/certs/localhost.crt
COPY web/ssl/hoge.key /etc/pki/tls/private/localhost.key

続いて、手順3と手順4をDockerfileに落とし込みます。

docker/web/Dockerfile
FROM hoge-web:latest
CMD /sbin/init

# enable httpd auto-start
RUN systemctl enable httpd

手順をdocker-compose.ymlに落とし込む

さあ、いよいよdbサービスとwebサービスをまとめるときがやってきました。最終的なdocker-compose.ymlは以下の通りです。何点か工夫を加えました。

  • db/initdb.dに初期化用のSQLスクリプトを配置
    • CREATE DATABASEステートメントでデータベース作成
    • EXPORTしたダンプファイルでDROP/CREATE/INSERT(=データ移行)
  • ローカルPC側のクライアントツールからのアクセスを考慮し、3306ポートを公開
  • buildを二段階にするため、web-initとwebに分割
  • OSに渡す環境変数をenv_fileとして独立
  • 自動起動するsystemctl start httpdがエラーにならないよう特権(privileged: true)を指定
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    container_name: hoge-db
    volumes:
      - "./db/data:/var/lib/mysql"
      - "./db/initdb.d:/docker-entrypoint-initdb.d"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: hoge_wordpress
      MYSQL_USER: hoge_wordpress
      MYSQL_PASSWORD: hoge_wordpress
    ports:
      - "3306:3306"
  web-init:
    image: hoge-web:latest
    build:
      context: ./
      dockerfile: ./docker/web-init/Dockerfile
    command: /bin/bash
    container_name: hoge-web-init
  web:
    depends_on:
      - db
    image: hoge-web:latest
    build:
      context: ./
      dockerfile: ./docker/Dockerfile
#   command: /usr/sbin/httpd -DFOREGROUND
    command: /sbin/init
    container_name: hoge-web
    volumes:
      - "./web/HOGE_WP:/var/app/current"
      - "./web/uploads:/var/www/hoge/local/wp-content/uploads"
    links:
      - db
    ports:
      - "80:80"
      - "443:443"
    privileged: true
    restart: always
    env_file: ./web/etc/sysconfig/httpd

Docker Composeで環境構築する

ついに、AWS Elastic Beanstalk(PHPランタイム)を利用したポータルサイトのローカル開発環境を構築するときがやってきました。面倒な手順はすべて設定ファイルにまとめましたので、コマンドはとてもシンプルです。

$ docker-compose build web-init web
$ docker-compose up -d db web

なお、docker-compose upするときにサービス名を明示しないと、web-initサービスもcreateされてしまい、ごみコンテナが残ってしまうので、注意が必要です。

さいごに

docker-compose.ymlのコメントにあるように、試行錯誤を重ねる中で/sbin/initではなく、/usr/sbin/httpdで起動してしまう方法も考えました。この場合、systemctlを利用せずにhttpdを起動/停止するため、/sbin/initでのコンテナ起動が不要となります。そうすると、かなりシンプルになるのですが、Amazon Linux 2上でのsystemdを利用したサービス制御ができなくなってしまうため、/sbin/initでの起動にこだわりました。

また、手順を確認したときのように、Dockerコマンドで対応すれば何とでもなるのですが、Docker Composeの利用にこだわりました。少しトリッキーな気もしますが、環境構築のための手順はかなりシンプル化できたと思います。

参考

https://qiita.com/harukisan/items/6910684bbf2043a29812
https://qiita.com/Targityen/items/6e80b855b79d521412f0
https://qiita.com/issei_0403/items/0dd1ce7407e720338ea8
https://qiita.com/idani/items/79de4a525eaeaa16e497

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1