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?

Golang APIをAWS ECS Fargateへデプロイする手順

0
Last updated at Posted at 2026-08-01

この記事では、Goで作成したTwitter風APIを、次の構成でAWSへデプロイします。

構成
Amazon ECS Fargate
Application Load Balancer
マルチAZ
Aurora PostgreSQL Serverless v2
ElastiCache for Redis
Amazon ECR
Secrets Manager
Amazon S3
Amazon SES
Route 53
AWS Certificate Manager
CloudWatch Logs

完成後はRoute 53で設定したURLで、APIへアクセスできる構成です。

構成図はこちらです。
exec-25b9e538-d05b-4934-9719-d085529d5bbd.png

1. 全体構成

通信の流れは次のようになります。

ユーザー
  ↓
Route 53
  ↓
ACM証明書
  ↓
Application Load Balancer
  ↓
ECS Fargate(2AZ・2タスク)
  ├─ Aurora PostgreSQL
  ├─ ElastiCache for Redis
  ├─ S3
  ├─ SES
  └─ Secrets Manager

東京リージョンを使用します。
ap-northeast-1

マルチAZ構成として、以下の2つを使用します。
ap-northeast-1a
ap-northeast-1c

2. 事前準備

ローカル環境へ次をインストールします。

インストール
Docker Desktop
AWS CLI
Git
Go
Route 53で利用するドメイン

AWS CLIへログインできることを確認します。

aws sts get-caller-identity

アカウントIDとIAMユーザーのARNが表示されれば準備完了です。

3. アプリケーションをECS向けに準備する

ヘルスチェックAPI

ALBがアプリケーションの状態を確認できるように、認証不要のヘルスチェックAPIを用意します。

r.GET("/health", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"status": "ok"})
})

ローカルで確認します。

curl http://localhost:8080/health

期待する結果は次のとおりです。
{"status":"ok"}

環境変数

アプリケーションは、最低限以下の環境変数を読み取れるようにします。

環境変数
DB_HOST
DB_PORT
DB_NAME
DB_USER
DB_PASSWORD
DB_SSLMODE

REDIS_ADDR
REDIS_PASSWORD
REDIS_TLS

AWS_REGION
S3_BUCKET

MAILER_BACKEND
SES_FROM
ACTIVATION_URL
SECURE_COOKIES

パスワードはコードやDockerイメージへ直接記述しません。

4. Dockerfileを作成する

Goアプリをマルチステージビルドします。

FROM golang:1.26.3-alpine AS build

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=0 GOOS=linux go build \
    -trimpath \
    -ldflags="-s -w" \
    -o /server .

FROM alpine:3.23

RUN apk add --no-cache ca-certificates \
    && adduser -D -H -u 10001 app

COPY --from=build /server /server

USER app

EXPOSE 8080

ENTRYPOINT ["/server"]

ECSタスクがARM64の場合は、イメージもARM64としてビルドします。

docker buildx build \
  --platform linux/arm64 \
  -t twitter-golang:arm64 \
  .

アーキテクチャが一致しない場合、ECSタスクは起動できません。

5. VPCとサブネットを作成する

VPC

例として次のCIDRを使用します。
10.0.0.0/24

サブネット

2つ以上のAZにサブネットを作成します。

用途 AZ CIDR
アプリ/ALB ap-northeast-1a 10.0.0.0/28
アプリ/ALB ap-northeast-1c 10.0.0.32/28
DB ap-northeast-1a 10.0.0.16/28
DB ap-northeast-1c 10.0.0.48/28

ALBを置くサブネットには、Internet Gatewayへのルートが必要です。

0.0.0.0/0 → Internet Gateway

ALBは、各サブネットに最低8個の空きIPアドレスを要求します。小さいサブネットを既存リソースと共有すると、ALB作成時に次のエラーが発生します。

Not enough IP space available

そのため、可能ならALB専用サブネットを用意します。

6. セキュリティグループを作成する

ALB用SG

受信ルール:

ポート 接続元
80 0.0.0.0/0
443 0.0.0.0/0

ECS用SG

受信ルール:

ポート 接続元
8080 ALB用SG

ECSの8080番ポートを、直接インターネットへ公開しないことが重要です。

RDS用SG

受信ルール:

ポート 接続元
5432 ECS用SG

Redis用SG

受信ルール:

ポート 接続元
6379 ECS用SG

IPアドレスではなく、セキュリティグループ同士で許可すると管理しやすくなります。

7. Aurora PostgreSQLを作成する

RDSコンソールから「データベースの作成」を選びます。
設定例:

エンジン: Aurora PostgreSQL
構成: 標準作成
インスタンス: Serverless v2
パブリックアクセス: なし
VPC: 作成したVPC
DBサブネットグループ: 2AZを含むグループ
セキュリティグループ: RDS用SG

