🕸️

Subnet Anastomosis(サブネット吻合術)- ECSで稼働しているサービスにIPv6を対応させてみた

に公開

はじめに - 問題の発覚

この方法を用いることで、2025年9月からサポートされたECS IPv6-onlyや既存のdual-stack環境でも、複雑な設定を回避して安全にIPv6対応を実装できます。

本記事では、この問題にどう対処し、最終的にALB専用サブネットという解決策にたどり着いたかを詳しく解説します!
最後の余談も見ていただけると幸いです!!🫶

既存アーキテクチャ(IPv4のみ)

最初の構成は以下のようなシンプルなものでした。

この構成では、ALBとECSが同じサブネット内に配置されており、すべてIPv4で通信していました。

失敗パターン - 既存サブネットにIPv6を追加

IPv6対応のため、既存のサブネットにIPv6設定を追加しました

resource "aws_subnet" "public_1a" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
  assign_ipv6_address_on_creation = true  # ←これを追加
  ipv6_cidr_block = cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 1)
}

結果として以下のような問題が発生

発生したエラー

IPv6検証のためサブネット設定を変更したところ、以下の問題が発生(事前にdualStackを有効、ecsのバージョンも問題ない)

  • ResourceInitializationError: failed to download env files from S3
  • TargetNotConnectedException: The execute command failed due to an internal error
  • ECSタスクの起動に失敗
  • 開発チーム全体のデプロイ停止

解決策 - ALB専用サブネット分離アーキテクチャ

問題を解決するため、以下のようなサブネット分離アプローチを採用しました:

実装のポイント

1. ALB専用サブネットの作成

# ALB専用サブネット(IPv6対応)
resource "aws_subnet" "alb_public_1a" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.10.0/24"  # 既存と重複しない範囲
  ipv6_cidr_block = cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 10)
  assign_ipv6_address_on_creation = true
  availability_zone = "ap-northeast-1a"
  
  tags = {
    Name = "alb-public-1a"
    Type = "ALB-Only"  # 用途を明確化
  }
}

resource "aws_subnet" "alb_public_1c" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.11.0/24"
  ipv6_cidr_block = cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 11)
  assign_ipv6_address_on_creation = true
  availability_zone = "ap-northeast-1c"
  
  tags = {
    Name = "alb-public-1c"
    Type = "ALB-Only"
  }
}

2. ALBのサブネット変更

resource "aws_lb" "alb" {
  name = "demo-alb"
  load_balancer_type = "application"
  ip_address_type = "dualstack"  # IPv4/IPv6両対応
  
  # 新しいALB専用サブネットに変更
  subnets = [
    aws_subnet.alb_public_1a.id,   # 新規ALB専用サブネット
    aws_subnet.alb_public_1c.id    # 新規ALB専用サブネット
  ]
}

3. ECSは既存サブネットをそのまま使用

resource "aws_ecs_service" "app" {
  # 既存のECS設定はそのまま
  network_configuration {
    subnets = [
      aws_subnet.public_1a.id,   # 既存サブネット(IPv4のみ)
      aws_subnet.public_1c.id    # 既存サブネット(IPv4のみ)
    ]
    security_groups = [aws_security_group.ecs.id]
  }
}

なぜこの方法でIPv6化できるのか

1. レイヤー分離によるメリット

Internet (IPv6/IPv4)

WAF (IP制御 - IPv6/IPv4対応)  

ALB (IPv6/IPv4受信 - 新しいサブネットに配置)

ECS (IPv4のみで動作 - 既存サブネットに配置、影響なし)

2. ALBの役割

  • 外向き: IPv6/IPv4両方のリクエストを受信
  • 内向き: IPv4のみでECSと通信
  • 配置: IPv6対応の新しいサブネットに配置

3. サブネット分離のメリット

ALB専用サブネット

  • IPv6アドレス自動割り当て有効
  • ALBのみが使用
  • ECSとは独立したサブネット

ECS専用サブネット

  • IPv4のみ
  • 既存の動作を維持
  • IPv6の影響を受けない

4. 段階的実装が重要

  1. VPC IPv6有効化: assign_generated_ipv6_cidr_block = true
  2. ALB専用サブネット作成: IPv6対応の新しいサブネット
  3. WAF IPv6対応: IPv6用IPセットとルール追加
  4. ALB移動: 新しいサブネットに移動し、dualstack化
  5. Route53 AAAAレコード: IPv6 DNS設定
terraform apply -target="aws_vpc.main"
terraform apply -target="aws_subnet.alb_public_1a" -target="aws_subnet.alb_public_1c"
terraform apply -target="aws_wafv2_ip_set.administrator_ipv6"
terraform apply -target="aws_lb.alb"
terraform apply -target="aws_route53_record.main_ipv6"

得られた知見

1. IPv6化の複雑さを実感

  • 各サービス個別のIPv6対応だけでは不十分
  • 複数コンポーネント間の協調設定が重要
  • ネットワーク設定変更の影響範囲は予想以上に広い
  • 段階的かつ慎重な変更が必要

2. サブネット分離が解決策

  • ALBとECSで異なるサブネットを使用
  • ECSが稼働しているサブネットは必ずIPv4のままで設定

まとめ

ECSのIPv6対応は直接的なアプローチでは問題が発生しましたが、ALB専用サブネットの分離という解決策により、間接的にIPv6化することに成功しました。
インフラには慎重な設計と段階的アプローチが重要であることを改めて実感しました。

余談

Anastomosisとは、血管や腸管、神経などの管状の構造物を互いに繋げ合わせること、またはそれらが互いに繋がっている状態を指します。手術でつなぎ合わせる「吻合術」を指すこともあります。

この記事の筆者はとある医療ドラマが好きすぎて、Subnet Anastomosis(サブネット吻合術)と勝手に名づけました!
同じような構成でIPv6化を対応したい時に、「サブネットアナストモーシスを使ってみよう」と思っていただけると嬉しいです❤️

BLT SDC Tech Blog

Discussion