経緯
拠所無き事情により PHP8.1 + SQLite の検証環境が必要になったため、 Docker で構築することにしました。ついでに、機能は少なくて良いので起動を軽くするために Ubuntu 環境で作ってみることにしました。
成果物
早速ですが、作成したものがこちらになります。
compose.yml
version: '3.9'
services:
web:
build:
context: ./apache/docker
dockerfile: Dockerfile
args:
WEB_ROOT_DIRECTORY: $WEB_ROOT_DIRECTORY
WEB_CONTAINER_PORTNUM: $WEB_CONTAINER_PORTNUM
PHP_VERSION: $PHP_VERSION
volumes:
# workspace
- ./workspace:/workspace
# docker settings template
- ./template:/template
# apache log
- ./apache/log:/var/log/apache2
# php ini
- ./php/ini/php.ini:/etc/php/${PHP_VERSION}/fpm/php.ini
# error log
- ./php/error_log:/var/log/php
# SSL
- ./cert:/etc/ssl/private
tty: true
ports:
- "$WEB_HOST_PORTNUM:$WEB_CONTAINER_PORTNUM"
- "$WEB_HOST_PORTSSL:$WEB_CONTAINER_PORTSSL"
- "$WEB_HOST_PORTSSH:$WEB_CONTAINER_PORTSSH"
entrypoint: bash -c "bash /workspace/entrypoint.sh $WEB_ROOT_DIRECTORY $WEB_DOMAIN $WEB_HOST_PORTNUM $WEB_CONTAINER_PORTNUM $WEB_HOST_PORTSSL $WEB_CONTAINER_PORTSSL $WEB_SSH_USER $WEB_SSH_PASSWORD $PHP_VERSION && /bin/bash"
Ambergrease (Almalinux) をベースにしているので骨格が同じですね。
Dockerfile
FROM ubuntu:latest
# args
ARG WEB_ROOT_DIRECTORY
ARG WEB_CONTAINER_PORTNUM
ARG PHP_VERSION
# install tzdata without interactive
ENV DEBIAN_FRONTEND=noninteractive
# apt update & install
RUN apt update \
&& apt install -y sudo \
vim \
less \
procps \
# network ss (instaed of netstat)
iproute2 \
# apache
apache2 \
# zip
zip \
unzip \
# SSL
openssl \
# SSH
openssh-server \
# git
git \
# pasword
passwd \
# Set Timezone
tzdata \
# Set local to jp.
language-pack-ja \
&& update-locale LANG=ja_JP.UTF-8 \
# cleaning
&& apt clean \
&& rm -rf /var/lib/apt/lists/*
# set env
ENV TZ="Asia/Tokyo" \
LANG="ja_JP.UTF-8" \
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# install php
RUN apt update \
&& apt install -y php \
libapache2-mod-php \
php-fpm \
php-common \
php-mbstring \
php-xmlrpc \
php-gd \
php-xml \
php-cli \
php-zip \
php-curl \
php-imagick \
# SQLite
php-sqlite3 \
# MySQL
#php-pdo \
#php-mysql \
# Xdebug
php-xdebug \
# cleaning
&& apt clean \
&& rm -rf /var/lib/apt/lists/*
# composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& mv composer.phar /usr/local/bin/composer
# PHP
RUN mkdir -p /run/php
RUN chown www-data:www-data /run/php
# php log
RUN mkdir /var/log/php
RUN chown www-data /var/log/php
RUN chmod 755 /var/log/php
# SSL
RUN mkdir -p /etc/ssl/private
# volume directory
RUN mkdir -p /template
RUN mkdir -p /var/www/${WEB_ROOT_DIRECTORY}
RUN mkdir -p /var/www/${WEB_ROOT_DIRECTORY}/web
RUN mkdir -p /workspace
# SSH
RUN mkdir -p /var/run/sshd
冒頭の通り、 Ubuntu にOSを差し替えてパッケージも Ubuntu 系のものに差し替え。 Ambergrease では統合的な検証環境を目指したためパッケージもモリモリでしたが今回は逆に削ぎ落とす方向で調整。
それでも日付を日本時間にするために tzdata
を入れたり、ロケールを日本語UTF-8にしたりしていますが。
やや嵌まったのがこの tzdata
でして、普通にパッケージをインストールすると途中でタイムゾーンを対話式で聞いてきます。手動インストールの場合はそのまま番号を入力してインストールを進めることができますが、 Docker で一括インストールの場合は人間の入力が介在しないためにビルドが途中で止まってしまいます。
そこで、 apt install
を走らせる直前に環境変数として
ENV DEBIAN_FRONTEND=noninteractive
この一行を入れることで対話式に入ることを回避しています。ちなみに、これと同種の問題は CI/CD するときにも発生するため、各種 CI/CD 用の YAML ファイルでやはり環境変数をセットして回避するTipsが必要になります。
それから、 Apache の実行ユーザが RedHat 系では httpd
でしたが、 Ubuntu では www-data
なのでこれも初見では見逃しがちなので注意。
entrypoint.sh
#!/bin/bash
# gen key & certificate
## localhost
openssl req -new -newkey rsa:2048 -nodes \
-out /etc/pki/tls/certs/localhost.csr \
-keyout /etc/pki/tls/private/localhost.key \
-subj "/C=/ST=/L=/O=/OU=/CN=www.example.com"
openssl x509 -days 365 -req \
-signkey /etc/pki/tls/private/localhost.key \
-in /etc/pki/tls/certs/localhost.csr \
-out /etc/pki/tls/certs/localhost.crt
## .env domain
openssl req -new -newkey rsa:2048 -nodes \
-out /etc/ssl/private/server.csr \
-keyout /etc/ssl/private/server.key \
-subj "/C=/ST=/L=/O=/OU=/CN=*.${2}"
openssl x509 -days 365 -req \
-signkey /etc/ssl/private/server.key \
-in /etc/ssl/private/server.csr \
-out /etc/ssl/private/server.crt
# setting file replace and copy
sed -e "s/WEB_ROOT_DIRECTORY/${1}/gi" \
-e "s/WEB_DOMAIN/${2}/gi" \
-e "s/WEB_HOST_PORTNUM/${3}/gi" \
-e "s/WEB_CONTAINER_PORTNUM/${4}/gi" \
-e "s/WEB_HOST_PORTSSL/${5}/gi" \
-e "s/WEB_CONTAINER_PORTSSL/${6}/gi" \
/template/apache/apache_vh.conf > /etc/apache2/sites-available/${1}.conf
sed -e "s/WEB_ROOT_DIRECTORY/${1}/gi" \
-e "s/WEB_DOMAIN/${2}/gi" \
-e "s/WEB_HOST_PORTNUM/${3}/gi" \
-e "s/WEB_CONTAINER_PORTNUM/${4}/gi" \
-e "s/WEB_HOST_PORTSSL/${5}/gi" \
-e "s/WEB_CONTAINER_PORTSSL/${6}/gi" \
/template/apache/apache_vh_ssl.conf > /etc/apache2/sites-available/${1}_ssl.conf
cp /template/apache/ssl.conf /etc/apache2/mods-available/ssl.conf
# apache module enable
a2enmod ssl proxy_fcgi setenvif rewrite
# apache conf enable
echo ServerName www.example.com:${4} >> /etc/apache2/conf-available/example.conf
a2enconf example php${9}-fpm
# apache cirtual site enable
a2ensite ${1} ${1}_ssl
# apache service start
service apache2 start
# PHP
/usr/sbin/php-fpm${11} &
# SSH
sed -ri 's/^#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
echo "${7}:${8}" | /usr/sbin/chpasswd
ssh-keygen -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key <<< y
/usr/sbin/sshd -D &
SSL証明書発行、 Apache の設定作成と起動、 PHP を php-fpm で起動、最後に SSH サーバを起動して SFTP を受け付けられるようにしておきます。これも基本 Ambergrease をベースにしていますね。
Almalinux との差異で言うと、以下の点でしょうか。
- Apache の設定ファイル
- Ubuntu では Apache の設定ファイルの構成が異なっており、特に
XXXXX-available
とXXXXX-enabled
があることに戸惑う XXXXX-enabled
はXXXXX-available
の同名設定ファイルへのシンボリックリンクになっているので、基本XXXXX-available
に設定ファイルを持って行けば問題なさそう- シンボリックリンクは
a2enconf
,a2ensite
辺りのコマンドを叩くとconf-enabled
やsites-enabled
に作られる模様
- Ubuntu では Apache の設定ファイルの構成が異なっており、特に
- SSH
root
ログインを許可する……としたいのですが、コメントに記載されている初期値がprohibit-password
なので Almalinux と同じコマンドだと文字列不一致を起こして上手く置換されないですね。地味に初見で「あれ?」となるポイント。
その他
php.ini
; XDEBUG ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xdebug.mode=debug,coverage
xdebug.client_host.=host.docker.internal
xdebug.client_port=9000
xdebug.remote_handler="dbgp"
php.ini
に Xdebug 関係の設定を追記したのですが、どうも上手くカバレッジが取れないので (でも上記の設定で phpinfo();
すると Xdebug は読み込まれているし Coverage ✔ enabled
, Step Debugger ✔ enabled
になる)、 PHP プロジェクトの方で XDEBUG_MODE=coverage phpunit --coverage-html coverage
と最初に環境変数をセットして力技で回避するようにしました (詳細は別記事: Docker 上の Ubuntu + PHP8.1 環境で PHPUnit のコードカバレッジを得るまで にて)。
余談
今回は PHP に特化した環境、ということで Elephpant こと象に関する事項で……コンテナなので四角い箱のイメージ、も合わせてインドのムンバイ、エレファンタ石窟群のあるエレファンタ島(石窟をコンテナのイメージに、島の名前は象の石像があったことに由来)の元々の名前 Gharapuri(ガーラープリ)島 から。
参考
Ubuntu
検証
これでビルドと破棄を繰り返して試験・検証。
ネットワーク状態確認
apt, apt-get
タイムゾーン・ロケール設定
対話式を回避
apt install tzdata
する前に
ENV DEBIAN_FRONTEND=noninteractive
の環境変数をセットして回避する。
Apache
RedHat系 とディレクトリ構成が異なるので戸惑うなど。まずは sites-available
と sites-enabled
の違いを認識する洗礼を受ける。
ユーザーグループ
apache
ではなく www-data
。
ServerName ディレクティブ
SSL
最初は躓いたが特に設定変更するでもなくできた。
PHP
PHP
# a2enconf php8.1-fpm
としたところ
NOTICE: Not enabling PHP 8.1 FPM by default.
NOTICE: To enable PHP 8.1 FPM in Apache2 do:
NOTICE: a2enmod proxy_fcgi setenvif
NOTICE: a2enconf php8.1-fpm
NOTICE: You are seeing this message because you have apache2 package installed.
と言われたので。
PHP + SQLite
Composer
failed to solve: executor failed running …
passwd
SSH
- linux – How to execute ssh-keygen without prompt – Stack Overflow
- Windows\/Linuxでパスワードをコマンドワンライナーで設定する方法 | あいしんくいっと
- PermitRootLoginをprohibit-passwordからnoに変更する – あそぶ技術