マルチAZ化

ライターを1a、リーダーを1cに配置します。

database-instance-1: Writer / ap-northeast-1a
database-instance-2: Reader / ap-northeast-1c

8. ElastiCache for Redisを作成する

ElastiCacheでRedis OSSまたはValkey互換キャッシュを作成します。
設定例:

VPC: アプリと同じVPC
転送中の暗号化: 有効
認証トークン: 有効
ポート: 6379
セキュリティグループ: Redis用SG

ECSへは次のように設定します。

REDIS_ADDR=master.example.cache.amazonaws.com:6379
REDIS_TLS=true

RedisパスワードはSecrets Managerから渡します。

9. Secrets Managerへパスワードを保存する

次のようなシークレットを作成します。

twitter-golang/database
twitter-golang/redis

保存する内容:

twitter-golang/database → DBユーザーのパスワード
twitter-golang/redis    → Redisの認証トークン

ECSタスク定義では、通常の環境変数ではなく「シークレット」として設定します。

{
  "secrets": [
    {
      "name": "DB_PASSWORD",
      "valueFrom": "DBシークレットのARN"
    },
    {
      "name": "REDIS_PASSWORD",
      "valueFrom": "RedisシークレットのARN"
    }
  ]
}

ECSがシークレットを取得するには、タスク実行ロールへ次の権限が必要です。

{
  "Effect": "Allow",
  "Action": "secretsmanager:GetSecretValue",
  "Resource": [
    "DBシークレットのARN",
    "RedisシークレットのARN"
  ]
}

シークレットを変更しただけでは、稼働中コンテナには反映されません。ECSサービスで「新しいデプロイの強制」が必要です。

10. 画像保存用S3バケットを作成する

S3バケットはグローバルで一意の名前にします。
twitter-golang-images-<AWSアカウントID>-ap-northeast-1

