Dockerfileリーディング PHP-FPM公式イメージ(2)

2019/10/14/

前回記事からの続きです。引き続きPHPの公式イメージを読み解いていきます。
Dockerイメージ6層目(90行目)から読み進めていきます。

Dockerイメージ 6層目

COPY docker-php-source /usr/local/bin/

phpのソースを展開するスクリプトを/usr/local/binにコピーします。

Dockerイメージ 7層目

Dockerイメージ 7層目(1/6)

RUN set -eux; \
	apk add --no-cache --virtual .build-deps \
		$PHPIZE_DEPS \
		argon2-dev \
		coreutils \
		curl-dev \
		libedit-dev \
		libsodium-dev \
		libxml2-dev \
		openssl-dev \
		sqlite-dev \
	; \
	\
	export CFLAGS="$PHP_CFLAGS" \
		CPPFLAGS="$PHP_CPPFLAGS" \
		LDFLAGS="$PHP_LDFLAGS" \
	; \
	docker-php-source extract; \

★続く

91-101行目: PHPをビルドする際に必要なパッケージを導入し、
104-107行目: ビルドオプションを設定後、
108行目: PHPのソースファイルを展開しています。

Dockerイメージ 7層目(2/4)

	cd /usr/src/php; \
	gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
	./configure \
		--build="$gnuArch" \
		--with-config-file-path="$PHP_INI_DIR" \
		--with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \
		\
# make sure invalid --configure-flags are fatal errors intead of just warnings
		--enable-option-checking=fatal \
		\
# https://github.com/docker-library/php/issues/439
		--with-mhash \
		\
# --enable-ftp is included here because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236)
		--enable-ftp \
# --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)
		--enable-mbstring \
# --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself)
		--enable-mysqlnd \
# https://wiki.php.net/rfc/argon2_password_hash (7.2+)
		--with-password-argon2 \
# https://wiki.php.net/rfc/libsodium
		--with-sodium=shared \
		\
		--with-curl \
		--with-libedit \
		--with-openssl \
		--with-zlib \
		\

★ 続く

109行目 : 展開したソースディレクトリに入り、
111-137行目: ソースファイルを精査し、Makefileを作成しています。

こちらのサイトにソースファイルからビルドする手順と説明が体系的に記載されており、非常に参考になります。

コンパイル (configure) オプションについては、説明を割愛します。Dockerfile内の説明にもありますが、あとから導入が困難なものは基本的に有効化されているようです。

Dockerイメージ 7層目(3/4)

# bundled pcre does not support JIT on s390x
# https://manpages.debian.org/stretch/libpcre3-dev/pcrejit.3.en.html#AVAILABILITY_OF_JIT_SUPPORT
		$(test "$gnuArch" = 's390x-linux-gnu' && echo '--without-pcre-jit') \
		\
		${PHP_EXTRA_CONFIGURE_ARGS:-} \
	; \
	make -j "$(nproc)"; \
	find -type f -name '*.a' -delete; \
	make install; \
	find /usr/local/bin /usr/local/sbin -type f -perm +0111 -exec strip --strip-all '{}' + || true; \
	make clean; \
	\
# https://github.com/docker-library/php/issues/692 (copy default example "php.ini" files somewhere easily discoverable)
	cp -v php.ini-* "$PHP_INI_DIR/"; \
	\
	cd /; \
	docker-php-source delete; \
	\

★続く

140行目: s390xではpcre-jitをサポートしていないようで、s390xの場合には–without-pcre-jitオプションをつけています。

s390xはIBMのCPUアーキテクチャで、pcre-jitはこちらのページがわかりやすいです。

144行目: makeコマンドでMakefileを生成しています。

makeの-jオプションについてはこちらに記載があるように、コンパイル時の並列性を指定できます。この中では、nprocでcpuコア数を取得して引数として与えています。

145行目 : 静的ライブラリ(.a)を削除し、
146行目: make installでビルドしてから、
147行目: シンボルファイルを削除しています。

シンボルファイルについてはこちらがわかりやすいです。

148行目: ビルド時に生成されたファイルを削除
149行目: PHPデフォルトのphp.ini-development, php.ini-productionなどのファイルを${PHP_INI_DIR}にコピー

コメントに記載のあるisuueからもわかるように、デフォルトのphp.iniをそのまま使用すると、 display_errors がonのままとなるようで、production環境では望ましくないのではないかという意見から、設定変更が容易になるように、デフォルトの設定ファイルのテンプレートをコピーしているみたいです。ですので、production環境で利用する場合は、設定ファイルをコピーする必要があることに留意します。

154行目: phpのソースを削除するスクリプト を利用して、ソースファイルを削除しています。

Dockerイメージ 7層目(4/4)

	runDeps="$( \
		scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
			| tr ',' '\n' \
			| sort -u \
			| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
	)"; \
	apk add --no-cache $runDeps; \
	\
	apk del --no-network .build-deps; \
	\
# update pecl channel definitions https://github.com/docker-library/php/issues/443
	pecl update-channels; \
	rm -rf /tmp/pear ~/.pearrc; \
# smoke test
	php --version

156-161行目: phpに依存されており、かつ共有ライブラリを利用するパッケージを変数に設定し、
162行目: apkに引数として渡してインストールしています。

runDeps変数を設定する箇所では、/usr/local配下について、scanelfコマンドを利用して、バイナリファイルを読み込み/整形しています。trコマンドで、カンマ(,)を改行(\n)に変換し、sortコマンドで重複行を省いた後、共有ライブラリパス(/usr/local/lib)で実行した結果が正常終了(0)なら次の処理へ(next)、それ以外なら、runDeps変数に設定という処理になっています。

scanelfコマンドのmanページはこちらに、elfについてはこちらに、
awkコマンドについてはこちら、awkコマンドで利用するsystem関数はこちらに記載があります。

164行目: ビルド時に利用したパッケージを削除します。

167-168行目: peclのアップデートを実施します。

peclについては、こちらがわかりやすいです。issueでは、ビルド時にはエラーが出ていなかったが、ビルド後にpeclアップデートしてねのwarnigが出たので入れたよ(超意訳)的なことが書いてあります。

170行目: php –versionコマンドで動作することを確認しています。