AlpineLinux on Docker × Laravelが遅い話


開発環境だけアプリがめちゃくちゃ重い

新しいチームに配属されて最初の感想です。

本番ではめちゃめちゃ早いのに開発環境がむちゃくちゃに遅い。

DXが最悪だったので原因を調査したところAlpineからCentOSに乗り換えたら3倍ぐらい早くなったという話です。


ベンチマーク

長々した説明は置いといて、結論から言うと「よくわからないがdockerで動かしているphpが異常に重い」ということだけがわかった。

これアプリケーションコードが重いというわけではなく、Alpine Linux on Docker で動いているLaravelが全体的に処理が遅いという体感があったので実際に計測してみた。

以下のPHPコードをAlpineとCentOSで動かして比較してみる。CentOSのDockerfileはPHP入れる処理だけなので省略。

test.php
<?php
ini_set('memory_limit', '-1');
function benchmark($i) {

    if($i ==! 0) {
        benchmark($i - 1);
    }
    function() { return sha1("test${i}");};
    function() { return md5("test${i}");};
}

$time_start = microtime(true);
foreach (range(1, 10000) as $i) {
    benchmark($i);
}

$time = microtime(true) - $time_start;
echo "{$time} sec";

コードの内容は至って簡単で、メモリ上限を無くし再帰的処理でハッシュを取得していくだけ。

 /t/test  docker run --rm -v /tmp/test/test.php:/test.php centos-php php /test.php
8.2858350276947 sec
/t/test  docker run --rm -v /tmp/test/test.php:/test.php centos-php php /test.php
8.2832388877869 sec
/t/test  docker run --rm -v /tmp/test/test.php:/test.php centos-php php /test.php
8.2994618415833 sec

/t/test  docker run --rm -v /tmp/test/test.php:/test.php php:7.4.1-fpm-alpine php /test.php
8.1350269317627 sec
/t/test  docker run --rm -v /tmp/test/test.php:/test.php php:7.4.1-fpm-alpine php /test.php
8.0924451351166 sec
/t/test  docker run --rm -v /tmp/test/test.php:/test.php php:7.4.1-fpm-alpine php /test.php
8.0950059890747 sec

これは特に問題なさそう(むしろAlpineの方が早い

Laravelでのベンチマーク

実際にLaravelで測定した時の結果を貼っていく

用意が面倒だったので開発環境での弊社サービスのLPページを測定対象とする

alpineでのdockerfileは以下の通り

FROM php:7.3-fpm-alpine
ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php

RUN apk --no-cache update \
&& apk add --no-cache $PHPIZE_DEPS postgresql-dev libpng-dev libjpeg-turbo-dev icu-dev \
&& docker-php-ext-configure gd --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/ \
&& docker-php-ext-configure intl --enable-intl \
&& docker-php-ext-install exif pdo_pgsql gd intl opcache pcntl
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug

WORKDIR /var/www/html

対してCentOSベースのDockerfileは以下の通り


FROM centos:7.5.1804

#locale 追加
RUN sed -i -e '/override_install_langs/s/$/,ja_JP.utf8/g' /etc/yum.conf

RUN curl -sL https://rpm.nodesource.com/setup_10.x | bash - \
  && yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
  https://s3-ap-northeast-1.amazonaws.com/sen-infra/rpms/centos/7/x86_64/pgdg-centos10-10-2.noarch.rpm \
  && yum install -y postgresql10 \
  nodejs \
  zlib-devel \
  glibc-common \
  make \
  libpng-devel \
  cronie \
  && yum install -y --enablerepo=remi,remi-php73 \
  php \
  php-opcache \
  php-mbstring \
  php-pdo \
  php-pecl-memcache \
  php-pecl-memcached \
  php-pecl-redis \
  php-pecl-imagick \
  php-mcrypt \
  php-mysqlnd \
  php-xml \
  php-gd \
  php-devel \
  php-pgsql \
  php-pecl-ssh2 \
  php-process \
  php-intl \
  php-pear \
  php-pecl-apcu \
  php-pecl-apcu-bc \
  php-pecl-zip \
  php-fpm \
  && rm -rf /var/cache/yum/* \
  && yum clean all


COPY ./php-fpm.conf /etc/php-fpm.conf

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin \
  && mv /usr/local/bin/composer.phar  /usr/local/bin/composer \
  && composer global require hirak/prestissimo

WORKDIR /var/www/html

CMD ["/usr/sbin/php-fpm","-F","-y","/etc/php-fpm.conf"]

LPページなのでミドルウェアもプロパイダーも挟んではいない(はず

まずはAlpineから

yoshiken@yskn:~/Git/sen/album$ time curl localhost
real    0m0.392s
user    0m0.013s
sys 0m0.004s
yoshiken@yskn:~/Git/sen/album$ time curl localhost
real    0m0.392s
user    0m0.013s
sys 0m0.000s
yoshiken@yskn:~/Git/sen/album$ time curl localhost
real    0m0.409s
user    0m0.012s
sys 0m0.004s

平均して約0.4sec

対してCentOSベースでは


yoshiken@yskn:~/Git/sen/album$ time curl localhost
real    0m0.064s
user    0m0.007s
sys 0m0.007s
yoshiken@yskn:~/Git/sen/album$ time curl localhost
real    0m0.062s
user    0m0.003s
sys 0m0.012s
yoshiken@yskn:~/Git/sen/album$ time curl localhost
real    0m0.052s
user    0m0.014s
sys 0m0.000s

平均して0.06sec前後といったところ。

よくわからん

ここまで書いていてなんだが、何故PHPとしてのパフォーマンスが上のAlpineがLaravelを介すると急激に遅くなるかわかっていない。

調べた感じAlpineだと遅いという点では色々困ってる人が見当たってるが、具体的な解決策、根本原因は未だ解明されていない。

[5.2] Slow response times running within a php-7 Docker container · Issue #12228 · laravel/framework

php - PHP7 + Laravel +Nginx is terribly slow on Docker - Stack Overflow

AlpineでPythonが遅くなるのはAlpineの独自パッケージによる差分が原因とされているが、PHPでは最初のベンチマークの時点では大きな乖離がなかった。
https://superuser.com/questions/1219609/why-is-the-alpine-docker-image-over-50-slower-than-the-ubuntu-image

言いたいこと

いろんな記事で「DockerとAlpine使って爆速で環境構築!!!」という文章を見かけるが、一旦待ってほしい。

ローカル環境では急速なスケールをする必要もないのでイメージが大きかろうが特に問題は無いわけであって、重要なのは使うフレームワークや言語に最適化された環境である。

もし、本番環境でコンテナ運用して開発と同じイメージ(特にAlpineLinux)を使用しているという状況であれば、まず一旦そのイメージの妥当性を確認すべきなのかなと。
他のディストリビューションをベースにした場合との速度計測をして正しい技術選定を行った方がよいのではと思う次第。