第5章:サービス構築
はじめに
Inceptionでは、Nginx、WordPress、MariaDBの3つのサービスを構築します。本章では、各サービスの詳細な設定を学びます。
---
1. Nginx(TLSターミネーション)
1.1 要件
Inceptionの要件:
- TLSv1.2 または TLSv1.3 のみ
- ポート443のみ
- リバースプロキシとしてWordPressに接続
1.2 SSL証明書生成
# 自己署名証明書の生成
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout /etc/nginx/ssl/nginx.key \
-out /etc/nginx/ssl/nginx.crt \
-subj "/C=JP/ST=Tokyo/L=Tokyo/O=42/CN=login.42.fr"
# オプション説明:
# -x509: 自己署名証明書を生成
# -nodes: パスフレーズなし
# -days 365: 有効期限1年
# -newkey rsa:2048: 2048ビットRSA鍵
# -keyout: 秘密鍵の出力先
# -out: 証明書の出力先
# -subj: 証明書の主体情報
1.3 nginx.conf
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# HTTPSサーバー
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name login.42.fr;
# SSL設定
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# ドキュメントルート
root /var/www/html;
index index.php index.html;
# PHP処理
location ~ \.php$ {
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# 静的ファイル
location / {
try_files $uri $uri/ /index.php?$args;
}
# セキュリティヘッダー
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
}
1.4 Dockerfile
FROM alpine:3.18
RUN apk update && \
apk add --no-cache nginx openssl && \
rm -rf /var/cache/apk/*
# SSL証明書ディレクトリ
RUN mkdir -p /etc/nginx/ssl
# 証明書生成(ビルド時)
ARG DOMAIN_NAME=login.42.fr
RUN openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout /etc/nginx/ssl/nginx.key \
-out /etc/nginx/ssl/nginx.crt \
-subj "/C=JP/ST=Tokyo/L=Tokyo/O=42/CN=${DOMAIN_NAME}"
# 設定ファイル
COPY conf/nginx.conf /etc/nginx/nginx.conf
# ログディレクトリ
RUN mkdir -p /var/log/nginx
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
---
2. WordPress + PHP-FPM
2.1 PHP-FPM設定
; /etc/php82/php-fpm.d/www.conf
[www]
user = nobody
group = nobody
; ソケットではなくTCPで待ち受け
listen = 0.0.0.0:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
; タイムアウト
request_terminate_timeout = 60s
; エラーログ
php_admin_value[error_log] = /var/log/php/error.log
php_admin_flag[log_errors] = on
2.2 WordPress設定スクリプト
#!/bin/sh
# /tools/setup.sh
set -e
# ディレクトリ準備
mkdir -p /var/www/html
cd /var/www/html
# WordPressダウンロード(なければ)
if [ ! -f /var/www/html/wp-config.php ]; then
echo "Downloading WordPress..."
# WP-CLIでダウンロード
wp core download --allow-root --path=/var/www/html
# wp-config.php生成
wp config create \
--dbname="${MYSQL_DATABASE}" \
--dbuser="${MYSQL_USER}" \
--dbpass="${MYSQL_PASSWORD}" \
--dbhost="${WORDPRESS_DB_HOST}:3306" \
--allow-root \
--path=/var/www/html
# データベース接続待機
echo "Waiting for MariaDB..."
until mysql -h"${WORDPRESS_DB_HOST}" -u"${MYSQL_USER}" \
-p"${MYSQL_PASSWORD}" -e "SELECT 1" > /dev/null 2>&1; do
sleep 2
done
# WordPress インストール
wp core install \
--url="https://${DOMAIN_NAME}" \
--title="${WP_TITLE:-WordPress}" \
--admin_user="${WP_ADMIN_USER}" \
--admin_password="${WP_ADMIN_PASSWORD}" \
--admin_email="${WP_ADMIN_EMAIL}" \
--skip-email \
--allow-root \
--path=/var/www/html
# 追加ユーザー作成
if [ -n "${WP_USER}" ]; then
wp user create "${WP_USER}" "${WP_USER_EMAIL}" \
--user_pass="${WP_USER_PASSWORD}" \
--role=author \
--allow-root \
--path=/var/www/html
fi
# パーミッション設定
chown -R nobody:nobody /var/www/html
echo "WordPress installation complete!"
fi
# PHP-FPM起動
echo "Starting PHP-FPM..."
exec php-fpm82 -F
2.3 Dockerfile
FROM alpine:3.18
# PHP と必要なモジュール
RUN apk update && \
apk add --no-cache \
php82 \
php82-fpm \
php82-mysqli \
php82-json \
php82-curl \
php82-dom \
php82-exif \
php82-fileinfo \
php82-mbstring \
php82-openssl \
php82-xml \
php82-zip \
php82-phar \
php82-iconv \
php82-gd \
php82-intl \
wget \
mariadb-client && \
rm -rf /var/cache/apk/*
# WP-CLI
RUN wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x wp-cli.phar && \
mv wp-cli.phar /usr/local/bin/wp
# PHP-FPM設定
COPY conf/www.conf /etc/php82/php-fpm.d/www.conf
# ログディレクトリ
RUN mkdir -p /var/log/php
# セットアップスクリプト
COPY tools/setup.sh /setup.sh
RUN chmod +x /setup.sh
WORKDIR /var/www/html
EXPOSE 9000
ENTRYPOINT ["/setup.sh"]
---
3. MariaDB
3.1 MariaDB設定
# /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
user = mysql
# ネットワーク設定
bind-address = 0.0.0.0
port = 3306
# 文字コード
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# ログ
log-error = /var/log/mysql/error.log
# パフォーマンス
key_buffer_size = 16M
max_allowed_packet = 16M
max_connections = 50
innodb_buffer_pool_size = 128M
[mysql]
default-character-set = utf8mb4
3.2 初期化スクリプト
#!/bin/sh
# /tools/init.sh
set -e
# データディレクトリ準備
mkdir -p /var/lib/mysql
mkdir -p /var/log/mysql
chown -R mysql:mysql /var/lib/mysql
chown -R mysql:mysql /var/log/mysql
# 初回起動時のみ初期化
if [ ! -d "/var/lib/mysql/mysql" ]; then
echo "Initializing MariaDB..."
# データベース初期化
mysql_install_db --user=mysql --datadir=/var/lib/mysql
# 一時的にサーバー起動(セキュリティなし)
mysqld --user=mysql --datadir=/var/lib/mysql --skip-networking &
pid=$!
# 起動待機
echo "Waiting for MariaDB to start..."
for i in $(seq 1 30); do
if mysqladmin ping --silent 2>/dev/null; then
break
fi
sleep 1
done
# データベースとユーザー作成
mysql -u root <<EOF
-- データベース作成
CREATE DATABASE IF NOT EXISTS \`${MYSQL_DATABASE}\`;
-- ユーザー作成
CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';
GRANT ALL PRIVILEGES ON \`${MYSQL_DATABASE}\`.* TO '${MYSQL_USER}'@'%';
-- rootパスワード設定
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
-- 変更を反映
FLUSH PRIVILEGES;
EOF
# サーバー停止
mysqladmin -u root -p"${MYSQL_ROOT_PASSWORD}" shutdown
echo "MariaDB initialization complete!"
fi
# 通常起動
echo "Starting MariaDB..."
exec mysqld --user=mysql --datadir=/var/lib/mysql
3.3 Dockerfile
FROM alpine:3.18
# MariaDB
RUN apk update && \
apk add --no-cache mariadb mariadb-client && \
rm -rf /var/cache/apk/*
# 設定ファイル
COPY conf/mariadb-server.cnf /etc/my.cnf.d/mariadb-server.cnf
# 初期化スクリプト
COPY tools/init.sh /init.sh
RUN chmod +x /init.sh
# データとログディレクトリ
RUN mkdir -p /var/lib/mysql /var/log/mysql && \
chown -R mysql:mysql /var/lib/mysql /var/log/mysql
EXPOSE 3306
ENTRYPOINT ["/init.sh"]
---
4. ホスト設定
4.1 /etc/hosts
# 42VMで必要な設定
echo "127.0.0.1 login.42.fr" | sudo tee -a /etc/hosts
# または
sudo sed -i '/login.42.fr/d' /etc/hosts
echo "127.0.0.1 login.42.fr" | sudo tee -a /etc/hosts
4.2 データディレクトリ
# ボリューム用ディレクトリ作成
mkdir -p /home/${USER}/data/wordpress
mkdir -p /home/${USER}/data/mariadb
# 権限設定
chmod 755 /home/${USER}/data
chmod 755 /home/${USER}/data/wordpress
chmod 755 /home/${USER}/data/mariadb
---
5. 動作確認
5.1 起動手順
# 1. ディレクトリ作成
make setup
# 2. ビルドと起動
make all
# 3. 状態確認
make ps
# 4. ログ確認
make logs
# 5. ブラウザでアクセス
# https://login.42.fr
5.2 トラブルシューティング
# コンテナ内に入る
docker exec -it nginx sh
docker exec -it wordpress sh
docker exec -it mariadb sh
# ネットワーク確認
docker network inspect inception
# ボリューム確認
docker volume ls
docker volume inspect inception_wordpress_data
# プロセス確認
docker exec wordpress ps aux
docker exec mariadb ps aux
# データベース接続テスト
docker exec wordpress mysql -h mariadb -u wpuser -p
5.3 よくある問題
問題1: WordPress接続エラー
原因: MariaDBが準備完了前に接続試行
解決: 初期化スクリプトで待機処理
問題2: 403 Forbidden
原因: パーミッション問題
解決: chown -R nobody:nobody /var/www/html
問題3: TLS接続失敗
原因: 証明書の問題
解決: ブラウザで例外を追加(自己署名証明書のため)
問題4: ボリュームが空
原因: バインドマウント先のディレクトリがない
解決: make setup で事前にディレクトリ作成
---
まとめ
本章で学んだこと:
- Nginx: TLS設定、リバースプロキシ
- WordPress: PHP-FPM、WP-CLI
- MariaDB: 初期化、ユーザー作成
- ホスト設定: /etc/hosts、データディレクトリ
- 動作確認: 起動手順、トラブルシューティング
次章では、セキュリティとベストプラクティスを学びます。