Symfony 2.7が動くDockerイメージを作ってみた


Symfony 2.7を使って開発しているシステムがある。今はVagrantで自作したCentOS 7.1のボックスを使って開発環境を構築しているが、それをDockerに置き換えるにはどのようにすればいいのかと思って、試しにDockerイメージを作ってみた。

試した環境はmacOS SierraのDocker for Mac。

$ docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Tue Mar 28 00:40:02 2017
 OS/Arch:      darwin/amd64

Server:
 Version:      17.03.1-ce
 API version:  1.27 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Fri Mar 24 00:00:50 2017
 OS/Arch:      linux/amd64
 Experimental: true

Dockerfile

FROM centos:7.3.1611

# UPDATE & EPEL
RUN yum -y update && yum install -y epel-release

# LANG
RUN localedef -v -c -i ja_JP -f UTF-8 ja_JP.UTF-8 || true
RUN unlink /etc/localtime && ln -s /usr/share/zoneinfo/Japan /etc/localtime
ENV LANG ja_JP.UTF-8

# Oracle Instant Client
COPY files/usr/local/src/oracle-instantclient /usr/local/src/oracle-instantclient/
RUN yum install -y \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-jdbc-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-odbc-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm
COPY files/etc/profile.d/oracle.sh /etc/profile.d/oracle.sh
COPY files/etc/ld.so.conf.d/oracle12c.conf /etc/ld.so.conf.d/oracle12c.conf

# PHP
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
 && yum install -y --enablerepo="remi,remi-php56" \
        php \
        php-intl \
        php-mbstring \
        php-oci8 \
        php-opcache \
        php-pdo \
        php-process \
        php-xml
