0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】XクローンをECS Fargateでデプロイした構成と判断の理由

0
Posted at

はじめに

こんにちは!AWSを学習中のrikutoです。

今回、ポートフォリオとして開発したXクローンをAWSにデプロイしました。

この記事では、構成の全体像と「何を選び、なぜそう判断したか」をまとめます。

対象読者は、これからECS Fargateでポートフォリオをデプロイする人です。
各サービスの基本的な使い方は省略して、判断した内容を中心にまとめています。

Xクローンのリポジトリは以下です。

この構成で実現していること

  1. ECS Fargateでデプロイ
  2. マルチAZ構成
  3. ALB使用
  4. 独自ドメイン + HTTPS化
  5. 画像をS3に保存
  6. メールをSESで送信
  7. ElastiCache for Redisの作成

構成図

RedisForNoded.png

ECS Fargate

マルチAZ + desired count 2

タスクの配置は次のようにしました。

  • 配置先: 2つのAZ(1a / 1c)のプライベートサブネット
  • サービスのdesired count: 2

これにより、各AZに1タスクずつ配置されます。

desired countを2にした理由は2つです。

  • ALBの振り分け先が2つになり、負荷分散が実際に機能する
  • 片方のAZに障害が起きても、もう片方でサービスを継続できる

料金は1タスクの2倍になりますが、本番運用を想定してこの構成にしました。

セキュリティグループはALBからのみ許可

外部からの入口はALBの1箇所に限定しています。

タスクのセキュリティグループでは、ALBのセキュリティグループをソースに指定して、8080番ポートだけを許可しました。

IPアドレス(CIDR)ではなくセキュリティグループを指定した理由は、ALBのIPが固定ではないからです。セキュリティグループで参照すれば、IPが変わってもルールは壊れません。

RDS(PostgreSQL)

プライベートサブネットに配置

RDSはプライベートサブネットに配置しました。

理由は、DBに個人情報が格納されるからです。
インターネットから構造的に到達できない場所に置くことで、外部からの攻撃経路を断っています。

マルチAZ構成にした

マルチAZ構成(Primary + Standby)を採用しました。
可用性と耐久性のためです。

  • 障害発生時にStandbyへ自動で切り替わり、稼働を継続できる(可用性)
  • Standbyへ同期レプリケーションされるため、切り替わってもコミット済みのデータを失わない(耐久性)

エンドポイントは1つのまま切り替わるため、アプリ側の変更は不要です。

DATABASE_URLはSecrets Manager経由で注入

DBの接続情報は、平文の環境変数では持たせていません。
Secrets Managerに保存し、タスク定義のValueFromで注入しています。

  • Secrets Managerに接続URLを丸ごと1キー(DATABASE_URL)で保存
  • ECSのタスク実行ロールに、該当シークレットへの GetSecretValue を許可
  • タスク定義では ARN:DATABASE_URL:: の形式で参照

丸ごと1キーで保存した理由は、Goのコードが最初から接続URLを1本の環境変数で読む実装だったからです。

databaseUrl := os.Getenv("DATABASE_URL")

ElastiCache for Redis

Redisはログイン時のセッション管理に使っています。

構成は次のとおりです。

  • ノードベース: cache.t3.micro
  • マルチAZ + レプリカ1台
  • 通信時暗号化: 有効

RedisもマルチAZにした理由

料金が2倍になっても、マルチAZを採用しました。
可用性のためです。

Redisが停止するとログイン機能ごとサービスが止まります。
停止中はセッションの発行も確認もできません。

セッションデータ自体は軽く、消えても全ユーザーが1回再ログインすれば回復します。
しかし「データの重さ」は軽くても、「稼働していることの重さ」はサービスの生死に直結すると判断しました。

TLS通信

通信時暗号化を有効にしています。

当初はElastiCache Serverlessで構築しており、ServerlessはTLS通信が必須です。
そのためGo側をTLS対応にしました。

その後、料金を抑えるためノードベースに移行しました。
通信が暗号化されている方が安全なため、有効のまま運用しています。

Go側がTLSに対応できておらず、エラーになったときの記事です。

SES + Secrets Manager

メール送信はSESを使い、アプリ → SES → ユーザーの流れで配信しています。

SMTP方式を採択した理由

SMTP方式を選びました。

SESの利用方法には、SDK(sesv2)方式とSMTP方式があります。
SMTPにした理由は2つです。

  • 既存のGoコードが net/smtp で実装済みのため、コード変更を最小化できる
  • SDK方式はAWSのライブラリにコードが依存するため、AWSへの依存度が高くなる

SMTPなら、接続先の環境変数を切り替えるだけです。
ローカル(Docker)と本番を同じコードで動かせます。

SDK方式について詳しく知りたい方は、公式ドキュメントを参照してください。

認証情報の管理

SMTP認証情報(実体はIAMユーザー)はSecrets Managerに保存しました。
Goのコードが環境変数 SMTP_USERSMTP_PASS を必要としますが、DATABASE_URLと同様に、タスク定義のValueFromで注入しています。

平文の環境変数にしなかった理由は2つです。

  • 平文で書いた値はタスク定義に露出する。閲覧権限があれば誰でも読めてしまうが、ValueFromならタスク定義に載るのはARNだけ
  • SMTP認証情報が漏れると、第三者が自分のSES経由でメールを送信できてしまう。スパム送信に悪用されれば、課金の発生に加えて送信ドメインの信頼も下がる

まとめ

この構成での一番の学びは、「正解は状況で変わるからこそ、判断に理由が要る」ということでした。

マルチAZもプライベートサブネットも、可用性やセキュリティと引き換えに料金がかかります。
要件を満たすだけなら、もっと安い構成もあり得ました。

その中で「何のために、いくら払うのか」を一つひとつ言語化しながら選んだことが、単に動くものを作る以上の経験になりました。

同じようにポートフォリオをAWSにデプロイする方の参考になれば嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?