本記事は TechHarmony Advent Calendar 2025 12/22付の記事です。 |
こんにちは、稲葉です。
アドベントカレンダーの機会で、普段触っていないコンテナに触れてみようと思いました。
本記事ではコンテナでWordPressサイトを作成し、Amazon ECSにデプロイするところまで試してみようと思います。
構成
本記事で試す構成です。
検証用にローカルPCのDockerでWordPressサイトを構築します。
その後、本番用にECSでWordPressを公開します。
ローカルPCにWordPressサイトを構築する
まずはdocker composeでWordPress環境を作成してみました。
下記のような構成で作成しました。
. ├── docker-compose.yml ├── .env ├── nginx │ ├── default.conf │ └── nginx.conf └── php-fpm ├── Dockerfile └── php.ini
| ファイル名 | 内容 |
| ./docker-compose.yml | 複数コンテナをまとめて管理するためのdocker compose用設定ファイル |
| .env | docker-compose.yml用の環境変数を記載するファイル (コード例は本記事の最後) |
| ./nginx/default.conf | nginxのサーバー設定用ファイル、php-fpm コンテナへ転送する設定などを記載 (コードは本記事の最後) |
| ./nginx/nginx.conf | nginxの基本設定ファイル(コードは本記事の最後) |
| ./php-fpm/Dockerfile | WordPressとphp-fpmの環境を作るためのDockerファイル ※nginx上でWordPressを公開する場合、WordPressはphp-fpmと同時に使用する必要がある (コードは本記事の最後) |
| ./php-fpm/php.ini | phpの設定ファイル(コードは本記事の最後) |
docker-compose.yml
下記設定docker-compose.ymlファイルで、ローカルPCのWordPressサイトを構築します。
services:
nginx:
image:nginx:alpine
ports:
- "8080:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- wordpress_data:/var/www/html
depends_on:
- php-fpm
networks:
- wordpress-network
php-fpm:
build:
context:./php-fpm
dockerfile:Dockerfile
volumes:
- wordpress_data:/var/www/html
environment:
WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
depends_on:
- mysql
networks:
- wordpress-network
mysql:
image:mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
networks:
- wordpress-network
volumes:
wordpress_data:
mysql_data:
networks:
wordpress-network:
driver:bridge
このdocker-compose.ymlでは3つのコンテナを立てる設定が記載されています。
- nginx
- php-fpm
- mysql
それぞれのコンテナの設定について簡単に記載します。
nginxコンテナ
image:nginx:alpineで、nginxのコンテナはnginx:alpineというイメージを元にコンテナを作成する設定をしています。
ports: “8080:80″で、ローカルホストの8080番ポートにアクセスした際にコンテナの80番ポートに転送する設定をしています。
volumes: ./nginx/nginx.conf:/etc/nginx/nginx.confで、ローカルPCの./nginx/nginx.confとコンテナ環境の/etc/nginx/nginx.confを同期しています。
volumes: ./nginx/default.conf:/etc/nginx/conf.d/default.confでも同様です。
volumes: wordpress_data:/var/www/htmlでは、wordpress_data名前付きボリュームでコンテナ内の/var/www/html にマウントする設定をしています。
名前付きボリュームとは、ローカルPCのDockerで名前を付けて管理するボリュームになります。ローカルPC内の他のDockerコンテナからもマウントして使用可能です。
depends_on: php-fpmで、php-fpmのコンテナを作成した後にnginxコンテナを作成する設定をしています。
networks: wordpress-networkで、wordpress-networkというDockerネットワークにnginxコンテナを属させる設定を行っています。
Dockerネットワークに属すことで、属しているコンテナ間でサービス名を使って名前解決可能になります。
php-fpmコンテナ
build: context:./php-fpmで、./php-fpmディレクトリをビルドコンテキストとして使用する設定をしています。
build: dockerfile:Dockerfileで、コンテナを立てるときに使用するDockerfileを指定しています。
volumesは、nginxと同様でコンテナ内の/var/www/html に名前付きボリュームのwordpress_dataをマウントしています。
この設定によって、php-fpmコンテナとnginxコンテナの/var/www/htmlは同期されます。
environment: WORDPRESS_DB_HOST:${WORDPRESS_DB_HOST}で、環境変数WORDPRESS_DB_HOSTの値に.envファイルのWORDPRESS_DB_HOSTで指定している値を使用する設定をしています。
他も同様になります。
mysqlコンテナ
volumes: mysql_data:/var/lib/mysqlで、このデータベースのデータをmysql_dataという名前付きボリュームで管理することで永続化しています。
他の設定は、他のコンテナのところで説明しているため省略します。
ローカルPCのWordpressサイトに接続する
コードができたら下記コマンドで、nginxとphp-fpm、mysqlの3つのコンテナを立てて、ローカルPCのWordPressサイトを構築できます。
docker compose up -d
まずは言語設定が聞かれるので、日本語を選択します。
次にデータベースの接続設定画面になりますが、こちらは.envに書いてある下記内容で入力します。
| 項目名 | 値 |
| データベース名 | wordpress |
| ユーザー名 | wordpress |
| パスワード | wordpress_password |
| データベースホスト | mysql |
| テーブル接頭辞 | wp_ |
そのまま初期設定とテスト記事を書くと、このように記事を表示できました。
これにてローカルPCのWordPress環境構築は完了です。
AWS環境にWordPressサイトを構築する
それでは、AWS環境にWordPressサイトを構築していきます。
ECRリポジトリを作成する
まずはECSで実行するためのコンテナイメージファイルを配置するためのECRリポジトリを作成します。
AWSの環境では、MySQLデータベースのところはRDSが担当するので、mysqlコンテナは立てません。
下記のシェルスクリプトを作成し、AWS CLIでECRリポジトリを作成しました。
※下記シェルスクリプトを実行する前に、aws loginなどでAWSの認証を通してください。
. ├── docker-compose.yml ├── .env ├── nginx ├── php-fpm └── create-ecr.sh <- new
#!/bin/bash
# 設定
AWS_REGION="ap-northeast-1"
PROJECT_NAME="wordpress"
echo "=== ECRリポジトリを作成 ==="
# Nginx用ECRリポジトリを作成
echo "Nginx用ECRリポジトリを作成中..."
aws ecr create-repository \
--repository-name ${PROJECT_NAME}-nginx \
--region ${AWS_REGION}
# PHP用ECRリポジトリを作成
echo "PHP用ECRリポジトリを作成中..."
aws ecr create-repository \
--repository-name ${PROJECT_NAME}-php \
--region ${AWS_REGION}
# アカウントIDを取得
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo "=== ECRリポジトリ作成完了 ==="
echo "Nginx ECR URL: ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${PROJECT_NAME}-nginx"
echo "PHP ECR URL: ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${PROJECT_NAME}-php"
echo ""
echo "次に ./image-push.sh を実行してイメージをプッシュしてください"
ECRにpushするイメージを作成する
ECRにプッシュするために、nginx用とphp-fpm(とwordpress)用のイメージを作成します。
. ├── docker-compose.yml
├── .env
├── nginx
├── php-fpm
├── create-ecr.sh
└── aws-ecs <- new
├── Dockerfile.nginx <- new
└── Dockerfile.php <- new
Dockerfile.nginx
FROM nginx:alpine
# 必要なパッケージをインストール(EFS用)
RUN apk add --no-cache nfs-utils
# Nginxの設定ファイルをコピー
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
# WordPressファイル用のディレクトリを作成
RUN mkdir -p /var/www/html
# EFS用のマウントポイントを作成
VOLUME ["/var/www/html"]
# ヘルスチェック用の設定を追加
RUN echo 'server {' > /etc/nginx/conf.d/health.conf && \
echo ' listen 80;' >> /etc/nginx/conf.d/health.conf && \
echo ' server_name _;' >> /etc/nginx/conf.d/health.conf && \
echo ' location /health {' >> /etc/nginx/conf.d/health.conf && \
echo ' access_log off;' >> /etc/nginx/conf.d/health.conf && \
echo ' return 200 "healthy\\n";' >> /etc/nginx/conf.d/health.conf && \
echo ' add_header Content-Type text/plain;' >> /etc/nginx/conf.d/health.conf && \
echo ' }' >> /etc/nginx/conf.d/health.conf && \
echo '}' >> /etc/nginx/conf.d/health.conf
EXPOSE 80
# Nginxをフォアグラウンドで実行
CMD ["nginx", "-g", "daemon off;"]
Dockerfile.php
FROM php:8.2-fpm # 必要なパッケージをインストール RUN apt-get update && apt-get install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ libzip-dev \ unzip \ nfs-common \ gettext-base \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ && docker-php-ext-install pdo_mysql \ && docker-php-ext-install mysqli \ && docker-php-ext-install zip \ && docker-php-ext-install opcache \ && rm -rf /var/lib/apt/lists/* # WordPressをダウンロードしてインストール RUN curl -O https://wordpress.org/latest.tar.gz \ && tar xzf latest.tar.gz \ && mkdir -p /var/www/html \ && mkdir -p /tmp/wordpress \ && cp -R wordpress/* /tmp/wordpress/ \ && cp -R wordpress/* /var/www/html/ \ && rm -rf wordpress latest.tar.gz \ && chown -R www-data:www-data /var/www/html # wp-config.phpのテンプレートは不要(起動時に作成) # PHP設定をコピー COPY php-fpm/php.ini /usr/local/etc/php/ # 起動スクリプトを作成 RUN echo '#!/bin/bash' > /start.sh && \ echo 'set -e' >> /start.sh && \ echo 'echo "Starting WordPress PHP-FPM container..."' >> /start.sh && \ echo 'echo "DB Host: $WORDPRESS_DB_HOST"' >> /start.sh && \ echo 'echo "DB Name: $WORDPRESS_DB_NAME"' >> /start.sh && \ echo 'echo "DB User: $WORDPRESS_DB_USER"' >> /start.sh && \ echo '' >> /start.sh && \ echo '# WordPressファイルがEFSにない場合はコピー' >> /start.sh && \ echo 'if [ ! -f /var/www/html/wp-config-sample.php ]; then' >> /start.sh && \ echo ' echo "Copying WordPress files to EFS..."' >> /start.sh && \ echo ' cp -R /tmp/wordpress/* /var/www/html/' >> /start.sh && \ echo 'fi' >> /start.sh && \ echo '' >> /start.sh && \ echo '# wp-config.phpを作成' >> /start.sh && \ echo 'cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php' >> /start.sh && \ echo 'sed -i "s/database_name_here/$WORDPRESS_DB_NAME/" /var/www/html/wp-config.php' >> /start.sh && \ echo 'sed -i "s/username_here/$WORDPRESS_DB_USER/" /var/www/html/wp-config.php' >> /start.sh && \ echo 'sed -i "s/password_here/$WORDPRESS_DB_PASSWORD/" /var/www/html/wp-config.php' >> /start.sh && \ echo 'sed -i "s/localhost/$WORDPRESS_DB_HOST/" /var/www/html/wp-config.php' >> /start.sh && \ echo '' >> /start.sh && \ echo '# ファイルの権限を設定' >> /start.sh && \ echo 'chown -R www-data:www-data /var/www/html' >> /start.sh && \ echo '' >> /start.sh && \ echo 'echo "Starting PHP-FPM..."' >> /start.sh && \ echo 'exec php-fpm' >> /start.sh && \ chmod +x /start.sh WORKDIR /var/www/html EXPOSE 9000 CMD ["/start.sh"]
作成したイメージをECRにpushする
次は、作成したDockerfileでイメージを作成し、ECRリポジトリにプッシュします。
下記のシェルスクリプトを作成し、AWS CLIでプッシュしました。
※下記シェルスクリプトを実行する前に、aws loginなどでAWSの認証を通してください。
. ├── docker-compose.yml ├── .env ├── nginx ├── php-fpm ├── create-ecr.sh ├── image-push.sh <- new └── aws-ecs
#!/bin/bash
# 設定
AWS_REGION="ap-northeast-1"
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ECR_REPO_BASE="${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
NGINX_REPO="${ECR_REPO_BASE}/wordpress-nginx"
PHP_REPO="${ECR_REPO_BASE}/wordpress-php"
echo "=== DockerイメージをECRにプッシュ ==="
# ECRにログイン
echo "ECRにログイン中..."
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REPO_BASE}
# Nginxイメージをビルド・プッシュ
echo "Nginxイメージをビルド中..."
docker build -f aws-ecs/Dockerfile.nginx -t ${NGINX_REPO}:latest .
docker push ${NGINX_REPO}:latest
# PHPイメージをビルド・プッシュ
echo "PHPイメージをビルド中..."
docker build -f aws-ecs/Dockerfile.php -t ${PHP_REPO}:latest .
docker push ${PHP_REPO}:latest
echo "イメージプッシュ完了!"
echo "次にTerraformでECS環境を構築してください"
TerraformでAWSリソースを構築する
ECSでWordpressサイトを公開するために必要なAWSリソースを構築します。
量が多いのでTerraformで構築します。
. ├── docker-compose.yml
├── .env
├── nginx
├── php-fpm
├── create-ecr.sh
├── image-push.sh
├── aws-ecs
└── terraform <- new
├── main.tf <- new
├── output.tf <- new
├── variables.tf <- new
└── terraform.tfvars <- new
各コードについては、本記事の最後に記載しています。
次のコマンドを叩くことでAWSリソースを構築します。
cd terraform terraform init terraform plan terraform apply
AWS環境のWordPressサイトに接続する
albのエンドポイントにアクセスするとWordPressの初期設定画面が開きます。
ローカルPCのWordPressサイトと同様に設定することで、WordPressサイトを公開できました。
終わりに
Kiroと二人三脚で構築することができました!
Dockerに触れた経験が少なかったので、WordPress環境を作ることで理解が深まったような気がします。
アドベントカレンダー当日の朝まで書いていました。。
コード
./.env
# MySQL設定 MYSQL_ROOT_PASSWORD=root_password MYSQL_DATABASE=wordpress MYSQL_USER=wordpress MYSQL_PASSWORD=wordpress_password # WordPress設定 WORDPRESS_DB_HOST=mysql WORDPRESS_DB_USER=wordpress WORDPRESS_DB_PASSWORD=wordpress_password WORDPRESS_DB_NAME=wordpress
./nginx/default.conf
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html index.htm;
client_max_body_size 100M;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\. {
deny all;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
./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" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/conf.d/*.conf;
}
./php-fpm/Dockerfile
FROM php:8.2-fpm # 必要なパッケージをインストール RUN apt-get update && apt-get install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng-dev \ libzip-dev \ unzip \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ && docker-php-ext-install pdo_mysql \ && docker-php-ext-install mysqli \ && docker-php-ext-install zip \ && docker-php-ext-install opcache # WordPressをダウンロード RUN curl -O https://wordpress.org/latest.tar.gz \ && tar xzf latest.tar.gz \ && cp -R wordpress/* /var/www/html/ \ && rm -rf wordpress latest.tar.gz \ && chown -R www-data:www-data /var/www/html # PHP設定 COPY php.ini /usr/local/etc/php/ WORKDIR /var/www/html EXPOSE 9000
./php-fpm/php.ini
upload_max_filesize = 100M post_max_size = 100M memory_limit = 256M max_execution_time = 300 max_input_vars = 3000 ; OPcache設定 opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=4000 opcache.revalidate_freq=2 opcache.fast_shutdown=1
./terraform/output.tf
output "alb_dns_name" {
description ="DNS name of the load balancer"
value =aws_lb.main.dns_name
}
output "aurora_cluster_endpoint" {
description ="Aurora cluster endpoint"
value =aws_rds_cluster.main.endpoint
}
output "aurora_reader_endpoint" {
description ="Aurora reader endpoint"
value =aws_rds_cluster.main.reader_endpoint
}
output "ecs_cluster_name" {
description ="Name of the ECS cluster"
value =aws_ecs_cluster.main.name
}
output "efs_file_system_id" {
description ="EFS file system ID"
value =aws_efs_file_system.wordpress.id
}
output "efs_dns_name" {
description ="EFS DNS name"
value =aws_efs_file_system.wordpress.dns_name
}
./terraform/variables.tf
variable "aws_region" {
description ="AWS region"
type =string
default ="ap-northeast-1"
}
variable "project_name" {
description ="Project name for resource naming"
type =string
default ="wordpress"
}
variable "db_username" {
description ="Database username"
type =string
default ="wordpress"
}
variable "db_password" {
description ="Database password"
type =string
sensitive =true
}
./terraform/terraform.tfvars
aws_region = "ap-northeast-1" project_name = "wordpress" db_username = "wordpress" db_password = "your-secure-password-here"
./terraform/main.tf
terraform {
required_providers {
aws ={
source="hashicorp/aws"
version="~> 5.57.0"
}
}
}
provider "aws" {
region = var.aws_region
profile ="inaba"
}
# Data sources
data "aws_availability_zones" "available" {
state ="available"
}
data "aws_caller_identity" "current" {}
# VPC
resource "aws_vpc" "main" {
cidr_block ="10.0.0.0/16"
enable_dns_hostnames =true
enable_dns_support =true
tags ={
Name="${var.project_name}-vpc"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id =aws_vpc.main.id
tags ={
Name="${var.project_name}-igw"
}
}
# Public Subnets
resource "aws_subnet" "public" {
count =2
vpc_id =aws_vpc.main.id
cidr_block ="10.0.${count.index+1}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch =true
tags ={
Name="${var.project_name}-public-subnet-${count.index+1}"
}
}
# Private Subnets
resource "aws_subnet" "private" {
count =2
vpc_id =aws_vpc.main.id
cidr_block ="10.0.${count.index+10}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
tags ={
Name="${var.project_name}-private-subnet-${count.index+1}"
}
}
# Route Table for Public Subnets
resource "aws_route_table" "public" {
vpc_id =aws_vpc.main.id
route {
cidr_block ="0.0.0.0/0"
gateway_id =aws_internet_gateway.main.id
}
tags ={
Name="${var.project_name}-public-rt"
}
}
# Route Table Associations for Public Subnets
resource "aws_route_table_association" "public" {
count =2
subnet_id =aws_subnet.public[count.index].id
route_table_id =aws_route_table.public.id
}
# NAT Gateway for Private Subnets (1台のみ)
resource "aws_eip" "nat" {
domain ="vpc"
depends_on =[aws_internet_gateway.main]
tags ={
Name="${var.project_name}-nat-eip"
}
}
resource "aws_nat_gateway" "main" {
allocation_id =aws_eip.nat.id
subnet_id =aws_subnet.public[0].id
tags ={
Name="${var.project_name}-nat-gateway"
}
depends_on =[aws_internet_gateway.main]
}
# Route Table for Private Subnets (共通)
resource "aws_route_table" "private" {
vpc_id =aws_vpc.main.id
route {
cidr_block ="0.0.0.0/0"
nat_gateway_id =aws_nat_gateway.main.id
}
tags ={
Name="${var.project_name}-private-rt"
}
}
# Route Table Associations for Private Subnets
resource "aws_route_table_association" "private" {
count =2
subnet_id =aws_subnet.private[count.index].id
route_table_id =aws_route_table.private.id
}
# Security Group for ALB
resource "aws_security_group" "alb" {
name_prefix ="${var.project_name}-alb-"
vpc_id =aws_vpc.main.id
ingress {
description ="HTTP from allowed IP"
from_port =80
to_port =80
protocol ="tcp"
cidr_blocks =["x.x.x.x7/32"]
}
ingress {
description ="HTTPS from allowed IP"
from_port =443
to_port =443
protocol ="tcp"
cidr_blocks =["x.x.x.x/32"]
}
egress {
description ="All outbound traffic"
from_port =0
to_port =0
protocol ="-1"
cidr_blocks =["0.0.0.0/0"]
}
tags ={
Name="${var.project_name}-alb-sg"
}
lifecycle {
create_before_destroy =true
}
}
# Security Group for ECS
resource "aws_security_group" "ecs" {
name_prefix ="${var.project_name}-ecs-"
vpc_id =aws_vpc.main.id
ingress {
description ="HTTP from ALB"
from_port =80
to_port =80
protocol ="tcp"
security_groups =[aws_security_group.alb.id]
}
egress {
description ="All outbound traffic"
from_port =0
to_port =0
protocol ="-1"
cidr_blocks =["0.0.0.0/0"]
}
tags ={
Name="${var.project_name}-ecs-sg"
}
lifecycle {
create_before_destroy =true
}
}
# Security Group for EFS
resource "aws_security_group" "efs" {
name_prefix ="${var.project_name}-efs-"
vpc_id =aws_vpc.main.id
ingress {
description ="NFS from ECS"
from_port =2049
to_port =2049
protocol ="tcp"
security_groups =[aws_security_group.ecs.id]
}
egress {
description ="All outbound traffic"
from_port =0
to_port =0
protocol ="-1"
cidr_blocks =["0.0.0.0/0"]
}
tags ={
Name="${var.project_name}-efs-sg"
}
lifecycle {
create_before_destroy =true
}
}
# Security Group for RDS
resource "aws_security_group" "rds" {
name_prefix ="${var.project_name}-rds-"
vpc_id =aws_vpc.main.id
ingress {
description ="MySQL from ECS"
from_port =3306
to_port =3306
protocol ="tcp"
security_groups =[aws_security_group.ecs.id]
}
egress {
description ="All outbound traffic"
from_port =0
to_port =0
protocol ="-1"
cidr_blocks =["0.0.0.0/0"]
}
tags ={
Name="${var.project_name}-rds-sg"
}
lifecycle {
create_before_destroy =true
}
}
# EFS File System
resource "aws_efs_file_system" "wordpress" {
creation_token ="${var.project_name}-efs"
performance_mode ="generalPurpose"
throughput_mode ="provisioned"
provisioned_throughput_in_mibps =10
encrypted =true
tags ={
Name="${var.project_name}-efs"
}
}
# EFS Mount Targets
resource "aws_efs_mount_target" "wordpress" {
count =2
file_system_id =aws_efs_file_system.wordpress.id
subnet_id =aws_subnet.private[count.index].id
security_groups =[aws_security_group.efs.id]
}
# Aurora Subnet Group
resource "aws_db_subnet_group" "main" {
name ="${var.project_name}-aurora-subnet-group"
subnet_ids =aws_subnet.private[*].id
tags ={
Name="${var.project_name}-aurora-subnet-group"
}
}
# Aurora Cluster
resource "aws_rds_cluster" "main" {
cluster_identifier ="${var.project_name}-aurora-cluster"
engine ="aurora-mysql"
engine_version ="8.0.mysql_aurora.3.04.2"
database_name ="wordpress"
master_username = var.db_username
master_password = var.db_password
db_subnet_group_name =aws_db_subnet_group.main.name
vpc_security_group_ids =[aws_security_group.rds.id]
backup_retention_period =7
preferred_backup_window ="03:00-04:00"
skip_final_snapshot =true
deletion_protection =false
tags ={
Name="${var.project_name}-aurora-cluster"
}
}
# Aurora Instance (1台のみ)
resource "aws_rds_cluster_instance" "main" {
identifier ="${var.project_name}-aurora-instance"
cluster_identifier =aws_rds_cluster.main.id
instance_class ="db.r5.large"
engine =aws_rds_cluster.main.engine
engine_version =aws_rds_cluster.main.engine_version
tags ={
Name="${var.project_name}-aurora-instance"
}
}
# CloudWatch Log Group
resource "aws_cloudwatch_log_group" "ecs" {
name ="/ecs/${var.project_name}"
retention_in_days =7
tags ={
Name="${var.project_name}-log-group"
}
}
# ECS Cluster
resource "aws_ecs_cluster" "main" {
name ="${var.project_name}-cluster"
tags ={
Name="${var.project_name}-cluster"
}
}
# IAM Role for ECS Execution
resource "aws_iam_role" "ecs_execution" {
name ="${var.project_name}-ecs-execution-role"
assume_role_policy =jsonencode({
Version="2012-10-17"
Statement= [
{
Action="sts:AssumeRole"
Effect="Allow"
Principal= {
Service="ecs-tasks.amazonaws.com"
}
}
]
})
tags ={
Name="${var.project_name}-ecs-execution-role"
}
}
resource "aws_iam_role_policy_attachment" "ecs_execution" {
role =aws_iam_role.ecs_execution.name
policy_arn ="arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
# CloudWatch Logs用のIAMポリシー
resource "aws_iam_role_policy" "ecs_logs" {
name ="${var.project_name}-ecs-logs-policy"
role =aws_iam_role.ecs_execution.id
policy =jsonencode({
Version="2012-10-17"
Statement= [
{
Effect="Allow"
Action= [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource="arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"
}
]
})
}
# ECS Task Definition
resource "aws_ecs_task_definition" "main" {
family = var.project_name
network_mode ="awsvpc"
requires_compatibilities =["FARGATE"]
cpu ="512"
memory ="1024"
execution_role_arn =aws_iam_role.ecs_execution.arn
volume {
name ="wordpress-efs"
efs_volume_configuration {
file_system_id =aws_efs_file_system.wordpress.id
root_directory ="/"
}
}
container_definitions =jsonencode([
{
name="nginx"
image="${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/${var.project_name}-nginx:latest"
portMappings= [
{
containerPort=80
protocol="tcp"
}
]
essential= true
dependsOn= [
{
containerName="php-fpm"
condition="START"
}
]
mountPoints= [
{
sourceVolume="wordpress-efs"
containerPath="/var/www/html"
readOnly= false
}
]
logConfiguration= {
logDriver="awslogs"
options= {
"awslogs-group" = aws_cloudwatch_log_group.ecs.name
"awslogs-region" = var.aws_region
"awslogs-stream-prefix" = "nginx"
}
}
},
{
name="php-fpm"
image="${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/${var.project_name}-php:latest"
essential= true
mountPoints= [
{
sourceVolume="wordpress-efs"
containerPath="/var/www/html"
readOnly= false
}
]
environment= [
{
name="WORDPRESS_DB_HOST"
value= aws_rds_cluster.main.endpoint
},
{
name="WORDPRESS_DB_NAME"
value= aws_rds_cluster.main.database_name
},
{
name="WORDPRESS_DB_USER"
value= aws_rds_cluster.main.master_username
},
{
name="WORDPRESS_DB_PASSWORD"
value=var.db_password
}
]
logConfiguration= {
logDriver="awslogs"
options= {
"awslogs-group" = aws_cloudwatch_log_group.ecs.name
"awslogs-region" = var.aws_region
"awslogs-stream-prefix" = "php-fpm"
}
}
}
])
tags ={
Name="${var.project_name}-task"
}
}
# Application Load Balancer
resource "aws_lb" "main" {
name ="${var.project_name}-alb"
internal =false
load_balancer_type ="application"
security_groups =[aws_security_group.alb.id]
subnets =aws_subnet.public[*].id
enable_deletion_protection =false
tags ={
Name="${var.project_name}-alb"
}
}
# Target Group
resource "aws_lb_target_group" "main" {
name ="${var.project_name}-tg"
port =80
protocol ="HTTP"
vpc_id =aws_vpc.main.id
target_type ="ip"
health_check {
enabled =true
healthy_threshold =2
interval =30
matcher ="200,302"
path ="/"
port ="traffic-port"
protocol ="HTTP"
timeout =5
unhealthy_threshold =2
}
tags ={
Name="${var.project_name}-tg"
}
}
# ALB Listener
resource "aws_lb_listener" "main" {
load_balancer_arn =aws_lb.main.arn
port ="80"
protocol ="HTTP"
default_action {
type ="forward"
target_group_arn =aws_lb_target_group.main.arn
}
}
# ECS Service
resource "aws_ecs_service" "main" {
name ="${var.project_name}-service"
cluster =aws_ecs_cluster.main.id
task_definition =aws_ecs_task_definition.main.arn
desired_count =1
launch_type ="FARGATE"
network_configuration {
subnets =aws_subnet.private[*].id
security_groups =[aws_security_group.ecs.id]
assign_public_ip =false
}
load_balancer {
target_group_arn =aws_lb_target_group.main.arn
container_name ="nginx"
container_port =80
}
depends_on =[
aws_lb_listener.main,
aws_efs_mount_target.wordpress
]
tags ={
Name="${var.project_name}-service"
}
}





