更新: firewalld の設定に誤りがあったので修正しました。
更新2: php のイメージに gd の jpeg と imagick を追加しました
更新3: firewalld の許可設定は不要でした
CentOS 6 のサポート期限が迫ってきているので CentOS 8 について必死で勉強しています。試しに全部コンテナで環境作ろうとしたのですが、CentOS 8 は docker ではなく podman が標準っぽいので、試しに podman で web サーバーを立ち上げてみました。
主力の PC が Windows なので Hyper-V で CentOS 8 を立ち上げて試しています(なので、 Hyper-V 専用の手順が紛れている可能性がありますがご承知おきください)。podman は docker と互換性があるので、 docker コマンドを podman に置き換えればほぼそのまま動くようです。
今回使用するイメージは以下の3つです。
podman でも Docker Hub からイメージをプルできます。
podman の目玉機能として、 rootless (ルート以外のユーザー)でコンテナ実行できる機能があるのですが、今回は 80 番ポートを使いたかったので rootfull で構築します。
SELinux が有効な場合は盛大にブロックしてくるので、先に setenforce 0
にしておき、後でポリシーを作りましょう(本記事では割愛)。また、 sudo 付けるのが面倒なので、root でログインして作業する想定で書いています。root 権限必須ですので、環境に合わせて sudo 付けてください。
PHP イメージの作成
php に関しては php の extension を入れないといけないので Dockerfile を書いてイメージを作る必要があります。podman でも Dockerfile なんですね。私はイメージ作成用のファイルをユーザーホームに作るタイプなので、/root/php/Dockerfile
に以下のファイルを配置しました。必要な拡張は docker-php-ext-install コマンドを使用してインストールします。
また、拡張をビルドするために必要なパッケージを apk add に指定する必要があります。alpine Linux をベースにしているので、パッケージ管理は apk を使用します。dnf, apt-get とはパッケージ名が違う場合があるので注意が必要です。必要な物は php のドキュメントに書いてありますが、私は面倒なのでエラーが出たら追加する方針で書いてます。
shadow は usermod, groupmod コマンドを入れるために指定しているパッケージです。
FROM php:fpm-alpine
RUN apk add --update --no-cache oniguruma-dev curl-dev \
icu-dev libpng-dev jpeg-dev giflib-dev shadow \
imagemagick-dev autoconf make g++ libzip-dev freetype-dev
RUN docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/
RUN docker-php-ext-install mbstring \
curl intl gd mysqli pdo_mysql opcache \
zip exif
RUN pecl install imagick
RUN docker-php-ext-enable imagick
ARG UID=1000
ARG GID=1000
RUN usermod -u $UID www-data
RUN groupmod -g $GID www-data
イメージを作成する前に、 www-data ユーザー&グループをホスト側に作っておきます。php fpm イメージでは www-data ユーザーで php を実行するので、ホスト側とコンテナ側で同じユーザー名&UIDに揃えておいた方が便利なためです。
useradd -M www-data
Dockerfile を配置したディレクトリに移動し、 buildah コマンドを打ちイメージを作成します。buildah はイメージ作成用のツールです。最初から CentOS 8 に入っていました。Dockerfile を置いたディレクトリで実行してください。
buildah bud \
--build-arg UID=$(id -u www-data) \
--build-arg GID=$(id -g www-data) \
--tag my-php .
完了後に buildah images
コマンドをたたくと localhost/my-php
イメージができているのが確認できます。
pod の作成
pod を作成します。pod はコンテナをまとめるグループのようなものです。ネットワーク的に良さそう(localhost でコンテナ間通信できる)だったので、pod でまとめることにしました。
pod はポートなどインフラ部分を複数のコンテナで共有します。ですのでポートフォワーディングの設定は pod を立ち上げる際に実施します。
podman pod create -p 80:80 -p 443:443 -p 3306:3306 -n wwwpod
ポート番号のマッピングを変えたい場合は、左側の数字を変更します。-p host:container
です。
コンテナで使用するディレクトリの作成
場所は任意ですが、今回はコンテナ関係のファイルを /srv
に置くことにしました。設定やデータ系を置く場所です。
mkdir --parents \
/srv/wwwpod/mariadb/data \
/srv/wwwpod/nginx/config \
/srv/wwwpod/php/config \
/srv/wwwpod/public
/srv/wwwpod/
├── mariadb
│ └── data
├── nginx
│ └── config
├── php
│ └── config
└── public
public は web ページのファイルを置く場所なので、 www-data
ユーザー&グループを所有者にしておきます。php が www-data
ユーザーで実行されるので、読み書きできるようにしておく必要があるためです。
chown www-data:www-data -R /srv/wwwpod/public
mariadb コンテナの立ち上げ
mariadb を立ち上げます。my-secret-pw
は root のパスワードなので変更してください。
podman run --detach \
--pod wwwpod \
--name mariadb \
--restart always \
--volume /srv/wwwpod/mariadb/data:/var/lib/mysql \
--env MYSQL_ROOT_PASSWORD=my-secret-pw \
--log-driver journald \
mariadb
標準のログドライバーは k8s-file なのでログファイルが出力されるのですが、ログローテーションの説明を見つけられず不安だったので journald を指定しておきます。
php コンテナの立ち上げ
php の設定ファイルを持ってきます。extension の読み込み設定は、 docker-php-ext-install
コマンドにより自動で追加されるので不要です。
podman run --name tmp-php -d localhost/my-php
podman cp tmp-php:/usr/local/etc/php/php.ini-production
/srv/wwwpod/php/config/php.ini
podman rm -f tmp-php
php を立ち上げます。
podman run --detach \
--pod wwwpod \
--name php \
--volume /srv/wwwpod/php/config/php.ini:/usr/local/etc/php/php.ini:ro \
--volume /srv/wwwpod/public:/usr/share/nginx/html \
--log-driver journald \
localhost/my-php
nginx コンテナの立ち上げ
まずは nginx の設定ファイルを持ってきます。
podman run --name tmp-nginx -d nginx
podman cp tmp-nginx:/etc/nginx/nginx.conf /srv/wwwpod/nginx/config/nginx.conf
podman cp tmp-nginx:/etc/nginx/conf.d/default.conf /srv/wwwpod/nginx/config/conf.d/default.conf
podman rm -f tmp-nginx
/srv/wwwpod/nginx/config/conf.d/default.conf を編集し、 php を実行できるようにします。
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /usr/share/nginx/html;
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
nginx を立ち上げます。
podman run --detach \
--pod wwwpod \
--name nginx \
--volume /srv/wwwpod/nginx/config/nginx.conf:/etc/nginx/nginx.conf:ro \
--volume /srv/wwwpod/nginx/config/conf.d:/etc/nginx/conf.d:ro \
--volume /srv/wwwpod/public:/usr/share/nginx/html:ro \
--log-driver journald \
nginx
コンテナ立ち上げ後に設定ファイルを修正した場合は、 reload コマンドを実行します。
podman exec nginx nginx -s reload
nginx が2つ並んでるのは間違いではないです。nginx コンテナの nginx コマンドを実行します。
net.ipv4.ip_forward を設定
デフォルトの状態だとコンテナからインターネットが見れなかったので以下のコマンドを打ちました。
sysctl -w net.ipv4.ip_forward=1
cat <<EOF > /etc/sysctl.d/podman.conf
net.ipv4.ip_forward=1
EOF
web ページの配置
/srv/wwwpod/public に html や php ファイルを置けば見えるようになるはずです。試しに WordPress を置いて軽く動かしてみましたが、大丈夫そうです。少なくとも記事の投稿やプラグインのインストールは可能でした。
firewalld の設定
この章は設定不要でした。firewalld の拒否設定より先にポートフォワーディングが適用されるので、ポートマッピングしただけで外から見えます。
外部に公開する場合は firewall-cmd を使って許可するポートを指定します。
firewall-cmd --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --zone=public --add-service=https
firewall-cmd --zone=public --add-service=https --permanent
–permanent ありの場合は firewall-cmd –reload も必要ですが、 reload をするとコンテナの再起動が必要になります(コンテナが起動時に自動設定したルールが消える。)。そのため、–permanent オプションあり(恒久的に反映)となし(即時反映)を両方実行します。
その他
診断
何か問題が起きた時に調査する方法です。
実行中のコンテナを見る場合は以下のコマンドを使用します。
podman ps
各コンテナの shell に入る場合は以下のコマンドを打ちます。php だけ alpine なので bash が入っていないです。
podman exec -it nginx bash
podman exec -it php sh
podman exec -it mariadb bash
各コンテナのログを見る場合は以下のコマンドを打ちます。
podman logs -f nginx
podman logs -f php
podman logs -f mariadb
コンテナの立ち上げ、停止
pod ごとまとめて開始・停止したり、コンテナごとに開始・停止したりできます。
podman pod start wwwpod
podman start nginx
podman start php
podman start mariadb
podman pod stop wwwpod
podman stop nginx
podman stop php
podman stop mariadb
課題
お試しなので権限回りの設定や動作確認が甘めです。
- nginx と mariadb も UID GID そろえた方がよさそう
- nginx はデフォルトだと UID=101 GID=101 で動く
- mariadb (mysqld) は UID=999 GID=999 で動く
- ✔ php と nginx のワーカープロセス、 mariadb 以外は root で動くので、SELinux を適切に設定したほうがよさそう
chcon -Rt container_file_t /srv/wwwpod
で許可できる- コンテナを複数立ち上げる場合は MCS の設定も考える必要がありそう
- こちらの記事にまとめました
- ✔ インターネット側からアクセスできるかの確認 → 確認しました
- ✔ ホスト起動時にコンテナも立ち上げる方法 → こちらの記事にまとめました
- mariadb の設定ファイルもホスト側に置く
- ✔ 存在しない php ファイルへアクセスすると「 File not found. 」画面が出てしまう → 本記事を修正しました
- ✔ podman のネットワークが初期設定だと IPv6 の通信を受けられない → こちらの記事にまとめました
バージョン情報
今回使用した podman のバージョンです。
podman version 1.6.4
buildah version 1.11.6