【Docker】Apache と Perl を別コンテナで動かす
業務において Movable Type の開発案件を引き受けることがあるのですが、Docker 環境で開発するにあたり Apache と Perl でコンテナを分けることで、環境の軽量化を図りたいと思いました。
今回は軽量化を実現するために私がいろいろ調べて実践した方法をご紹介します。
ここではあくまで開発環境を構築するための方法をご紹介しています。
セキュリティ的にはベストでないものもありますので、商用環境にそのまま利用しないでください。
この記事では Apache と Perl の部分のみ取り扱います。
Movable Type に必要な設定や、データベース・PHP のコンテナなどは省略します。
ファイル
docker-compose.yaml
Perl と Apache は別コンテナで稼働させます。 また、httpd は一番軽量な Alpine Linux ベースのものを使用します。
version: '3'
services:
perl:
build:
context: ./docker/perl
volumes:
- type: bind
source: ./example
target: /usr/local/apache2/vhosts/localhost
httpd:
build:
context: ./docker/httpd
volumes:
- type: bind
source: ./docker/httpd/httpd-vhosts.conf
target: /usr/local/apache2/conf/extra/httpd-vhosts.conf
- type: bind
source: ./example
target: /usr/local/apache2/vhosts/localhost
ports:
- "80:80"
Perl コンテナ
マルチステージビルドを採用します。
FROM perl:5.36.0-threaded-bullseye AS build
RUN apt update
COPY cpanfile cpanfile
RUN cpanm --notest --installdeps .
FROM perl:5.36.0-slim-threaded-bullseye AS deploy
RUN apt update \
&& apt install -y fcgiwrap spawn-fcgi
COPY --from=build /usr/local/lib/perl5 /usr/local/lib/perl5
ARG FCGI_PORT=9000
RUN sed -ie "s/^FCGI_SOCKET=.*$/FCGI_PORT=\"${FCGI_PORT}\"\nFCGI_ADDR=\"0.0.0.0\"/g" /etc/init.d/fcgiwrap
EXPOSE ${FCGI_PORT}
CMD ["bash", "-c", "service fcgiwrap start && tail -f /dev/null"]
ビルドステージでは、必要なモジュールを cpanfile からインストールします。 デプロイステージでは、ビルドツールの入っていない軽量な Perl イメージを元にして、ビルドステージからインストールしたモジュールをコピーし、Perl を CGI 化して動かすためのセットアップをします。
マルチステージビルドに関しては、こちらの Gist を参考にしました。
試しにモジュールを一つ入れてみることにします。
requires 'HTML::Entities';
Apache コンテナ
<VirtualHost *:80>
ServerName localhost
DocumentRoot "/usr/local/apache2/vhosts/localhost/htdocs"
Alias /cgi-bin/ "/usr/local/apache2/vhosts/localhost/cgi-bin/"
<Directory "/usr/local/apache2/vhosts/localhost/htdocs">
Options None
AllowOverride None
Require all granted
DirectoryIndex index.html
</Directory>
<Directory "/usr/local/apache2/vhosts/localhost/cgi-bin">
AllowOverride None
Options None
Require all granted
<FilesMatch "\.cgi$">
ProxyFCGIBackendType GENERIC
SetHandler "proxy:fcgi://perl:9000"
</FilesMatch>
</Directory>
</VirtualHost>
ファイル名が .cgi
で終わる場合にプロキシを設定し、Perl コンテナの Perl を利用するようにします。
FROM httpd:2.4.54-alpine3.17
RUN sed -i -Ee 's/#(LoadModule proxy_module modules\/mod_proxy.so)/\1/g' /usr/local/apache2/conf/httpd.conf \
&& sed -i -Ee 's/#(LoadModule proxy_fcgi_module modules\/mod_proxy_fcgi.so)/\1/g' /usr/local/apache2/conf/httpd.conf \
&& sed -i -Ee 's/#(Include conf\/extra\/httpd-vhosts.conf)/\1/g' /usr/local/apache2/conf/httpd.conf
プロキシの設定を有効にします。
サンプルファイル
example/cgi-bin/index.cgi
に Perl のバージョンを表示するファイルを置きます。
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
print "Content-type: text/html\n\n";
print "Hello World!<br>";
print "Perl Version: $^V<br>";
WSL 等の Linux 上にファイルを置いている場合は実行権限を付与してください。
chmod a+x example/cgi-bin/index.cgi
example/htdocs/index.html
にもサンプルファイルを置きます。
Hello HTML!
動作確認
ファイルを作成したらコンテナを立ち上げて動作確認をします。
docker-compose up -d --build
http://localhost/index.html
にアクセスしてHello HTML!
と表示されることを確認します。http://localhost/cgi-bin/index.cgi
にアクセスして以下のように表示されることを確認します。
Hello World!
Perl Version: v5.36.0
動作確認後はコンテナを終了します。
docker-compose down --remove-orphans -v