Docker for Macで構築したEC−CUBE4が激遅だったので改善してみた

2018年秋にリリースされたEC−CUBE4の開発環境をdocker-composeで作成してみました。

タイトルにある通り開発環境の「速度改善」が今回のメインですが、一応環境構築するまでの手順から載せておきます。
※不要な方は飛ばしてください

開発環境

  • MacBook Pro(macOS Mojave 10.14.2)

$ git --version
git version 2.18.0

$ docker --version
Docker version 18.09.1, build 4c52b90

$ docker-compose --version
docker-compose version 1.23.2, build 1110ad01

※インストールされていない方はこちら

【随時更新】WebエンジニアがMacBook Proを新調したのでインストールしたアプリを紹介する

開発環境の構築手順

構築手順はこちらの記事を参考にさせて頂きました。

docker-composeでEC-CUBE4の開発環境構築 – Qiita

今後は本番環境とできるだけ近い環境を作ることもあると思うでの、一般的(?)な下記環境を作成します。

  • PHP:7.1
  • MySQL:5.7
  • Apache

※初学者のためになるべく丁寧に解説していますので多少冗長的な部分もあります。

適当なディレクトリに移動

EC−CUBE4のファイルを取得する前準備として「ターミナル」を立ち上げます。

開発環境を作る前に適当なディレクトリを作成するなり移動しましょう。


$ cd ~/
$ mkdir eccube-dev # eccube-devディレクトリを作成
$ cd eccube-dev    # 作成したディレクトリに移動
$ pwd
# カレントディレクトリを確認
/Users/yusuke/eccube-dev

EC−CUBE4のファイル取得

EC−CUBE4のファイルをGitHubから取得します。

EC-CUBE/ec-cube: EC-CUBE is the most popular e-commerce solution in Japan – GitHub

2019/01/19時点で最新のver4.0.1を指定しましょう。


$ git clone -b 4.0.1 https://github.com/EC-CUBE/ec-cube.git
Cloning into 'ec-cube'...
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 257555 (delta 1), reused 5 (delta 1), pack-reused 257548
Receiving objects: 100% (257555/257555), 108.10 MiB | 298.00 KiB/s, done.
Resolving deltas: 100% (187966/187966), done.
Note: checking out 'd8f189cce78e5cca9d4a3478931bae61901c504e'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

git cloneする際に「-b」オプションでブランチやタグを指定してcloneすることができます。

dockerの設定ファイルを追加

取得したらDockerを立ち上げるために設定ファイルを新規作成します。


$ cd ec-cube/

Dockerfileを作成


$ vim Dockerfile
# 下記内容を入力し保存

FROM php:7.1-apache

RUN set -x
RUN sed -i.bak -e "s%http://deb.debian.org/debian%http://ftp.riken.jp/pub/Linux/debian/debian%g" /etc/apt/sources.list

RUN apt-get update
RUN apt-get install -y --no-install-recommends \
    sudo \
    git \
    libxml2-dev \
    unzip \
    wget \
    zlib1g-dev \
    iproute \
    libsqlite3-dev \
    libpq-dev \
    libicu-dev \
    gnupg2
RUN wget -qO- https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get install -y --no-install-recommends nodejs
RUN docker-php-ext-install \
    intl \
    mbstring \
    pdo \
    pdo_sqlite \
    pdo_mysql \
    pdo_pgsql \
    soap \
    xml \
    zip
