Amazon Web Services ブログ

Amazon EKS が IPv6 サポートを開始

この記事は、Amazon EKS launches IPv6 support を翻訳したものです。

モバイルアプリケーション、IoT、アプリケーションのモダナイゼーションなどの分野におけるインターネットの継続的な成長により、業界全体で IPv6 への移行が進んでいます。128 ビットのアドレス空間を持つ IPv6 では、IPv4 が提供する 43 億の IP アドレスと比較して、340 澗の IP アドレスを提供できます (訳注: 340 澗は 3.4 x 10^38 です)。Amazon Web Services (AWS) は過去数年間で、Elastic Load BalancingAWS IoT CoreAWS Direct ConnectAmazon Route 53Amazon CloudFrontAWS Web Application FirewallS3 Transfer AccelerationAmazon Elastic Container Service (Amazon ECS) など、さまざまなサービスに IPv6 サポートを追加してきました。

その勢いのままに、先日 Amazon Elastic Kubernetes Service (Amazon EKS) は IPv6 のサポートを発表しました。EKS による IPv6 のサポートは、Amazon VPC の IP アドレスが枯渇するという課題に焦点を当てています。これは、IPv4 アドレス空間のサイズによって制限されるものです。多くのお客様から提起されていた重大な懸念事項であり、Kubernetes の “IPv4/IPv6 デュアルスタック” 機能とは異なります。Kubernetes クラスターの管理者は、IPv4 の制限を回避するために時間を費やす代わりに、アプリケーションの移行やスケーリングに集中できます。

EKS における IPv6 サポートの開始により、IPv6 Kubernetes クラスターを作成できます。IPv6 EKS クラスターでは、Pod と Service が IPv6 アドレスを受け取りつつ、レガシー IPv4 エンドポイントが IPv6 クラスターで稼働しているサービスに接続する機能と、Pod がクラスター外のレガシー IPv4 エンドポイントに接続する機能を維持します。クラスター内の Pod 間の通信は、常に IPv6 アドレスが使用されます。VPC (/56) 内では、IPv6 サブネットの IPv6 CIDR ブロックサイズは /64 に固定されます。これにより、2^64 (約 1,800 京) の IPv6 アドレスが提供され、EKS におけるデプロイを拡張できます。

本記事では、デュアルスタック Amazon Virtual Private Cloud (VPC) 内に IPv6 EKS クラスターを作成する方法を紹介します。サンプルとして IPv6 のみのサービスをデプロイし、IPv4 および IPv6 の Ingress (入力) / Egress (出力) 機能を説明します。

IPv6 サポートによる変更点

クラスターの作成時に、クラスターの IP アドレスファミリーとして IPv4 または IPv6 のいずれかを指定するオプションが追加されました。IP アドレスファミリーを指定しない場合、IPv4 が選択されます。クラスターを IPv6 モードで実行するように設定すると、Kubernetes Pod と Service は IPv6 アドレスを受け取ります。

Amazon EKS の IPv6 サポートは、VPC のネイティブな IPv6 機能を活用します。VPC の IPv6 サポートは、新規および既存の VPC で機能します。VPC ごとにオプトインできます。各 VPC には、IPv4 アドレスプレフィックス (CIDR ブロックのサイズは /16 から /28) と、Amazon の GUA (グローバルユニキャストアドレス) 内から一意の /56 IPv6 アドレスプレフィックス (CIDR ブロックのサイズは /56 で固定) が割り当てられます。VPC の各サブネットに、/64 アドレスプレフィックスを割り当てることができます。セキュリティグループ、ルートテーブル、ネットワーク ACL、ピアリング、VPC 内の名前解決などすべての VPC の機能は、IPv4 と同じように動作します。すべてのインスタンスは、対応する DNS エントリと共に IPv4 アドレスと IPv6 アドレスの両方を受け取ります。インスタンスに対して、VPC アドレス範囲から 1 つの IPv4 アドレスのみが消費されます。VPC に関する完全な考慮事項については、EKS ユーザーガイドを参照してください。

