Skip to content

Dockerボリュームの罠:テーマが反映されない原因と解決策

はじめに

本記事は以下の環境を前提としています。

  • WordPress + Docker Compose構成
  • 本番環境でテーマディレクトリをボリュームマウント
  • GitHub Actionsによる自動デプロイ

本番環境へのデプロイ後、WordPressテーマのCSSが一切反映されない問題に遭遇しました。Dockerイメージは最新なのに、なぜか古いファイルが表示される。調査を進めると、Dockerボリュームマウントの特性が原因でした。

この記事では、ボリュームがイメージのファイルを上書きしてしまう仕組みと、GitHub Actionsに自動同期処理を追加して解決した方法をご紹介します。

本番デプロイ後にCSSが反映されない問題

WordPressテーマのCSSファイルに122行の変更を加えました。開発環境では正常に動作を確認し、GitHubにプッシュしてデプロイを実行。しかし、本番環境では変更が一切反映されていませんでした。


flowchart TD
    A[CSSを122行変更] --> B[開発環境で動作確認]
    B --> C[GitHubにプッシュ]
    C --> D[GitHub Actionsでデプロイ]
    D --> E[本番環境で確認]
    E --> F{CSSは反映された?}
    F -->|No| G[変更が反映されていない]

初期調査で確認した項目

以下の項目を確認しました。

  • Dockerコンテナは最新のイメージで稼働中
  • イメージタグは最新のコミットハッシュを含んでいる
  • ブラウザのキャッシュクリアも実施済み

しかし、CSSファイルの行数を確認すると、開発環境では2431行あるのに対し、本番環境では2309行。122行の差分が完全に欠落していました。

ボリュームマウントがイメージを上書きする仕組みが原因だった

ボリューム内の古いファイルがイメージ内の新しいファイルを上書きしていたのが原因だったことに気づきました


flowchart TD
    A[新しいDockerイメージ] -->|デプロイ| B[コンテナ起動]
    B --> C[ボリュームマウント]
    C --> D[古いファイルが優先される]
    D --> E[変更が反映されない]

Dockerのボリュームマウントは、コンテナ内のディレクトリをホストのボリュームに置き換えます。ボリュームにすでにファイルが存在する場合、イメージ内のファイルは無視されます。

ボリュームマウントを使用している理由

ボリュームマウントは以下の理由で使用していました。

  • WordPressのプラグインやアップロードファイルの永続化
  • コンテナ再作成時のデータ保護
  • 開発時の利便性向上

これ自体は正しい設計です。しかし、テーマファイルの更新を考慮していませんでした。

根本原因の特定

5 Whys分析を実施しました。


flowchart TD
    Q1[なぜテーマが更新されない?] --> A1[ボリュームに古いファイルが残っている]
    A1 --> Q2[なぜ古いファイルが残る?]
    Q2 --> A2[デプロイ時にコピーされない]
    A2 --> Q3[なぜコピーされない?]
    Q3 --> A3[デプロイスクリプトに処理がない]
    A3 --> Q4[なぜ処理がない?]
    Q4 --> A4[手動コピーを想定していた]
    A4 --> Q5[なぜ自動化されていない?]
    Q5 --> A5[設計時に考慮されていなかった]

解決策の検討と選択

2つの解決策を検討しました。

デプロイスクリプトへの同期処理追加

GitHub Actionsのデプロイ時に、新しいイメージからテーマファイルを自動的にコピーする処理を追加します。

利点:

  • 既存の構造を変更せず最小限の修正で実現可能
  • ボリュームマウントの利点を維持できる
  • デプロイのたびに確実に最新のファイルが反映される

欠点:

  • デプロイ時間がわずかに増加

docker-compose設定の変更

ボリュームマウントの範囲を変更し、テーマファイルはイメージから読み込むようにします。

利点:

  • シンプルな設計になる
  • デプロイ時の追加処理が不要

欠点:

  • 既存の構造を大きく変更する必要がある
  • 開発時の利便性が低下する可能性がある

今回は、既存の構造を維持できるデプロイスクリプトへの同期処理追加を採用しました。

この方法が成立する条件

この解決策は以下の条件で有効です。

  • 単一のテーマのみを管理している
  • テーマをCIでビルドしている
  • テーマの変更頻度がそれほど高くない

複数テーマを管理している場合や、テーマの変更頻度が高い場合は、ボリュームマウントの範囲自体を見直す方が適切かもしれません。

GitHub Actionsワークフローへの自動同期処理の実装

.github/workflows/deploy.ymlのデプロイステップに、以下の処理を追加しました。


# Wait for container to be ready
sleep 5