RUN pecl install xdebug
RUN pecl install apcu
RUN docker-php-ext-enable \
    xdebug \
    apcu \
    opcache \
    && a2enmod rewrite \
    && apt-get clean \
    && rm -rf /tmp/*

RUN curl -sS https://getcomposer.org/installer \
    |  php -- \
    --filename=composer \
    --install-dir=/usr/local/bin \
    # composerの高速化
    && COMPOSER_ALLOW_SUPERUSER=1 composer global require --optimize-autoloader "hirak/prestissimo" \
    && chown www-data /var/www \
    && chmod g+s /var/www/html

COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

CMD ["apache2-foreground"]

docker-compose.ymlを作成

※今回の完成形はこれではないので、手っ取り早く完成させたい方はこちら


$ vim docker-compose.yml
# 下記内容を入力し保存

version: '3'

services:
  db:
    image: mysql:5.7
    container_name: eccube_db
    environment:
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - eccube-db-data:/var/lib/mysql
    ports:
      - 3306:3306

  app:
    build: .
    container_name: eccube
    volumes:
      - .:/var/www/html
    ports:
      - 8080:80
    stdin_open: true
    tty: true
    depends_on:
      - db

volumes:
  eccube-db-data:
    driver: local

entrypoint.shを作成


$ vim entrypoint.sh
# 下記内容を入力し保存

#!/bin/sh
set -e

# www-dataのUIDを変更する
if [ -n "${HOST_UID}" -a "${HOST_UID}" != "$(id -u www-data)" ]; then
    usermod -u "${HOST_UID}" www-data
fi

if [ -e "composer.json" ]; then
    composer install
fi

if [ -e "package.json" ]; then
    npm install
fi

exec "$@"

確認

追加した3ファイルがあるか確認します。


$ tree -L 1
.
├── COPYING
├── Dockerfile         # 1
├── LICENSE.txt
├── Procfile
├── README.md
├── app
├── app.json
├── appveyor.yml
├── bin
├── codeception
├── codeception.sh
├── codeception.yml
├── composer.json
├── composer.lock
├── docker-compose.yml # 2
├── entrypoint.sh      # 3
├── gulpfile.js
├── html
├── index.php
├── maintenance.php
├── package-lock.json
├── package.json
├── phpunit.xml.dist
├── robots.txt
├── src
├── symfony.lock
├── tests
├── var
└── web.config

7 directories, 22 files

サービス開始(起動)

下記コマンドを実行しサービスを開始します。


$ HOST_UID=$(id -u) docker-compose up -d --build
Creating network "ec-cube_default" with the default driver
Creating volume "ec-cube_eccube-db-data" with local driver
Building app
Step 1/16 : FROM php:7.1-apache
 ---> 21aea3c944f5
Step 2/16 : RUN set -x
 ---> Using cache
 ---> f84886341760
Step 3/16 : RUN sed -i.bak -e "s%http://deb.debian.org/debian%http://ftp.riken.jp/pub/Linux/debian/debian%g" /etc/apt/sources.list
 ---> Using cache
 ---> 5846d0ea485b
Step 4/16 : RUN apt-get update
 ---> Using cache
 ---> 252de8ddc99b
Step 5/16 : RUN apt-get install -y --no-install-recommends     sudo     git     libxml2-dev     unzip     wget     zlib1g-dev     iproute     libsqlite3-dev     libpq-dev     libicu-dev     gnupg2
 ---> Using cache
 ---> 675f76441831
Step 6/16 : RUN wget -qO- https://deb.nodesource.com/setup_10.x | bash -
 ---> Using cache
 ---> 75ec6412e7bc
Step 7/16 : RUN apt-get install -y --no-install-recommends nodejs
 ---> Using cache
 ---> 8b47d9e4f85b
Step 8/16 : RUN docker-php-ext-install     intl     mbstring     pdo     pdo_sqlite     pdo_mysql     pdo_pgsql     soap     xml     zip
 ---> Using cache
 ---> b72cae5fb92e
Step 9/16 : RUN pecl install xdebug
 ---> Using cache
 ---> 995115352947
Step 10/16 : RUN pecl install apcu
 ---> Using cache
 ---> cd6e0f33a66c
Step 11/16 : RUN docker-php-ext-enable     xdebug     apcu     opcache     && a2enmod rewrite     && apt-get clean     && rm -rf /tmp/*
 ---> Using cache
 ---> a7d0fa89697b
Step 12/16 : RUN curl -sS https://getcomposer.org/installer     |  php --     --filename=composer     --install-dir=/usr/local/bin     && COMPOSER_ALLOW_SUPERUSER=1 composer global require --optimize-autoloader "hirak/prestissimo"     && chown www-data /var/www     && chmod g+s /var/www/html
 ---> Using cache
 ---> 82b5e334a3ce
Step 13/16 : COPY ./entrypoint.sh /entrypoint.sh
 ---> Using cache
 ---> 584029ed2d46
Step 14/16 : RUN chmod +x /entrypoint.sh
 ---> Using cache
 ---> 35fc277edb3d
Step 15/16 : ENTRYPOINT ["/entrypoint.sh"]
 ---> Using cache
 ---> d835e1d01f23
Step 16/16 : CMD ["apache2-foreground"]
 ---> Using cache
 ---> eac545a091ac
Successfully built eac545a091ac
Successfully tagged ec-cube_app:latest
Creating eccube_db ... done
Creating eccube    ... done

立ち上がるまでにちょっと時間がかかります。

ログを確認してDockerfileの最後に記載しているコマンドが実行されるまで待ちましょう。


$ docker-compose logs
:
:
eccube | [Sat Jan 19 02:03:02.922063 2019] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'

docker-compose.ymlで定義しているコンテナが起動していることを確認してみます。


$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
19ebbba83330        ec-cube_app         "/entrypoint.sh apac…"   23 minutes ago      Up 23 minutes       0.0.0.0:8080->80/tcp                eccube
6c0512d5c76a        mysql:5.7           "docker-entrypoint.s…"   23 minutes ago      Up 23 minutes       0.0.0.0:3306->3306/tcp, 33060/tcp   eccube_db

大丈夫そうですね。

次にeccubeコンテナにアタッチしインストール処理を行います。

MySQL環境を利用するためDatabase Urlの入力だけ必要です。
※入力値は「mysql://root:password@eccube_db/eccube」


$ docker container exec -it eccube bin/console eccube:install

EC-CUBE Installer Interactive Wizard
====================================

 If you prefer to not use this interactive wizard, define the environment valiables as follows:

  $ export APP_ENV=dev
  $ export APP_DEBUG=1
  $ export DATABASE_URL=database_url
  $ export DATABASE_SERVER_VERSION=server_version
  $ export MAILER_URL=mailer_url
  $ export ECCUBE_AUTH_MAGIC=auth_magic
  ... and more
  $ php bin/console eccube:install --no-interaction


 Database Url [sqlite:///var/eccube.db]:
 > mysql://root:password@eccube_db/eccube # DBの接続設定を入力

 Database Server version [auto]:
 >

 Mailer Url [null://localhost]:
 >

 Auth Magic [VB1E2b9UFTVBW7xr]:
 >

 !
 ! [CAUTION] Execute the installation process. All data is initialized.
 !

 Is it OK? (yes/no) [yes]:
 >

 Run doctrine:database:create --if-not-exists...
 Created database `eccube` for connection named default

 Run doctrine:schema:drop --force...

 Dropping database schema...

 [OK] Database schema dropped successfully!


 Run doctrine:schema:create...

 ! [CAUTION] This operation should not be executed in a production environment!

 Creating database schema...

 [OK] Database schema created successfully!


 Run eccube:fixtures:load...
   > Finished Successful!

 Run cache:clear --no-warmup...

 // Clearing the cache for the dev environment with debug
 // true

 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.

 [OK] EC-CUBE installation successful.

インストールが無事に完了したら早速アクセスしてみましょう。

長い間待たされタイムアウトとなりました・・・。

ようやくここからが本題です。

現状把握

レスポンスが遅い原因はホスト側とコンテナ側のファイル共有にあります。

現状把握のためレスポンスタイムを計測してみましょう。

.htaccessに下記記述を追加しタイムアウトを3分まで延ばしてみます。


$ vim .htaccess
# 下記記述を追加
php_value max_execution_time 180

初回アクセスの結果です。

90秒もかかってしまいました。。。

ただ初回はキャッシュ生成に時間かかるので2回目以降は早くなります。

と言っても10秒くらいかかりますね。

これで開発するのはストレスフルなので改善方法を探します。

docker-syncの導入とキャッシュを共有しない

EC−CUBE4に限らずDocker for MacSymfony全般に言える問題と判断しこちらの記事にたどり着きました。

3 ways to get Docker for Mac faster on your Symfony app.

記事で紹介されている手順を一通り試しました結果、結論としては「docker-syncを導入し、キャッシュディレクトリは除外する」です。

docker-syncの概要やインストールはこちらの記事が参考になります。

docker-syncでホスト-コンテナ間を爆速で同期する – Qiita

インストールが完了したらdocker-sync.ymlを新規作成します。


$ docker-compose down # 一旦サービス停止
Stopping eccube    ... done
Stopping eccube_db ... done
Removing eccube    ... done
Removing eccube_db ... done
Removing network ec-cube_default

$ vim docker-sync.yml # 新規作成
# 下記内容を入力し保存

version: '2'
syncs:
  eccube-sync:
    src: '.'
    sync_host_ip: '127.0.0.1'
    sync_host_port: '5000'
    sync_strategy: 'native_osx'
    sync_excludes: ['.git', '.gitignore', 'node_modules', 'var']

docker-compose.ymlvolumes部分を修正します。


version: '3'

services:
  db:
    image: mysql:5.7
    container_name: eccube_db
    environment:
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - eccube-db-data:/var/lib/mysql
    ports:
      - 3306:3306

  app:
    build: .
    container_name: eccube
    volumes:
      - eccube-sync:/var/www/html # 修正
    ports:
      - 8080:80
    stdin_open: true
    tty: true
    depends_on:
      - db

volumes:
  # 追加
  eccube-sync:
    external: true
  eccube-db-data:
    driver: local

準備が出来たので実行します。


$ docker-sync start
          ok  Starting native_osx for sync eccube-sync
doing initial sync with unison
Unison 2.51.2 (ocaml 4.06.1): Contacting server...
Looking for changes
Reconciling changes
Propagating updates
UNISON 2.51.2 (OCAML 4.06.1) started propagating changes at 15:01:46.59 on 19 Jan 2019
[BGN] Copying .coveralls.yml from /host_sync to /app_sync
:
:
real	1m 8.25s
user	0m 1.94s
sys	0m 5.72s
chown ing file to uid 0
5f56df335f9ea35ee561f51e8e23324d0c4dc4c36db47c9fd8e0bf69973f881a
     success  Sync container started
     success  Starting Docker-Sync in the background

サービスを再度開始します。


$ HOST_UID=$(id -u) docker-compose up -d --build
:
:
Successfully tagged ec-cube_app:latest
Creating eccube_db ... done
Creating eccube    ... done

無事立ち上がったらアクセスしてみましょう。

初回アクセスは2〜3秒ほどかかりましたが、2回目以降は0.5秒ほどと決して早くはないですが実用に耐えるレベルにまで改善されました。

それでも改善しないなら?

前述のdocker-sync導入後も改善しない、使っているうちに遅くなっているケースが何度ありました。(4〜5秒くらいかかりました)

その場合Docker for Macに割り当てるリソースを増やす、Docker for Macを再起動することで改善しました。

メニューバーのアイコンから設定や再起動ができます。

歴史が浅くまだ成熟していない技術なので今後に期待ですね。ではまた。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ABOUTこの記事をかいた人

Yusuke Ito

■25歳時に異業種からWeb系企業に転職、現在はフリーランスとして活動 ■バックエンド(PHP、Ruby、Python)がメイン、フロントエンドも少々 ※ECサイトの開発が得意 ■筋トレ、ゴルフ、読書、ポケモンが趣味 ■エンジニアとしてのキャリア、アプリ開発、書評をメインに発信しています。