IPv6 の世界では、すべてのアドレスがインターネットでルーティング可能です。Node や Pod に関連付けられている IPv6 アドレスはパブリックです。プライベートサブネットは、VPC に Egress-Only インターネットゲートウェイ (EIGW) を作成することでサポートされ、すべてのインバウンドトラフィックをブロックしながらアウトバウンドトラフィックを許可できます。IPv6 サブネットを作成するためのベストプラクティスについては、VPC ユーザーガイドを参照してください。

Pod ネットワーキング

IPv6 は、EC2 ネットワークインターフェイス (ENI) へのプレフィックスの割り当てモードをサポートしています。Amazon VPC Container Network Interface (CNI) プラグインは、プライマリ ENI に付与されたプレフィックスからアドレスを割り当てるように設定されています。IPv4 とは対照的に、IPv6 プレフィックスの割り当ては Node の起動時にのみ行われます。このアプローチは、特に大規模なクラスターにおいて、ネットワーク関連の AWS API のスロットリングを削除し、パフォーマンスを大幅に向上させます。IPv6 プレフィックスの委任で割り当てられた単一のプレフィックスには多くのアドレスがあり (/80、ENI ごとに 10^14 アドレス)、数百万の Pod を持つ大規模なクラスターをサポートするのに十分な大きさです。同様に、ウォームプレフィックスと最小 IP 構成の設定が不要になります。現時点で、VPC CNI は IPv6 クラスターでプレフィックス割り当てモードのみをサポートしており、Nitro ベースの EC2 インスタンスでのみ動作します。

単一の IPv6 プレフィックスは、単一の Node で多くの Pod を実行するのに十分な大きさです。これにより、ENI および IP の制限による max-pods (訳註: 各インスタンスタイプによりサポートされる Pod の最大数。詳細は GitHub の eni-max-pods.txt を参照してください) の制限も効果的に削除されます。IPv6 は max-pods への直接的な依存を取り除きますが、m5.large のように小さなインスタンスタイプでプレフィックス割り当てを使用すると、IP アドレスを使い尽くすよりもずっと前に、インスタンスの CPU やメモリを使い尽くす可能性があります。マネージド型ノードグループと Amazon EKS 最適化 AMI を使用する場合、推奨される Pod の最大数はインスタンスタイプと VPC CNI の設定値に基づいて自動的に計算され設定されます。セルフマネージド型ノードやカスタム AMI を用いたマネージド型ノードグループを使用する場合、EKS 推奨の Pod の最大数を手動で設定する必要があります。セルフマネージド型ノードやカスタム AMI を用いたマネージド型ノードグループのユーザーに対するこれらのプロセスを簡素化するために、max-pod-calculator.sh を利用して、インスタンスタイプと VPC CNI の設定に基づいて Amazon EKS が推奨する Pod の最大数を計算できます。

パケットフロー

Pod から外部の IPv6 エンドポイント

IPv6 VPC 内のプライベートサブネットは、Egress-Only インターネットゲートウェイと構成されます。プライベートサブネット内の Pod からクラスター外部の IPv6 エンドポイントへの通信は、デフォルトでは Egress-Only インターネットゲートウェイ経由でルーティングされます。

Pod から外部の IPv4 エンドポイント

完全に IPv6 へ移行するための業界全体の取り組みが進んでいますが、IPv6 と IPv4 は引き続き共存します。これは、Kubernetes Pod がクラスター外部の IPv4 エンドポイントへの接続を確立する必要があることも示しています。クラスター外部の IPv4 エンドポイントへの接続をサポートするために、EKS は Egress-only (出力専用) の IPv4 モデルを導入しています。

EKS は、Pod への IPv4 アドレスの割り当ておよび設定のために、VPC CNI にチェインされる host-local CNI を実装しました。CNI プラグインは、169.254.172.0/22 の範囲から、Pod にホスト固有のルーティング不可能な IPv4 アドレスを設定します。Pod に割り当てられた IPv4 アドレスは Node に固有であり、Kubernetes コントロールプレーンにアドバタイズされません。

