0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

テスト環境では動くのに本番環境で動かない!環境差異によるトラブルとその対策

0
Posted at

環境情報

  • テスト環境: PHP 8.1, MySQL 8.0, Apache 2.4, macOS
  • 本番環境: PHP 7.4, MySQL 5.7, Nginx 1.18, CentOS 7
  • フレームワーク: Laravel 9
  • デプロイツール: Deployer

はじめに

Web制作に携わるエンジニアであれば、一度は経験したことがある「テスト環境では問題ないのに、本番環境で動かない」という現象。私も先日、あるECサイトの改修中にこの問題に直面しました。テスト環境で徹底的にテストした機能が、本番環境にデプロイした瞬間に全く動作しなくなる。この記事では、その原因と具体的な解決策を、実装の手順を交えて詳しく解説します。

問題の発生

あるECサイトの商品検索機能を改良し、テスト環境で以下の確認を行いました:

  • 検索結果が正しく表示される
  • フィルタリングが正常に動作する
  • ページネーションが機能する
  • エラーハンドリングが適切

しかし、本番環境にデプロイした直後、検索機能が完全に停止。ブラウザの開発者ツールで確認すると、500エラーが返ってきていました。

原因の特定

1. PHPバージョンの違い

本番サーバーのPHPバージョンが7.4だったのに対し、テスト環境は8.1でした。PHP 8.0で非推奨となった関数を使用していたことが判明。

// 問題のコード(PHP 8.1では動作するが、7.4では非推奨)
$result = array_map(function($item) {
    return str_replace(' ', '_', $item);
}, $data);

// PHP 7.4で動作する修正版
$result = array_map(function($item) {
    return str_replace(' ', '_', $item);
}, $data);

実はこのコード自体は問題ありませんでしたが、別の箇所でeach()関数を使用していたことが原因でした。

// PHP 7.4で非推奨、8.0で削除されたeach()
while (list($key, $value) = each($array)) {
    // 処理
}

// foreachに書き換え
foreach ($array as $key => $value) {
    // 処理
}

2. ファイルパスの大文字小文字の違い

テスト環境(macOS)では大文字小文字を区別しないファイルシステムでしたが、本番環境(Linux)では区別されます。

// テスト環境では動くが、本番環境でエラー
include 'Config/Database.php'; // 実際のファイルは config/database.php

// 正しいパス
include 'config/database.php';

3. データベースの文字コード設定の差異

テスト環境ではUTF-8mb4がデフォルトでしたが、本番環境ではUTF-8のまま変更されていませんでした。

-- テスト環境のテーブル定義
CREATE TABLE products (
    name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
);

-- 本番環境のテーブル定義(古いまま)
CREATE TABLE products (
    name VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci
);

具体的な対策と実装手順

1. 環境変数による設定の一元管理

.envファイルを活用し、環境ごとの設定を一元管理します。

// .env.example(全環境で共通)
APP_ENV=local
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

// config/database.php
return [
    'default' => env('DB_CONNECTION', 'mysql'),
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
        ],
    ],
];

2. 本番同等のステージング環境の構築

Dockerを使用して、本番環境と同一の環境を構築します。

# docker-compose.yml
version: '3.8'
services:
  app:
    image: php:7.4-fpm
    volumes:
      - ./:/var/www/html
    environment:
      - APP_ENV=staging
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: staging_db

3. デプロイ前の自動チェックスクリプト

#!/bin/bash
# deploy-check.sh

echo "=== 環境差異チェック ==="

# PHPバージョンチェック
PHP_VERSION=$(php -v | head -n 1 | cut -d " " -f 2 | cut -d "." -f 1-2)
echo "PHP Version: $PHP_VERSION"

# 非推奨関数の使用チェック
echo "非推奨関数チェック..."
grep -r "each(" --include="*.php" . && echo "警告: each()関数が使用されています"
grep -r "create_function(" --include="*.php" . && echo "警告: create_function()が使用されています"

# ファイルパスの大文字小文字チェック
echo "ファイルパスチェック..."
find . -name "*.php" -path "*[A-Z]*" | while read file; do
    lowercase=$(echo "$file" | tr '[:upper:]' '[:lower:]')
    if [ "$file" != "$lowercase" ]; then
        echo "警告: 大文字を含むパス: $file"
    fi
done

# データベース文字コードチェック
echo "データベース文字コードチェック..."
php -r "
    \$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
    \$stmt = \$pdo->query('SHOW VARIABLES LIKE \"character_set_server\"');
    \$row = \$stmt->fetch();
    echo 'Server charset: ' . \$row['Value'] . PHP_EOL;
"

4. 環境差異の比較表

項目 テスト環境 本番環境 注意点
PHPバージョン 8.1 7.4 非推奨関数のチェック必須
データベース MySQL 8.0 MySQL 5.7 文字コード、ストレージエンジン
Webサーバー Apache Nginx .htaccessの非互換
ファイルシステム 大文字小文字区別なし 区別あり パスは常に小文字で統一
OS macOS CentOS パーミッション設定の違い

5. デプロイフローの改善

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '7.4' # 本番環境と同じバージョン
    
    - name: Run tests
      run: |
        composer install
        php artisan test
    
    - name: Deploy to staging
      run: |
        # ステージング環境にデプロイ
        php artisan deploy staging
    
    - name: Run integration tests on staging
      run: |
        # ステージング環境で結合テスト
        curl -f http://staging.example.com/health-check
    
    - name: Deploy to production
      run: |
        php artisan deploy production

ハマりポイントと解決策

1. PHPのバージョン互換性

PHP 7.4から8.0への移行で特に注意が必要な点:

  • each()関数の削除
  • create_function()の削除
  • 型宣言の厳格化

2. データベースのマイグレーション

// データベースマイグレーション時の注意点
Schema::table('products', function (Blueprint $table) {
    // 本番環境では既存データがある場合の考慮
    $table->string('name', 255)->charset('utf8mb4')->change();
    
    // インデックス追加時のロック対策
    $table->index('category_id')->algorithm('INPLACE');
});

3. ファイルパスの統一ルール

// プロジェクト全体で統一するルール
class PathHelper {
    public static function normalize($path) {
        return strtolower(str_replace('\\', '/', $path));
    }
    
    public static function include($path) {
        require_once self::normalize($path);
    }
}

まとめ

テスト環境と本番環境の差異によるトラブルを防ぐためには、以下の3つの対策が効果的です:

  1. 環境変数による設定の一元管理 - 環境ごとの設定をコードから分離
  2. 本番同等のステージング環境の構築 - DockerやVagrantを活用
  3. デプロイ前の自動チェック - CI/CDパイプラインに組み込む

特に重要なのは、テスト環境と本番環境の差異を事前に把握し、デプロイ前に自動チェックを行うことです。これにより、人的ミスを減らし、安定したデプロイを実現できます。

あなたのプロジェクトでも、環境差異によるトラブルが発生した場合は、まずPHPバージョン、ファイルパス、データベース設定の3点を確認してみてください。そして、上記の対策を導入することで、同じミスを繰り返さないようにしましょう。


この記事を書いた人

BENTEN Web Works — 業務自動化・システム開発のフリーランスエンジニアです。

GAS / Python / RPA を使った業務自動化や、Web制作・システム開発のご相談を承っています。
「こんなこと自動化できる?」というご質問だけでもお気軽にどうぞ。

👉 BENTEN Web Works — 詳細・お問い合わせはこちら
🐦 X(旧Twitter) — 日々の知見を発信中

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?