こちらのページでは、本サイトを支えるAWSインフラ構成と、TerraformによるIaC(インフラのコード化)、およびLambda (Python)を用いた自動化の仕組みについて解説しています。
本サイトの構築に使用した技術(HTML、CSS、JavaScript、Python、Terraform)およびAWSの各マネージドサービスに関する知識は、すべてオンライン教材の活用や生成AIを用いたプロンプトエンジニアリングにより、独学で実装いたしました。
※本サイトのHTML/CSSは、既存のデザインテンプレートをベースにカスタマイズして使用しています。
本サイトは、Amazon S3に配置した静的ファイルを、Amazon CloudFrontおよびRoute 53を介してセキュアに配信しています。
また、S3とLambda(Python)を連携させた自動化パイプラインを構築しており、S3バケットへ新しいイラスト画像を追加・削除すると、HTMLが動的に更新され、自動で「Illustrations」ページに反映される仕組みを実装しています。 さらに、一連のデプロイ完了・失敗のステータスは、SNS(Simple Notification Service)を介してクリエイター本人へリアルタイムで通知されます。
インフラ構成図はこちらになります。 ※構成図をクリックすると、大きなサイズでご覧いただけます。
【制作期間】 約3週間
【設計の思想】 本サイトはマネージドサービスのみで構成し、運用負荷と稼働コストの削減を意識して設計しました。AWS Budgetsにて月5ドルのコストアラートを設定し、個人運用しやすいセキュアかつ低コストな環境となっております。
外部サイトで独自ドメインを取得し、Route 53とCloudFront(OAC構成)を用いた HTTPS通信による、安全かつ低遅延な静的サイト配信環境を構築しました。
全てのリソースをTerraformで管理し、設定漏れの防止と構成の可視化を行っています。
・コンポーネントの分割
s3.tf や lambda.tf 等、9つのサービス毎にファイルを分割して管理することで、確認のしやすさと保守性を高めております。
・コードと環境の分離
固有情報を変数化してvariables.tfにまとめることで、コードと環境を分離し、他の環境での再利用を可能にしています。
・CloudFrontとドメイン紐付けのコード管理
独自ドメインとCloudFrontの紐付けをテスト環境⇒本番環境に変更できるように設定し、また、OAC(Origin Access Control)の設定と、S3バケットポリシーの紐付けをコードで一元管理できるようにしています。
・べき等性を意識した設定管理
「一度適用すれば何度実行しても同じ状態になる(べき等性)」を担保し、手動運用の不確実性を排除しています。
※他サービスのterraformファイルについては、githubに掲載しております。 リンクはこちら>github link
# terraform内の 環境変数の指定
variable "domain_name" {
type = string
default = "nui-raferafe.com"
description = "Route 53やCloudFront、ACMで使用するドメイン名"
}
variable "bucket_name" {
type = string
default = "2026portfolio-nui-bucket"
description = "静的ウェブサイト公開用のS3バケット名"
}
variable "public_key" {
type = string
default = "illustrations.html"
}
variable "template_key" {
type = string
default = "illustrations_template.html"
}
# CloudFrontがS3にアクセスするためのアクセス制御設定(OAC)
resource "aws_cloudfront_origin_access_control" "s3_oac" {
name = "s3-portfolio-oac"
description = "OAC for portfolio S3 bucket"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}
# CloudFront ディストリビューション本体の設定
resource "aws_cloudfront_distribution" "s3_distribution" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
aliases = [var.domain_name] # variables.tf のドメインを適用
# オリジン(配信元となるS3)の設定
origin {
domain_name = aws_s3_bucket.web_bucket.bucket_regional_domain_name
origin_id = "S3-${aws_s3_bucket.web_bucket.id}"
origin_access_control_id = aws_cloudfront_origin_access_control.s3_oac.id
}
S3内の画像フォルダへのイラスト追加・削除をトリガーとして、SQSで10分間実行を遅延させた後、HTMLを自動更新し、実行結果をSNSでメール通知する設計になっています。
・SQSによるバッファリング
複数のイラストを追加・削除した際の、lambdaの同時多発起動を抑え、一括アップロード時の負荷と大量通知によるコスト増加を防止しました。
・HTMLのテンプレート分離
自動生成される公開用HTMLと、元のテンプレートHTMLを分離。万が一自動生成時にプログラムのエラーなどで不具合が起きても、テンプレートからすぐにサイトを正常な状態に復旧できるよう工夫しています。
・CloudFrontのキャッシュクリア
HTMLの自動更新と連動して、CloudFrontの古いキャッシュを削除する設定を追加し、常に最新のサイトが配信されるようにしました。
・不要なlambda実行防止とファイル名によるソート
指定以外のファイル形式がアップロードされた場合は更新処理をしないよう設定しています。また、画面側では画像がファイル名順で並ぶよう、ソート処理を行っています。
※pythonコード全体はgithubに掲載しております。 リンクはこちら>github link
# 4. テンプレート読み込み&置換
template_obj = s3_client.get_object(Bucket=BUCKET_NAME, Key=TEMPLATE_KEY)
template_content = template_obj['Body'].read().decode('utf-8')
marker_regex = r"[\s\S]*"
replacement = f"\n{gallery_html} "
if re.search(marker_regex, template_content):
new_html_content = re.sub(marker_regex, replacement, template_content)
else:
raise ValueError("テンプレートHTML内にマーカーが見つかりません。")
# 6. S3上書き出力
s3_client.put_object(
Bucket=BUCKET_NAME,
Key=PUBLIC_KEY,
Body=new_html_content.encode('utf-8'),
ContentType='text/html'
)
# 6.5 CloudFrontのキャッシュ削除
try:
cloudfront_client.create_invalidation(
DistributionId=DISTRIBUTION_ID,
InvalidationBatch={
'Paths': {'Quantity': 1, 'Items': [f"/{PUBLIC_KEY}"]},
'CallerReference': str(time.time())
}
)
print("CloudFrontのキャッシュ削除要求を送信しました。")
except Exception as cf_err:
print(f"CloudFrontキャッシュ削除スキップ: {str(cf_err)}")