Pod がエンドポイントの DNS ルックアップを実行し、 A レコード (IPv4) をレスポンスとして受け取ると、ホストローカルな 169.254.172.0/22 の範囲から割り当てられた IPv4 アドレスを使用して IPv4 エンドポイントとの接続を確立します。Pod に割り当てられた Node 固有の IPv4 アドレスは、ネットワークアドレス変換 (NAT) を介して Node にアタッチされているプライマリネットワークインターフェイス (ENI) の IPv4 アドレスに変換されます。下記の図に示すように、Node のプライベート IPv4 アドレスは、NAT ゲートウェイによってパブリック IPv4 アドレスに変換され、インターネットゲートウェイによってインターネットとの間でルーティングされます。

2021 年 11 月の時点で、Amazon VPC の IPv6 AWS リソースは NAT64 (on AWS NAT Gateway) および DNS64 (on Amazon Route 53 Resolver) を使用して IPv4 エンドポイントのサービスと通信できます。現在、EKS における IPv6 サポートは、NAT64 機能の活用に取り組んでいる間、egress-only (出力専用) の IPv4 をサポートしています。

Pod から Pod

Node 内、または Node をまたぐ Pod 間の通信では、常に Pod の IPv6 アドレスが使用されます。VPC CNI は、IPv4 接続をブロックしつつ IPv6 を処理するように iptables を設定します。

クラスターへの入力

IPv6 EKS クラスターでは、Service は Unique Local IPv6 Unicast Addresses (ULA) からの IPv6 アドレスのみを受け取ります。IPv6 クラスターの ULA Service CIDR ブロックは、クラスターの作成段階で自動的に割り当てられ変更できません。

ロードバランサーをデプロイすることで、クラスターの外部に Kubernetes Service を公開できます。AWS Load Balancer Controller は、Kubernetes クラスターの Elastic Load Balancing を管理します。コントローラーは、LoadBalancer タイプの Kubernetes Service を作成すると Network Load Balancer (NLB) を、Kubernetes Ingress を作成すると Application Load Balancer (ALB) をプロビジョニングします。

現時点での IPv6 サポートのフェーズでは、ALB および NLB はインターネット向け (フロントエンド) エンドポイントのデュアルスタックが可能です。デュアルスタックモードでは、IPv4 クライアントと IPv6 クライアントの両方が NLB および ALB に接続できます。EKS IPv6 クラスターは、Service や Ingress のマニフェストにアノテーション service.beta.kubernetes.io/aws-load-balancer-ip-address-type: dualstack を追加するとデュアルスタック IP モードで ALB および NLB をプロビジョニングします。NLB および ALB では、ターゲットタイプを使用して宛先ターゲットを定義します。現時点では、Ingress ではアノテーション alb.ingress.kubernetes.io/target-type: ip のみが設定可能です。インスタンスターゲットタイプはサポートされていません。

Kubernetes in-tree の Service Controller は、IPv6 をサポートしていない点に注意してください。

EKS クラスター通信

EKS クラスターは 2 つの VPC で構成されています。1) Kubernetes コントロールプレーンをホストしている AWS が管理する VPC、2) ワークロードやクラスター (データプレーン) で使用される他の AWS インフラストラクチャ (ロードバランサーなど) をホストする、お客様が管理する VPC。コントロールプレーンとワーカーノードの通信は、引き続き IPv4 モデルに従います。EKS は、デュアルスタックモード (IPv4/IPv6) でマネージドなクロスアカウント Elastic Network Interface (X-ENI) をプロビジョニングします。kubelet や kube-proxy などの Kubernetes Node コンポーネントは、デュアルスタックをサポートするように構成されています。kubelet と kube-proxy は、Node のプライマリネットワークインターフェイスにアタッチされている IPv4 アドレスと IPv6 アドレスの両方をバインドします。Kubernetes API サーバーは、EKS の管理する ENI (IPv6) を介して Pod および Node と通信します。Pod も同様に、EKS の管理する ENI を介して API サーバーと通信します。この際、Pod から API サーバーへの通信は、常に IPv6 モードを使用します。