COPY files/etc/php.d/*.ini /etc/php.d/

# CLEAN UP
RUN yum clean all

# USER/GROUP
RUN groupadd -r symfony && useradd -r -g symfony symfony
USER symfony

# RUN
WORKDIR /app
CMD ["bin/docker-run.sh"]

ディレクトリ構成

$ tree . 
.
├── Dockerfile
└── files
    ├── etc
    │   ├── ld.so.conf.d
    │   │   └── oracle12c.conf
    │   ├── php.d
    │   │   ├── 00-timezone.ini
    │   │   └── 20-mbstring.ini
    │   └── profile.d
    │       └── oracle.sh
    └── usr
        └── local
            └── src
                └── oracle-instantclient
                    ├── oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm
                    ├── oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm
                    ├── oracle-instantclient12.1-jdbc-12.1.0.2.0-1.x86_64.rpm
                    ├── oracle-instantclient12.1-odbc-12.1.0.2.0-1.x86_64.rpm
                    └── oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm

9 directories, 10 files

解説

FROM centos:7.3.1611

ベースイメージはCentOS 7.3。最初は今の環境に合わせてCentOS 7.1にしたが、yum updateの実行で失敗したので7.3に変更した。

# UPDATE & EPEL
RUN yum -y update && yum install -y epel-release

パッケージを最新にし、EPELを利用できるようにする。

# LANG
RUN localedef -v -c -i ja_JP -f UTF-8 ja_JP.UTF-8 || true
RUN unlink /etc/localtime && ln -s /usr/share/zoneinfo/Japan /etc/localtime
ENV LANG ja_JP.UTF-8

言語設定を日本語に変更。localedefコマンドでは終了コードが0にならなかったため、trueコマンドを実行して0になるようにした。

2行目のRUNでtimezoneをAsia/Tokyoに変更し、環境変数LANGをja_JP.UTF-8に変更する。

# Oracle Instant Client
COPY files/usr/local/src/oracle-instantclient /usr/local/src/oracle-instantclient/
RUN yum install -y \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-jdbc-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-odbc-12.1.0.2.0-1.x86_64.rpm \
        /usr/local/src/oracle-instantclient/oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm
COPY files/etc/profile.d/oracle.sh /etc/profile.d/oracle.sh
COPY files/etc/ld.so.conf.d/oracle12c.conf /etc/ld.so.conf.d/oracle12c.conf

DBがOracleであるため、Instant Clientのインストールと設定を行う。

$ cat files/etc/profile.d/oracle.sh
export ORACLE_HOME=/usr/lib/oracle/12.1/client64
export NLS_LANG=JAPANESE_JAPAN.AL32UTF8

export PATH=${PATH+"$PATH:"}$ORACLE_HOME/bin
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH+"$LD_LIBRARY_PATH:"}$ORACLE_HOME/lib

files/etc/profile.d/oracle.shは、LinuxアカウントにORACLE_HOMEなどの環境変数を設定するためのスクリプト。

$ cat files/etc/ld.so.conf.d/oracle12c.conf
/usr/lib/oracle/12.1/client64/lib

/etc/ld.so.conf.d/oracle12c.confは、Instant Clientの共有ライブラリを追加する設定ファイル。

# PHP
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
 && yum install -y --enablerepo="remi,remi-php56" \
        php \
        php-intl \
        php-mbstring \
        php-oci8 \
        php-opcache \
        php-pdo \
        php-process \
        php-xml
COPY files/etc/php.d/*.ini /etc/php.d/

phpはremiのパッケージを使用する。remiのパッケージを使用するにはEPELが必要であるため、先にEPELをインストールした。

$ cat files/etc/php.d/00-timezone.ini
date.timezone = Asia/Tokyo
$ cat files/etc/php.d/20-mbstring.ini
; Enable mbstring extension module
extension=mbstring.so

mbstring.language=Japanese

/etc/php.d/にコピーするファイルはtimezoneを設定する00-timezone.iniとmbstringの設定をする20-mbstring.iniの2つ。

# CLEAN UP
RUN yum clean all

以後はyumを使用しないので、キャッシュをクリア。

# USER/GROUP
RUN groupadd -r symfony && useradd -r -g symfony symfony
USER symfony

ユーザを追加して、以後のコマンドを所定のアカウントで実行するように変更する。

# RUN
WORKDIR /app
CMD ["bin/docker-run.sh"]

作業ディレクトリを設定し、コンテナ起動時に所定のスクリプトを実行するようにする。

このDockerfileを使って、Symfony 2.7のプロジェクトが実行できるイメージを作成する。

docker build -t symfony27 ./

確認

symfonyコマンドで2.7のプロジェクトを作成する。

symfony new symfony27-test 2.7

コンテナで実行するスクリプトを作成し、実行可能にする。

cat <<''EOT' > symfony27-test/bin/docker-run.sh
#!/bin/sh
set -eu

php app/console server:run 0.0.0.0:8000
EOT
chmod 755 symfony27-test/bin/docker-run.sh

dockerコンテナを起動する。

docker run -d -p 8000:8000 -v $(pwd)/symfony27-test:/app symfony27

ブラウザでlocalhost:8000にアクセスしてページが表示されることを確認する。

試してみて

少し試してみて気になった点を2つ。

ひとつはキャッシュのクリア。今までのように

php app/console cache:clear

コマンドを使ってキャッシュをクリアすると、コマンドを実行した環境の絶対パスを含むキャッシュが作成されるようで、Symfonyのプロファイラでログを確認すると

ERROR - The template "::base.html.twig" contains an error: Warning: file_get_contents(/Users/te2u/Inbox/docker/proj/symfony27-test/app/Resources/views/base.html.twig): failed to open stream: No such file or directory

ファイルが見つからないというエラーになる。

これを解決するには

rm -rf app/cache/dev

ディレクトリを直接削除するか

php app/console cache:clear --no-warmup

キャッシュクリアでno-warmupオプションをつけて実行する。

もうひとつはMacでの実行の遅さ。

どうやらMacの環境でVolumeを設定して実行すると遅くなるらしく、それを解決するのにdocker-syncがある。ただ今回は、Dockerのイメージを作ってみることが目的だったので、こちらは試していない。

参考