
WordPress
イベント
マガジン
該当するコンテンツが見つかりませんでした
技術ブログ
こんにちは。ファインディのPlatform開発チームでSREを担当している 大矢 です。 2026年はファインディのSREについて1ヶ月に1本ペースで発信していきます。今回はその第1弾として、ファインディにおけるSREの体制についてご紹介します。 この記事では、SREチーム(現在のPlatform開発チーム)がどのように発足し、現在どのような体制で運用しているのかをお伝えします。SREに興味がある方、特にこれからSREを目指す方に読んでいただけますと幸いです。 目次 目次 はじめに Platform開発チームのSREとEmbedded SREの役割分担 Platform開発チームのSREとは Embedded SREとは 役割の違い SREチームの発足まで SREがいなかった時期(〜2023年8月) 1人目SRE入社後(2023年9月〜2024年3月) SREチーム発足後(2024年4月〜) チームの変化 2024年 2025年 2026年以降 まとめ はじめに 2026年1月現在、ファインディでは「Platform開発チーム」が全社横断のSREの役割を担っています。 このチームは、ファインディが提供する複数のプロダクトに対して横断的に信頼性を向上させ、開発チームが事業成長に関わる開発に集中できるような仕組みを構築・提供することを目指しています。 現在は5名のSREメンバーで構成されており、各プロダクトの開発チームと連携しながら、環境の整備や運用改善、ファインディ全社へのSREのイネーブリングに取り組んでいます。 Platform開発チームのSREとEmbedded SREの役割分担 ファインディのSRE体制には、「Platform開発チームのSRE」と「Embedded SRE」という2つの役割があります。 Platform開発チームのSREとは ファインディで単に「SREチーム」といった場合、SREメンバーが所属するPlatform開発チームを指します。私たちはこのチームに所属しています。 私たちのチームではSREとPlatform Engineeringを推進しており、弊社内では「横断SRE」や「Platform SRE」と呼ばれることもあります。 私たちは「SREの文化を組織全体に根付かせ、開発チームが自律的にSREを実践できるように支援する」というビジョンを掲げています。このビジョンについては別の機会に詳しく紹介したいと思います。 なお、ローンチから日が浅いプロダクトなど、プロジェクト規模が比較的小さいプロダクトには後述のEmbedded SREが在籍していないため、Platform開発チーム/SREがプロダクト固有のタスクも含めて対応しています。 Embedded SREとは Platform開発チームのSREメンバーとは別に、各プロダクトの開発チームには「Embedded SRE」と呼ばれるメンバーが在籍しています。 Embedded SREは、SREチーム発足前から各プロダクトの開発チーム内でSRE的な立ち回りをしていたメンバーです。Platform開発チーム発足後の現在でも、プロダクトに特化したタスクについては引き続き担当しています。 役割の違い Platform開発チームのSRE : プロダクト横断的な信頼性向上、共通基盤の整備 Embedded SRE : 特定プロダクトに特化した信頼性向上、プロダクト固有の課題対応 この2つの役割が連携することで、全社的な視点とプロダクト固有の視点の両方から、信頼性の向上に取り組んでいます。 SREチームの発足まで SREがいなかった時期(〜2023年8月) 実は、ファインディには2023年9月までSREは1人も在籍していませんでした。各プロダクトの開発チーム内で、クラウドやインフラに詳しいメンバーがSRE的な役割を担っていました。 プロダクト開発をメインにしながら、障害対応やインフラの改善も同時に行うという状況が続いていました。 サービスが成長するにつれて、信頼性向上やクラウド・インフラの整備がより重要になり、専門的に取り組む必要性が高まっていきました。 1人目SRE入社後(2023年9月〜2024年3月) 2023年9月、ファインディに1人目のSREが入社しました。ただし、最初はチームではなく「1人SRE」としての活動でした。 この時期は、ファインディの新規サービスの立ち上げのための環境構築や、それまで実現したくても手の付けられなかった課題に対応していきました。 SREチーム発足後(2024年4月〜) 2024年4月、2人目のSREメンバーが加わり、正式に「SREチーム」が発足しました。1人から2人になったことで、チームとしての活動が本格的にスタートしました。 その後、メンバーが徐々に増え、2026年1月現在では5人体制となっています。組織の成長に伴い、チーム名も「Platform開発チーム」に変更されました。 チームの変化 2024年 チーム発足時からしばらくの間、SREチームはマネジメント経験のあるシニアメンバーのみで構成されていました。当時はチームマネジメントは必要最小限にとどめ、マネージャーもプレイングマネージャーとしてメンバーと同等のタスクを担当していました。 タスク管理には「かんばん」を利用し、各自で優先順位付けとチーム内外の合意、タスクのクローズまでおこなっていました。 また、この年の12月にSREチーム初のジュニアメンバーがチームにジョインしました。 2025年 2025年は、ファインディがAI関連の新プロダクトを中心に多くのリリースをおこなった年でした。新プロダクトのリリースに伴い、SREチームには環境構築やインフラ整備の依頼が集中しました。 この状況に対応するため、構築作業の短縮化とトイルの削減が急務となりました。具体的には、新環境を3日で提供できるようTerraformのモジュールを汎用化し、Terraform Testの導入による環境構築の信頼性向上も実現しました。 tech.findy.co.jp tech.findy.co.jp そしてDevinを使ったユーザー管理業務の自動化など、さまざまな効率化施策に取り組みました。 tech.findy.co.jp その他、WordPressのShifter移行やFlatt Security様提供のTakumi導入など、セキュリティ強化にも注力しました。 tech.findy.co.jp tech.findy.co.jp この年にもジュニアメンバーが増え、チームの育成やナレッジ共有の重要性も高まりました。 ファインディでは2026年もより多くの成長を目指しており、チームとしての立ち回りの変化も求められています。 2026年以降 2026年1月現在、Platform開発チームはシニア2名、ジュニア3名の5人体制で運用されています。 チーム運営の面では、これまでの「かんばん」でトイルや細かなタスク管理をおこない、構築や1ヶ月以上かかるタスクはロードマップを引くようになり、中期的な視点でSRE活動を計画できるようになりました。 2026年度も引き続きプロダクトが増え続ける見込みです。 現在の体制でファインディの全てのプロダクトを見ていくことは難しくなるため、環境構築やプロダクトのクラウド運用を開発チーム主体でおこなえるよう、ファインディ全体へのSRE文化の浸透を推進します。 新規プロダクト立ち上げ時や環境追加時には、開発チームの担当メンバーに主導していただき、Platform開発チームはサポート役として次のような支援をおこないます。 簡単に新規環境を構築するための仕組みの提供(汎用Terraformモジュール、環境構築のClaude CodeのPlugin) 構築・運用のレクチャー これらの施策により、SREが環境構築を直接おこなうのではなく、開発チームが自律的に構築・運用できるような仕組み作りとイネーブリングに注力していきます。 まとめ ファインディのSREは、2023年9月の1人目入社から始まり、約2年半で5人体制のPlatform開発チームへと成長してきました。 Platform開発チーム/SREとEmbedded SREが連携することで、全社的な視点とプロダクト固有の視点の両方から信頼性向上に取り組んでいます。まだまだ発展途上のチームですが、これからもファインディのサービス成長を支えるべく、日々改善を続けています。 ファインディでは一緒に会社を盛り上げてくれるメンバーを募集中です。興味を持っていただいた方はこちらのページからご応募お願いします。 herp.careers
背景:公開されたWebアプリへの脆弱性スキャンの観測 インターネットにWebアプリケーションを公開した瞬間から、そのシステムは世界中の攻撃者による脆弱性スキャンの対象になります。多くの場合は攻撃に至る前の 「調査段階」ですが、近年の攻撃は高度かつ自動化されており、スキャン結果が攻撃の機会を示すものであれば、即座に脆弱性を突かれる懸念があります。 例として下記の画像はAmazon Web Services(AWS)において、検証用に用意した環境でのAWS WAFのコンソール画面です。 日時は伏せていますが、日常的に数百〜数万件のリクエストがブロックされていることが確認できます。 これ
本記事は 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 http://localhost:8080でローカルサーバーにアクセスすると、WordPressの初期設定画面が開きます。 まずは言語設定が聞かれるので、日本語を選択します。 次にデータベースの接続設定画面になりますが、こちらは.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" } }


.png)


.png)