IPv6 モードの EKS は、クラスターエンドポイントへのアクセス制御の従来の方法 (パブリック、プライベート、パブリックとプライベートの両方) を引き続きサポートします。IPv6 クラスターをプロビジョニングする場合でも、クラスターエンドポイント (NLB) は IPv4 モードで構成されます。NLB がインスタンスターゲットタイプのサポートを追加すると、クラスターエンドポイントをデュアルスタックモードで構成できるようになります。

Kubernetes クラスターエンドポイントへの接続は、クラスターのエンドポイント設定により決定します。エンドポイントでプライベートまたはプライベートとパブリックの両方が有効になっている場合、kubelet や kube-proxy のような Pod ネットワーキングを利用しない Node コンポーネントによるお客様の VPC 内からの Kubernetes API サーバーリクエストは、常に EKS の管理する ENI を介して IPv4 モードで発生します。パブリックエンドポイントのみが有効になっている場合、お客様の VPC 内からのリクエストは IPv4 を使用してクラスターエンドポイントと通信します。

パブリックエンドポイントを使用する kubectl の利用など、VPC の外部からの通信は、現時点では NLB および IPv4 を使用します。プライベートエンドポイントを使用する場合、インターネットから API サーバーへのパブリックアクセスはありません。kubectl コマンドは、VPC または VPC に接続されたネットワークから、IPv4 を使用して実行する必要があります。接続オプションについては、プライベート専用 API サーバーへのアクセスを参照してください。

ウォークスルー

このセクションでは、IPv6 モードで EKS クラスターをプロビジョニングし、サンプルアプリケーションをデプロイした後、Ingress (入力) および Egress (出力) 通信のメカニズムを説明します。

前提条件

クラスターの作成

はじめに、IPv6 EKS クラスターとマネージド型ノードグループを作成します。クラスターの作成には eksctl を使用します。最新バージョンの eksctl を使用していることを確認してください。IPv6 はプレフィックス割り当てモードでのみサポートされており、Nitro ベースの EC2 インスタンスタイプでのみ動作します。Amazon Linux 2 を使用して、Nitro ベースのインスタンスタイプのいずれかを選択します。

IPv6 EKS クラスターでは、バージョン 1.10.1 以降の Amazon VPC CNI アドオンが必要です。アドオンをデプロイした後は、クラスター内のすべてのノードグループのすべてのノードを削除しなければ、Amazon VPC CNI アドオンを 1.10.1 以前のバージョンにダウングレードすることはできません。

下記の設定をコピーして、cluster.yml というファイルに保存します。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: my-ipv6-cluster
  version: "1.21"
  region: us-west-2

kubernetesNetworkConfig:
  ipFamily: IPv6

vpc:
  clusterEndpoints:
    publicAccess: true
    privateAccess: true

iam:
  withOIDC: true

addons:
  - name: vpc-cni
    version: v1.10.1-eksbuild.1 # optional
  - name: coredns
    version: v1.8.4-eksbuild.1 # optional
  - name: kube-proxy
    version: v1.21.2-eksbuild.2 # optional

managedNodeGroups:
  - name: x86-al2-on-demand-xl
    amiFamily: AmazonLinux2
    instanceTypes: [ "m6i.xlarge", "m6a.xlarge" ]
    minSize: 1
    desiredCapacity: 2
    maxSize: 3
    volumeSize: 100
    volumeType: gp3
    volumeEncrypted: true
    ssh:
      allow: true
      publicKeyName: ipv6-ssh-key
    updateConfig:
      maxUnavailablePercentage: 33
    labels:
      os-distribution: amazon-linux-2

クラスターを作成します。

eksctl create cluster -f cluster.yml

踏み台ホストのデプロイ

クラスター作成手順の一部として作成された IPv6 パブリックサブネットに、踏み台ホストをデプロイします。手順については、Linux Bastion Hosts on the AWS Cloud を参照してください。

AWS Load Balancer Controller のデプロイ

AWS Load Balancer Controller は、Kubernetes クラスター用の Elastic Load Balancing の管理を担当します。AWS Load Balancer Controller をデプロイするには、EKS ユーザーガイドで説明されているステップに従います。