# Sync theme files from new image to volume
echo "Syncing theme files from image to volume..."

# Create a temporary container to extract theme files
TEMP_CONTAINER=$(docker create ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${IMAGE_TAG})

# Copy theme files from temporary container to host
docker cp ${TEMP_CONTAINER}:/var/www/html/wp-content/themes/scriptlab-theme /tmp/scriptlab-theme-new

# Remove temporary container
docker rm ${TEMP_CONTAINER}

# Copy theme files from host to volume via running container
docker cp /tmp/scriptlab-theme-new/. slab-wordpress:/var/www/html/wp-content/themes/scriptlab-theme/

# Fix permissions
docker exec slab-wordpress chown -R www-data:www-data /var/www/html/wp-content/themes/scriptlab-theme

# Clean up temporary files
rm -rf /tmp/scriptlab-theme-new

# Restart to clear cache
docker compose -f docker-compose.prod.yml restart wordpress nginx

この処理の流れを以下に示します。


sequenceDiagram
    participant GHA as GitHub Actions
    participant TmpC as 一時コンテナ
    participant Host as EC2ホスト
    participant WP as WordPressコンテナ
    participant Vol as Dockerボリューム

    GHA->>TmpC: 新しいイメージから一時コンテナを作成
    TmpC->>Host: テーマファイルをホストにコピー
    GHA->>TmpC: 一時コンテナを削除
    Host->>WP: ホストからWordPressコンテナへコピー
    WP->>Vol: ボリュームに書き込み
    GHA->>WP: 権限を修正(www-data:www-data)
    GHA->>WP: コンテナを再起動してキャッシュクリア

実装中に発生したGitHub Actions変数のエスケープ問題

実装中、GitHub Actionsのワークフローファイルで複数のエラーが発生しました。

AWSリージョンが無効になるエラー

以下のようなエラーが発生しました。


Error: Region is not valid: \ap-northeast-1

原因は、ワークフローファイル内の全てのGitHub Actions変数参照に不要なバックスラッシュエスケープが入っていたことでした。\${{ ... }}となっていた箇所を${{ ... }}に修正しました。

rsyncコマンドが失敗するエラー

以下のようなエラーも発生しました。


rsync: [sender] link_stat "/home/runner/work/slab-wp/slab-wp/\" failed: No such file or directory (2)

YAMLの複数行文字列内で、シェルスクリプトの行継続に二重バックスラッシュを使用していたことが原因でした。全ての不要なエスケープ(22箇所)と二重バックスラッシュ(6箇所)を修正しました。

デプロイの実行と検証結果

修正したワークフローをプッシュし、GitHub Actionsが自動的に実行されました。

  • ビルドジョブ:1分53秒で成功
  • デプロイジョブ:1分33秒で成功
  • テーマファイル同期:成功

検証で確認した項目

以下の項目を確認しました。

  • コンテナは最新のイメージタグで稼働
  • CSSファイルサイズは65KBで正しいサイズ
  • タイムスタンプはデプロイ時刻と一致
  • 所有者はwww-data:www-dataで正しい権限

manifest.jsonも最新のCSSファイルを正しく参照していることを確認しました。

ボリュームマウント運用で得られた知見

ボリュームマウント使用時の注意点

Dockerボリュームマウントを使用する際は、以下の点に注意が必要です。

  • ボリューム内のファイルはイメージ内のファイルより優先される
  • イメージを更新してもボリューム内のファイルは自動的に更新されない
  • 更新が必要なディレクトリの扱いを慎重に検討する

flowchart LR
    A[Dockerイメージ内のファイル] --> B{ボリュームマウントあり?}
    B -->|Yes| C[ボリューム内のファイルが優先]
    B -->|No| D[イメージ内のファイルを使用]

GitHub Actionsワークフローのデバッグ手法

ワークフローファイルをデバッグする際は、以下が有効でした。

  • ログに検証ステップを追加する
  • ローカルのDocker環境で同じ処理を試す
  • エスケープ処理は特に慎重に確認する

問題解決における分析手法の有効性

5 Whys分析を実施したことで、表面的な問題から根本原因まで掘り下げることができました。問題解決の際は、現象だけでなく「なぜ」を繰り返し問うことが重要です。

終わりに

今回の問題は、Dockerボリュームマウントの特性を正しく理解していなかったことが原因でした。GitHub Actionsワークフローに自動同期処理を追加することで、デプロイのたびに確実に最新のテーマファイルが反映されるようになりました。

この経験から、インフラ設計時には「更新が必要なファイル」と「永続化が必要なファイル」を明確に区別することの重要性を学びました。

コメントを残す