設定:
パブリックアクセスをすべてブロック
ACL無効
デフォルト暗号化を有効
署名付きURLでアップロード
オブジェクトキーを images/* に限定

CORS例:

{
  "CORSRules": [
    {
      "AllowedOrigins": [
        "https://example.com"
      ],
      "AllowedMethods": [
        "PUT"
      ],
      "AllowedHeaders": [
        "*"
      ],
      "ExposeHeaders": [
        "ETag"
      ],
      "MaxAgeSeconds": 3600
    }
  ]
}

タスクロールには最小限の権限だけを付与します。

{
  "Effect": "Allow",
  "Action": "s3:PutObject",
  "Resource": "arn:aws:s3:::バケット名/images/*"
}

署名付きURLを使えば、フロントエンドへAWS認証情報を渡さずにアップロードできます。

11. SESを設定する

SESでドメインIdentityを作成します。example.com

Route 53を利用している場合、SESが発行するDKIM用CNAMEをDNSへ登録します。さらに、必要に応じて以下を設定します。

  • DKIM
  • SPF
  • DMARC
  • カスタムMAIL FROM

アプリ側の設定例:
MAILER_BACKEND=ses
SES_FROM=noreply@example.com
AWS_REGION=ap-northeast-1
ACTIVATION_URL=https://example.com/activate

タスクロールにSES送信権限を追加します。

{
  "Effect": "Allow",
  "Action": [
    "ses:SendEmail",
    "ses:SendRawEmail"
  ],
  "Resource": "arn:aws:ses:ap-northeast-1:<AWSアカウントID>:identity/example.com"
}

12. IAMロールを作成する

ECSでは、2種類のロールを分けます。

タスク実行ロール

ECS自体が使用します。
用途:

  • ECRからイメージをpull
  • CloudWatch Logsへ出力
  • Secrets Managerから値を取得

タスクロール

アプリケーションが使用します。
用途:

  • S3へ画像を保存
  • SESでメールを送信

アプリケーションへAWSアクセスキーを環境変数で渡す必要はありません。AWS SDKはタスクロールの一時認証情報を自動的に使用します。

13. ECRへDockerイメージをpushする

リポジトリ作成

aws ecr create-repository \
  --region ap-northeast-1 \
  --repository-name golang-twitter

ECRへログイン

aws ecr get-login-password \
  --region ap-northeast-1 |
docker login \
  --username AWS \
  --password-stdin \
  <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com

ARM64イメージをbuild・push

docker buildx build \
  --platform linux/arm64 \
  -t <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/golang-twitter:arm64-v1 \
  --push \
  .

ECSタスク定義のCPUアーキテクチャもARM64にします。

{
  "runtimePlatform": {
    "cpuArchitecture": "ARM64",
    "operatingSystemFamily": "LINUX"
  }
}

14. ALBとターゲットグループを作成する

ターゲットグループ

設定例:

ターゲットタイプ: IP
プロトコル: HTTP
ポート: 8080
ヘルスチェックパス: /health
成功コード: 200

Fargateのawsvpcネットワークモードでは、ターゲットタイプをinstanceではなくipにします。

ALB

設定:

スキーム: Internet-facing
AZ: ap-northeast-1a / ap-northeast-1c
セキュリティグループ: ALB用SG

最初は80番リスナーを作り、ターゲットグループへ転送します。

15. ECSタスク定義を作成する

設定例:

起動タイプ: AWS Fargate
OS: Linux
CPUアーキテクチャ: ARM64
コンテナポート: 8080
ログ: awslogs

環境変数例:

DB_HOST=<Auroraクラスタエンドポイント>
DB_PORT=5432
DB_NAME=postgres
DB_USER=twitter_app
DB_SSLMODE=require

REDIS_ADDR=<Redisエンドポイント>:6379
REDIS_TLS=true

AWS_REGION=ap-northeast-1
S3_BUCKET=<S3バケット名>

MAILER_BACKEND=ses
SES_FROM=noreply@example.com
ACTIVATION_URL=https://example.com/activate
SECURE_COOKIES=true

シークレット:

DB_PASSWORD
REDIS_PASSWORD

CloudWatch Logsの例:

ロググループ: /ecs/twitter-golang-task
ストリームプレフィックス: ecs

HealthCheck(オプション)を追加

項目 設定値
コマンド CMD-SHELL,curl -fsS http://localhost:8080/health || exit 1
間隔 30
タイムアウト 5
開始期間 30
再試行 3

それぞれの値には次の意味があります。

  • command:コンテナ内部で実行する確認コマンド
  • interval:ヘルスチェックを実行する間隔
  • timeout:何秒応答しなければ失敗と判断するか
  • retries:何回連続で失敗したらUNHEALTHYにするか
  • startPeriod:起動直後の失敗をカウントしない猶予期間
  • curl -fは、HTTP 400や500などのエラーレスポンスを失敗として扱います。成功時の終了コードは0、失敗時は0以外になります。

16. ECSクラスターとサービスを作成する

クラスター

twitter-golang-cluster

インフラストラクチャはAWS Fargateを選びます。

サービス

設定例:

サービス名: twitter-golang-service
必要タスク数: 2
サブネット: ap-northeast-1a / ap-northeast-1c
パブリックIP: 有効
セキュリティグループ: ECS用SG
ロードバランサー: 作成したALB
ターゲットグループ: 作成したターゲットグループ
コンテナ: twitter-golang
ポート: 8080

低コスト構成では、Fargateを公開サブネットへ配置し、ECS用SGでALBからの通信だけを許可できます。
より安全な本番構成では、Fargateをプライベートサブネットへ配置し、NAT GatewayまたはVPC Endpointを利用します。

サービス作成後、タスクが2AZへ分散していることを確認します。

ap-northeast-1a: 1タスク
ap-northeast-1c: 1タスク

17. Route 53でドメインを設定する

Route 53でドメインを購入、またはホストゾーンを作成します。
例:

example.com
ALBを指すAレコードを作成します。
レコード名: example.com
タイプ: A
Alias: 有効
Alias先: Application Load Balancer

ALBへはIPアドレスではなくAliasレコードを設定します。

18. ACMでHTTPS証明書を作成する

ACMで証明書をリクエストします。

example.com
*.example.com

検証方法はDNS検証を選びます。
Route 53へ検証用CNAMEを登録し、証明書が次の状態になるまで待ちます。

Issued

ALBへ443番HTTPSリスナーを追加します。

HTTPS :443
証明書: ACM証明書
転送先: ECSターゲットグループ

80番リスナーはHTTPSへリダイレクトします。

HTTP :80 → HTTPS :443
Status: 301

19. 動作確認

HTTPS

curl -i https://example.com/health

期待する結果:

HTTP/2 200

HTTPリダイレクト

curl -I http://example.com

期待する結果:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/

ALBターゲット

ターゲットグループで2台とも次の状態になっていることを確認します。

healthy

ECS

desiredCount: 2
runningCount: 2
pendingCount: 0

CloudWatch Logs

以下のログがあればアプリは起動しています。

Listening and serving HTTP on :8080

まとめ

今回のデプロイでは、単にコンテナをECSで起動するだけでなく、以下を組み合わせました。

ECS Fargateへデプロイする際にしたこと
Fargateによるコンテナ実行
ALBによる負荷分散
2AZへのタスク分散
Aurora Writer/Readerによる可用性
Secrets Managerによる認証情報管理
S3署名付きURLによる画像アップロード
SESによるメール送信
Route 53とACMによる独自ドメイン・HTTPS
CloudWatch Logsによる障害調査

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?