第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、データディレクトリ
  • 動作確認: 起動手順、トラブルシューティング

次章では、セキュリティとベストプラクティスを学びます。