サンプルアプリケーションは Ingress Class アノテーションを使用しているため、Ingress Class に対応するために AWS Load Balancer Controller をアップグレードします。

helm upgrade aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=my-ipv6-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --set createIngressClassResource=true

サンプルアプリケーションのデプロイ

サンプルの 2048 ゲームアプリケーションを Kubernetes クラスターにデプロイし、Ingress リソースを使用してアプリケーションを外部に公開します。

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/2048/2048_full_dualstack.yaml

サービスがアクティブになるまで、数分待ちます。以下のコマンドを使用して、ロードバランサーのエンドポイントを介して新しくデプロイされた 2048 ゲームにアクセスします。

export GAME_2048=$(kubectl get ingress/ingress-2048 -n game-2048 -o jsonpath=‘{.status.loadBalancer.ingress[0].hostname}’)
echo http://${GAME_2048}

EC2 コンソールからロードバランサーのページを開き、サンプルアプリケーション用に作成された ALB を確認できます。DNS 名の下に「A レコードまたは AAAA レコード」という表示があることを確認できます。dig などのユーティリティを使用して、A レコードおよび AAAA レコードを確認できます。

dig <ALB DNS name> A
dig <ALB DNS name> AAAA

ブラウザから IPv4 の接続性を確認:

サンプルアプリケーションを表示するには、IPv4 ネットワークで実行されているブラウザから GAME 2048 の URL に遷移します。

踏み台ホストから IPv6 の接続性を確認:

ターミナル画面で ssh コマンドを使用して踏み台インスタンスに接続します。

ssh -i /path/ipv6-ssh-key.pem ec2-user@BastionPublicIp

以下の応答が表示されます。

The authenticity of host 'ec2-198-51-100-1.compute-1.amazonaws.com (198-51-100-1)' can't be established.
ECDSA key fingerprint is l4UB/neBad9tvkgJf1QZWxheQmR59WgrgzEimCG6kZY.
Are you sure you want to continue connecting (yes/no)

GAME 2048 の URL に curl を実行できます。curl コマンドは、すぐに ALB の IPv6 アドレスに解決します。(訳註: 先ほど取得した GAME 2048 の URL $GAME_2048 を、踏み台ホスト上でも改めて設定してください)

while true; do curl http://$GAME_2048/; echo sleep 5; done

主な考慮事項

IPv6 への移行

現在、IPv6 は新規の EKS クラスターでのみサポートされています。IPv4 から IPv6 へのアップグレードはサポートされていません。IP の枯渇や Pod の密度に課題がある場合、IPv6 への移行をおすすめします。同時に、IPv6 クラスターに移行する前に、アプリや EKS アドオン、AWS サービスを徹底的に評価することをおすすめします。

EKS クラスターの Blue/Green クラスターマイグレーションの戦略をおすすめします。引き続きクラスターとワークロードを IPv4 モードで実行しつつ、それらを新しい IPv6 クラスターにデプロイします。Amazon EKS は、IPv6 ガイドラインに従って新しい VPC の設定をおすすめします。カナリアベースのテスト手法を用いて、本番トラフィックのごく一部 (通常は 10 %) を新しい IPv6 クラスターにリダイレクトできます。テストの結果に基づいてトラフィックの分散比率を徐々に上げていき、最終的に 100 % のトラフィック分散で IPv6 クラスターに移行できます。

IPv6 と AWS Fargate

Amazon EKS は、Fargate で実行されている Pod の IPv6 をサポートするようになりました。さらに、このリリースの一部として、Fargate で実行されている各 Pod は IPv6 アドレスを受け取ります。これにより、Fargate ベースの Pod とクラスターで実行されるその他の Pod 間の通信が可能になります。Fargate は、VPC CNI の修正版を使用します。Fargate CNI は、プレフィックス割り当てを利用しません。各 Pod は独自のハードウェアユニットで実行されるため、CNI は VPC CIDR の範囲から一意の IPv6 アドレスを割り当てます。IPv4 の Egress (出力) 通信の問題に対処するために、Fargate Pod を実行する基盤となるハードウェアユニットは、IPv6 アドレスに加えて、VPC IPv4 アドレス範囲から一意の IPv4 アドレスを取得します。前述したすべての Ingress (入力) および Egress (出力) の通信フローは、Fargate Pod にも適用されます。IPv6 モードで Fargate プロファイルを構成するには、EKS Fargate ユーザーガイドを参照してください。

