AWS Fargateを使って、スケールするWordPress環境を作りたい。でも、正直よくわからない…。
そこで、いきなり完成形を目指すのではなく、「まずはコンテナでWordPressを動かす」という基本から始め、一つずつ仕組みを理解しながら、最終的に目標の構成にたどり着くまでの過程を記録してみました。
まず、ローカルで WordPress をコンテナで作ってみる
1. docker-compose.ymlを作成
# servicesセクション: アプリケーションを構成する各コンテナ(サービス)を定義 services: # 'db'という名前のサービス(MySQLデータベースコンテナ)を定義 db: # 使用するDockerイメージを指定。ここではMySQLのバージョン8.0を使用。 image: mysql:8.0 # volumesセクション: データの永続化に関する設定。 volumes: # 'db_data'という名前付きボリュームを、コンテナ内の'/var/lib/mysql'ディレクトリにマウント。 # コンテナを起動するホストマシン上にデータを保持する領域が作られる。 # これにより、コンテナを削除してもデータベースのデータが保持される。 - db_data:/var/lib/mysql # restartポリシー: コンテナが停止した場合の再起動方針。'always'は常に再起動。 restart: always # environmentセクション: コンテナ内で使用する環境変数を設定。 environment: MYSQL_ROOT_PASSWORD: wordpress # MySQLのrootユーザーのパスワードを設定。 MYSQL_DATABASE: wordpress # 'wordpress'という名前のデータベースを初期作成。 MYSQL_USER: wordpress # 'wordpress'という名前のユーザーを作成。 MYSQL_PASSWORD: wordpress # 上記ユーザーのパスワードを設定。 # 'wordpress'という名前のサービス(WordPressアプリケーションコンテナ)を定義。 wordpress: # depends_onセクション: サービスの起動順序を制御。 # 'db'サービスが起動してから、この'wordpress'サービスが起動。 depends_on: - db # 使用するDockerイメージを指定。ここでは最新版のWordPressを使用。 image: wordpress:latest # portsセクション: ホストマシンとコンテナ間のポートマッピングを設定。 # ホストマシンのポート8000番へのアクセスを、コンテナのポート80番に転送。 # これにより、ブラウザで http://localhost:8000 を開くとWordPressにアクセスできる。 ports: - "8000:80" # restartポリシー: コンテナが停止した場合、常に再起動。 restart: always # environmentセクション: WordPressコンテナ用の環境変数を設定。 environment: WORDPRESS_DB_HOST: db:3306 # 接続するデータベースのホスト名(サービス名'db')とポート番号を指定。 WORDPRESS_DB_USER: wordpress # データベースへの接続に使用するユーザー名を指定。 WORDPRESS_DB_PASSWORD: wordpress # データベースへの接続に使用するパスワードを指定。 # WORDPRESS_DB_NAMEは、MYSQL_DATABASEで指定した'wordpress'が自動的に使われる。 # volumesセクション: このdocker-composeファイル全体で使用する名前付きボリュームを定義。 volumes: # 'db_data'という名前のボリュームを定義。実体はDockerが管理。 db_data:
2. コンテナを起動
DockerDesktopを起動し、docker-compose up -d
でコンテナを起動します。
y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker-compose up -d --省略-- 22.3s [+] Running 4/4 ✔ Network y-ishikawa-docker-wordpress_default Created 0.1s ✔ Volume "y-ishikawa-docker-wordpress_db_data" Created 0.0s ✔ Container y-ishikawa-docker-wordpress-db-1 Started 0.7s ✔ Container y-ishikawa-docker-wordpress-wordpress-1 Started 0.6s y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$
3. 確認
ブラウザから `http://localhost:8000` にアクセスします。
できた
webサーバー(Apache)とPHPの処理を分けてみる
静的ファイル(画像など)はwebコンテナで返し、PHPのリクエストはcmsコンテナへ転送するようにしようと思いました。
1. docker-compose.yml を修正
services: # DBサービスは変更なし db: image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password # MySQLの認証プラグインを指定(これがないとうまくいかない) volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress # (旧wordpressサービス)PHPの実行に特化させる cms: image: wordpress:php8.2-fpm-alpine # PHP-FPM版のイメージに変更し、webサーバー機能がないPHP処理専用のコンテナにする depends_on: - db restart: always volumes: - wordpress_files:/var/www/html # WordPressのファイルを格納するボリュームを指定 environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress # データベース名を指定するように変更 # 【追加】apacheのwebサーバーサービス web: image: httpd:2.4-alpine # Apacheの公式イメージ depends_on: - cms # cmsコンテナが起動してから起動 restart: always ports: - "8000:80" # 外部との接続ポートはこっちに移動 volumes: - wordpress_files:/var/www/html # cmsと共有するボリュームを指定することで、Apacheは画像やCSSなどの静的ファイルを直接配信でき、PHPファイルはcmsコンテナに処理を渡すパスを認識できる。 - ./apache/httpd.conf:/usr/local/apache2/conf.d/httpd.conf # ローカルのApache設定ファイルを読み込ませる volumes: db_data: wordpress_files: # WordPressのファイルを格納する新しいボリューム
2. apacheの設定ファイルを作成
. ├── apache/ │ └── httpd.conf # <-- 新しく作成するApacheの設定ファイル └── docker-compose.yml
httpd.conf ↓
y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ mkdir apache y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ cd apache/ y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress/apache$ cat httpd.conf # サーバーの基本的な動作に必要なモジュール LoadModule mpm_event_module modules/mod_mpm_event.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule unixd_module modules/mod_unixd.so LoadModule dir_module modules/mod_dir.so LoadModule log_config_module modules/mod_log_config.so LoadModule rewrite_module modules/mod_rewrite.so # プロキシに必要なモジュール LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so # UserとGroupはhttpdイメージのデフォルトに合わせておく User daemon Group daemon # サーバーの基本設定 ServerRoot "/usr/local/apache2" Listen 80 ServerName localhost # ドキュメントルート(Webコンテンツの場所) DocumentRoot /var/www/html # ディレクトリの設定 Options Indexes FollowSymLinks AllowOverride All Require all granted # index.phpをデフォルトページに DirectoryIndex index.php # .phpファイルへのリクエストをcmsコンテナに転送する ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://cms:9000/var/www/html/$1 # ログのフォーマットを定義 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined # エラーログとアクセスログの設定 ErrorLog /proc/self/fd/2 CustomLog /proc/self/fd/1 combined y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress/apache$
3. コンテナを起動
y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker-compose up -d [+] Running 6/6 ✔ Network y-ishikawa-docker-wordpress_default Created 0.1s ✔ Volume "y-ishikawa-docker-wordpress_wordpress_files" Created 0.0s ✔ Volume "y-ishikawa-docker-wordpress_db_data" Created 0.0s ✔ Container y-ishikawa-docker-wordpress-db-1 Started 0.5s ✔ Container y-ishikawa-docker-wordpress-cms-1 Started 0.6s ✔ Container y-ishikawa-docker-wordpress-web-1 Started 0.8s y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$
できた
4. 動作確認
4-1. 静的ファイルがwebコンテナで処理されることを確認
ブラウザでWordPressのサイトのトップページを何度かリロードし、webコンテナのログが出力されることを確認。
y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker-compose logs -f web web-1 | 192.168.65.1 - - [19/Jul/2025:13:28:17 +0000] "GET /wp-admin/admin-ajax.php?action=wp-compression-test&test=1&_ajax_nonce=c07f70353f&1752931697561 HTTP/1.1" 200 1114 "http://localhost:8000/wp-admin/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) web-1 | 192.168.65.1 - - [19/Jul/2025:13:28:27 +0000] "POST /wp-admin/ web-1 | 192.168.65.1 - - [19/Jul/2025:13:28:35 +0000] "GET / HTTP/1.1" 200 57198 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
4-2. PHPがcmsコンテナで処理されることを確認
ブラウザでWordpressの管理画面にアクセスし、cmsコンテナのログが出力されることを確認。
y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker-compose logs -f cms cms-1 | 172.19.0.4 - 19/Jul/2025:13:27:23 +0000 "GET /index.php" 500 cms-1 | 172.19.0.4 - 19/Jul/2025:13:27:34 +0000 "GET /index.php" 302 cms-1 | 172.19.0.4 - 19/Jul/2025:13:27:34 +0000 "GET /wp-admin/install.php" 200 cms-1 | 172.19.0.4 - 19/Jul/2025:13:27:42 +0000 "POST /wp-admin/install.php" 200 cms-1 | 172.19.0.4 - 19/Jul/2025:13:28:01 +0000 "POST /wp-admin/install.php" 200
できました。dbコンテナに command: --default-authentication-plugin=mysql_native_password
を追加しないと認証のタイプがどうのでうまくいかないので忘れないず設定しましょう。
AWS Fargate で起動してみる
web (Apache) コンテナは自作の httpd.conf を使っているため、この設定ファイルを含んだカスタムイメージを Dockerfile で作成し、ECRにプッシュする必要があるようです。
1. webコンテナ用の Dockerfile を作成する
. ├── apache/ │ └── httpd.conf ├── docker-compose.yml └── Dockerfile # <-- これを新規作成
Dockerfile ↓
# ベースイメージとして公式のhttpdイメージを指定 FROM httpd:2.4-alpine # ローカルのhttpd.confをコンテナ内の正しい場所にコピーする COPY ./apache/httpd.conf /usr/local/apache2/conf/httpd.conf
2. ECRにリポジトリを作成
Amazon ECR > プライベートレジストリ > リポジトリ >プライベートリポジトリを作成
リポジトリ名だけ決めて、他はデフォルトで「作成」をクリックします。
3. httpd.conf の修正
docker-composeでは各サービスがコンテナ名(例: cms)で通信できましたが、Fargateの同一タスク内のコンテナは localhost で通信します。
そのため、apache/httpd.conf のPHPへの転送設定を以下のように変更します。
# 変更前 # ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://cms:9000/var/www/html/$1 # 変更後: 'cms:9000' を 'localhost:9000' に変更 ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://localhost:9000/var/www/html/$1
4. イメージをビルドしてECRにプッシュする
作成したリポジトリを選択 > プッシュコマンドを表示 >
表示されたコマンドをターミナルから順に実行します(AWSアカウントの認証情報は取得しておいてください)
y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker build -t y-ishikawa/web . [+] Building 0.1s (7/7) FINISHED docker:desktop-linux --省略-- y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker tag y-ishikawa/web:latest ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/y-ishikawa/web:latest y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$ docker push ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/y-ishikawa/web:latest The push refers to repository [ACCOUNT_ID.dkr.ecr.ap-northeast-1.amazonaws.com/y-ishikawa/web] --省略-- y-ishikawa@y-ishikawa1:~/y-ishikawa-docker-wordpress$
5. ECSタスク定義の作成
タスク定義は、Fargateで起動するコンテナ群の設計図で、docker-compose.yml にあたるものです。
ECS > タスク定義 > 新しいタスク定義の作成
以下の内容で作成をクリック
【基本設定】 起動タイプ: AWS Fargate OS/アーキテクチャ: Linux/ARM64 タスクサイズ: CPU: 2vCPU メモリ: 5GB その他: デフォルト 【コンテナ定義】 ① web コンテナ 名前: ewb イメージ: 先ほどECRにプッシュしたイメージのURI 必須コンテ: はい ポートマッピング: コンテナポート: 80 プロトコル: TCP ポート名: 空欄か任意で入力 アプリケーションプロトコル: HTTP その他: デフォルト ② db コンテナ 名前: db イメージ: mysql:8.0(イメージURIの欄に入力して大丈夫、URIがECRの形式でない場合、自動的にDocker Hubからイメージを取得) 必須コンテナ: はい 環境変数: MYSQL_ROOT_PASSWORD: wordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress HealthCheck: コマンド: CMD-SHELL,mysql -h localhost -u root -p"$MYSQL_ROOT_PASSWORD" -e "USE wordpress" || exit 1 間隔: 10 タイムアウト: 5 再試行: 3 Docker設定 > コマンド: --default-authentication-plugin=mysql_native_password その他: デフォルト ③ cms コンテナ 名前: cms イメージ: wordpress:php8.2-fpm-alpine 必須コンテナ: はい 環境変数: WORDPRESS_DB_HOST: 127.0.0.1 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress スタートアップの依存関係の順序: コンテナ名: db 条件: Healthy その他: デフォルト 【オプション設定】 ボリューム: ボリューム名: 任意 コンテナマウントポイント: マウントポイント①: コンテナ: web ソースボリューム: 設定したボリューム名 コンテナパス: /var/www/html マウントポイント②: コンテナ: cms ソースボリューム: 設定したボリューム名 コンテナパス: /var/www/html
mac を使っている場合は、OS/アーキテクチャでLinux/ARM64
を選ばないとうまくいかないです。
あとは、メモリは4GBか5GBくらいないといけない、cmsコンテナの環境変数WORDPRESS_DB_HOST
は、localhostではなく127.0.0.1
じゃないとうまくいかないなど、はまりポイントが多かったです。
6. ECSサービスを作成してタスクを起動する
作成したタスク定義を実行し、外部からアクセスできるように「サービス」を作成します。
6-1. ECSクラスターの作成
クラスター名: 任意 インフラストラクチャ: AWS Fargate
6-2. サービスの作成
作成したクラスター > サービス > 作成
以下の内容で、作成をクリック
タスク定義ファミリー: 先ほど作成したタスク定義を選択 サービス名: 任意 起動タイプ: FARGATE ネットワーキング: VPC: 任意のもの サブネット: 任意のもの セキュリティグループ: タイプ: HTTP ソース: Anywhere パブリックIP: オン
作成をクリックし、タスクのステータスが「実行中」になっていることを確認します。
7. 動作確認
起動されたタスクのIDをクリックし、IPを確認して、ブラウザからアクセスすると、おなじみの画面が表示されました。
本番構成にアップグレード
最後に、以下のスケーラブルで堅牢な構成にアップグレードします。
ALB → Fargateに、Fargateをプライベートサブネットに、データベースをRDS、コンテンツ共有をEFS、ログをFireLens → S3にします。
1. ネットワーク設定を整備
1-1. NATゲートウェイの作成
パブリックサブネットの一つにNATゲートウェイを作成
1-2. ルートを設定
プライベートサブネットのルートテーブルを編集し、インターネットへの通信(0.0.0.0/0)がNATゲートウェイに向かうように設定します。
これにより、プライベートサブネット内のFargateタスクがコンテナイメージをプルしたり、WordPressが外部にアップデートを確認しに行けるようになります。
2. RDSを作成
以下の設定で作成します。
エンジンのタイプ: MySQL エンジンバージョン: 8.0.41 VPC: Fargateと同じもの サブネットグループ: 任意のプライベートサブネット セキュリティグループ: タイプ: MySQL/Aurora ポート: 3306 ソース: ecsのセキュリティグループ 追加設定: 最初のデータベース名: wordpress その他: 任意で設定
3. EFSを作成
ファイルシステムの作成からカスタマイズを選択して、以下の設定で作成します。
VPC: Fargateと同じもの ファイルシステムのタイプ: リージョン マウントターゲット: サブネット: プライベートサブネットを選択 セキュリティグループ: タイプ: nfs ポート: 2049 ソース: ecsのセキュリティグループ その他: 任意で設定
4. ログ保管用S3バケットを作成
5. Fargate用のタスクロールを作成
ECSタスクのコンテナがAWSサービスへのAPIリクエストを行うことを許可するロールを作成します。
以下設定で作成します。
信頼されたエンティティ: AWSのサービス ユースケース: Elastic Container Service Task 許可ポリシー: AmazonS3FullAccess(FireLensがS3にログを書き込むために必要) AmazonElasticFileSystemClientReadWriteAccess(FargateタスクがEFSをマウントするために必要)
6. タスク定義の更新
既存のタスク定義に以下の変更を加え、新しいリビジョンを作成します。
タスクロール: 先ほど作成したタスクロールを選択 dbコンテナ: 削除する webコンテナ: ログ記録: 「AWS FireLens 経由でS3にログをエクスポートする」 bucket: 作成したS3バケット名 その他: デフォルト cmsコンテナ: 環境変数: WORDPRESS_DB_HOST: RDSのエンドポイント WORDPRESS_DB_USER: RDSで設定したマスターユーザー名 WORDPRESS_DB_PASSWORD: RDSで設定したマスターパスワード WORDPRESS_DB_NAME: RDSで作成したデータベース名 スタートアップの依存関係の順序: 削除する ログ記録: 「AWS FireLens 経由でS3にログをエクスポートする」 bucket: 作成したS3バケット名 その他: デフォルト ボリューム: 既存のボリューム: 削除 ボリュームの追加: ボリューム名: 任意 ボリュームタイプ: EFS ファイルシステムID: 作成したEFSを選択 ルートディレクトリ: / マウントポイントの追加: マウントポイント①: コンテナ: web ソースボリューム: 設定したボリューム名 コンテナパス: /var/www/html マウントポイント②: コンテナ: cms ソースボリューム: 設定したボリューム名 コンテナパス: /var/www/html
ログ記録でFireLensを選択するとログルーティングコンテナ (FireLens)
というコンテナが自動で追加されました。
本番環境では、パスワードなどはSecrets Managerで管理してください。
7. ALBを作成
7-1. ターゲットグループを作成
ターゲットタイプ: IPアドレス プロトコル: HTTP ポート: 80 VPC: Fargateと同じVPC ヘルスチェック: 成功コード: 200-399(wordpressインストール画面にリダイレクトされるのを成功として扱うようにするため)
ALBをECS用で利用する場合、タスクがスケーリングしても、ECSサービスがALBと連携し、タスクのIPアドレスを自動的に登録・解除するみたいです。
ターゲットグループ作成時は何も登録しなくて大丈夫です。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/service-load-balancing.html
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/alb.html
7-2. ALB作成
スキーム: インターネット向け VPC: Fargateと同じVPC サブネット: 任意のパブリックサブネット セキュリティグループ: タイプ: HTTP ポート: 80 ソース: Anywhere リスナー: プロトコル: HTTP ポート: 80 転送先: 作成したターゲットグループ
8. ECSサービスの更新
8-1. セキュリティグループの修正
ecsにつけていたセキュリティグループに以下のインバウンドルールを追加します。
①: タイプ: HTTP ポート: 80 ソース: ALBのセキュリティグループ ②: タイプ: MySQL/Aurora ポート: 3306 ソース: RDSのセキュリティグループ ③: タイプ: NFS ポート: 2049 ソース: EFSのセキュリティグループ
8-2. ECSサービスの更新
タスク定義: 更新したタスク定義の最新のリビジョンを選択 起動タイプ: FARGATE VPC: これまでと同じVPC サブネット: EFSのマウントターゲットで指定したプライベートサブネットを選択 セキュリティグループ: 前回と同じセキュリティグループ ロードバランシング: 種類: ALB コンテナ: web 80:80 ロードバランサー: 作成したALBを選択 リスナー: 作成したリスナーを選択 ターゲットグループ: 作成したターゲットグループ
9. 動作確認
9-1. ALBのDNS名にブラウザからアクセスし、WordPressの初期設定画面が表示されることを確認
9-2. WordPressのインストールを進め、記事の投稿、画像のアップロードが問題なくできることを確認
記事の投稿を確認
画像のアップロードを確認
9-3. 記事投稿時にRDSの接続数メトリクスが増えていることを確認
9-4. EFSでファイルが永続化できていることを確認
ECSのタスクを停止
タスクが新たに起動されることを確認
ブラウザを更新し、画像が表示されることを確認
9-5. S3バケットにログファイルが出力されていることを確認
これで全てできました!!
まとめ
はまりポイントは多いですが、一つひとつ進めることで理解することができました。
CI/CDやスケーリング設定、サービス間の連携なども今後理解していきたいです。
参考になったら幸いです。
参考記事
クィックスタート: Compose と WordPress
https://docs.docker.jp/compose/wordpress.html
ロードバランサーを使用して Amazon ECS サービストラフィックを分散する
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/service-load-balancing.html
Amazon ECS 用の Application Load Balancer を使用する
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/alb.html
Amazon EFS を利用した Amazon ECS on AWS Fargate での WordPress の実行
https://aws.amazon.com/jp/blogs/news/running-wordpress-amazon-ecs-fargate-ecs/
スタートアップのためのコンテナ入門 – AWS Fargate 編
https://aws.amazon.com/jp/blogs/startup/techblog-container-fargate-1/