IPv6 と Windows

現時点では、IPv6 は Windows Node でサポートされていません。現在、Windows への IPv6 サポートの追加に取り組んでいます。IPv6 サポートが追加されると、Windows Node にスケジュールされた Pod は IPv6 アドレスを受け取ります。また、前述したすべての Ingress (入力) および Egress (出力) の通信フローが Windows Node にも適用されます。

CNI カスタムネットワークにおける IPv6

Amazon VPC CNI カスタムネットワークを使用すると、Pod のネットワークインターフェイスに Node のプライマリインターフェイスとは異なるサブネットやセキュリティグループを割り当てることができます。CNI カスタムネットワークの主なユースケースの一つは、セキュリティやネットワークの分離とともに IPv4 枯渇問題を解決することです。直面している問題が IP 枯渇である場合は、IPv6 EKS クラスターでは CNI カスタムネットワークを使用する必要がなくなります。IPv6 が有効化された VPC 内では、IP のニーズを満たすのに十分なアドレスが利用できます。IPv6 を使用した CNI カスタムネットワークは、現在のリリースの一部としてサポートされていません。セキュリティやネットワークのニーズを満たすために CNI カスタムネットワークが必要な場合、AWS Containers Roadmap にフィードバックを送信してください。

IPv6 と Security Groups for Pod

Amazon EC2 セキュリティグループを使用して、Pod からのインバウンドおよびアウトバウンドのネットワークトラフィックを許可するルールを定義できます。Security Groups for Pods は、Branch インターフェイスと呼ばれる個別の ENI を使用します。これは、Node にアタッチされている Trunk インターフェイスに関連づけられています。現時点では、IPv6 はプレフィックス割り当てモードのみをサポートしていますが、security groups for pods をサポートするにはプレフィックスを割り当てないモードで Branch ENI を管理する必要があります。そのため、IPv6 クラスターの現在のリリースフェーズでは、security groups for pods を利用できません。Pod ごとにセキュリティグループを使用する強いニーズがある場合は、IPv4 モードでクラスターを実行するか、IPv6 クラスターで EKS on Fargate を使用することをおすすめします。IPv6 クラスターにおける Security Groups for Pods のサポートについては、AWS Containers Roadmap を参照してください。

クリーンアップ

今後の請求を回避するために、本記事のウォークスルーで作成したすべてのリソースを削除できます。同様に、ウォークスルーの中で作成した踏み台ホストについても削除できます。(訳註: Linux Bastion Hosts on the AWS Cloud の手順で作成した CloudFormation スタックを削除して、踏み台ホストを削除できます)

eksctl delete cluster -f cluster.yml

まとめ

本記事では、IPv6 モードで EKS クラスターをプロビジョニングして IP 枯渇問題を対処し、Pod の密度を高める方法を説明しました。EKS を IPv6 モードで使用するための十分なガイダンスを、前述の変更の概要と主な考慮事項で説明しました。EKS の IPv6 サポートを発表できることを嬉しく思います。今後も、AWS サービスが IPv6 サポートを追加することで、お客様体験の向上に取り組んでいきます。

AWS サービスが IPv6 サポートを追加した際に通知を受け取るには、What’s New at AWS をサブスクライブします。AWS Containers Roadmap では、ロードマップの確認、フィードバックの提供、新機能のリクエストができます。

– デベロッパーアドボケイト Sheetal Joshi
– ソフトウェアデベロップメントエンジニア Apurup Chevuru
– シニアプロダクトマネージャー Mike Stefaniak

翻訳は、ソリューションアーキテクトの落水 (おちみず) が担当しました。原文はこちらです。