Amazon Web Services ブログ

Amazon VPC CNI が拡張サブネットディスカバリーを導入

AWS の Amazon Elastic Kubernetes Service (Amazon EKS) を使用してアプリケーションをモダナイズする際、ユーザーはしばしばスケールに伴う IPv4 アドレス空間の枯渇という深刻な問題に直面します。ユーザーは、運用の複雑さを増やすこと無く、EKS 上の Pod に割り当てられた VPC の CIDR とサブネットをできる限り活用したいと考えています。IPv6 アドレス空間の利用が、スケーラブルなネットワークソリューションを構築するための長期的な解決策になると考えられています。しかし、他のネットワークコンポーネントやアプリケーションの IPv6 サポートの制約から、Amazon EKS ユーザーは IPv4 環境を強いられている可能性もあります。そこで、Amazon EKS ではネットワーク設定を合理化し、運用の複雑さを増やすことなく IPv4 ベースのクラスターをスケーリングできるように、拡張サブネットディスカバリーのサポートを導入しました。

どのように機能するか

EKS クラスターの各 Amazon Elastic Compute Cloud (Amazon EC2) ワーカーノードに Amazon VPC Container Network Interface (CNI) プラグインがデプロイされています。このプラグインは、ワーカーノードに Elastic Network Interface (ENI) を作成して接続するとともに、EKS クラスター内の各 Pod に VPC CIDR からプライベート IPv4、IPv6 アドレスを割り当てます。デフォルトでは、VPC CNI はワーカーノードのプライマリ ENI と同じサブネットから Pod に IP アドレスを割り当てます。これは時々、「利用可能なサブネット」と呼ばれます。追加の設定を行わない場合、ワーカーノードは EC2 インスタンスが起動された「利用可能なサブネット」から ENI を接続できます。VPC CNI の新しい機能により、「利用可能なサブネット」の範囲が拡張されました。拡張サブネットディスカバリーを有効にすると、利用対象としてタグ付けされた VPC 内のすべての提供可能なサブネット/CIDR から Pod の IP アドレスが自動的に割り当てられるようになります。

新しいサブネットを作成して、「kubernetes.io/role/cni」という特定のタグを付与することで、既存のネットワーク設定にシームレスに統合されます。この機能により、継続的な運用の中断を最小限に抑えつつ、アプリケーションを効果的にスケーリングできるようになります。

前提条件

この機能を利用するための前提条件は以下の通りです。

  • AWS アカウント
  • バージョン 1.25 以降の EKS クラスター (ウォークスルーでは v1.29 を利用)
  • バージョン 1.18.0 以降の Amazon VPC CNI
  • 利用しているデバイスにインストール済みの最新バージョンの AWS Command Line Interface (AWS CLI)、または AWS CloudShell
  • eksctl – EKS クラスターの作成と管理を簡単に行うことができる CLI ツール (バージョン 0.165.0 以降)

セットアップ

export AWS_REGION= #Replace with your AWS Region
export AWS_ACCOUNT= #Replace with your AWS Account number
export CLUSTER_NAME=eks-enhsubsel-demo #Replace with your EKS cluster name

このウォークスルーでは、/24 の CIDR ブロック (256 個の IP アドレス) を持つ Amazon VPC を作成し、IP アドレス枯渇のシナリオをシュミレーションします。この VPC は、3 つのパブリックサブネットと 3 つのプライベートサブネットに分かれており、それぞれ /27 の CIDR ブロック (28 個の IP アドレス) が割り当てられています。これは、次の図のような構成になります。VPC の CIDR ブロック内の IP アドレスが枯渇した後、VPC にセカンダリ CIDR を関連付けます。その後、「kubernetes.io/role/cni」タグを付与した VPC サブネットを作成します。これにより、VPC CNI が新しいサブネットを自動的に検出し、 Pod に IP アドレスの割り当てができるようになります。

図 1: Amazon VPC のセットアップ

図 1: Amazon VPC のセットアップ

次に、バージョン 1.18.0 の VPC CNI がインストールされた EKS クラスターを作成します。

cat << EOF > cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: ${CLUSTER_NAME}
  region: ${AWS_REGION}
  version: "1.29"

vpc:
  cidr: 10.0.0.0/24

addons:
  - name: vpc-cni
    version: 1.18.0
  - name: coredns
  - name: kube-proxy
    
managedNodeGroups:
  - name: ${CLUSTER_NAME}-mng
    instanceType: m6a.large
    privateNetworking: true
    minSize: 2
    desiredCapacity: 2
    maxSize: 5
EOF

eksctl create cluster -f cluster.yaml

クラスターの作成が完了するのを待ち、vpc-cni アドオンがクラスター内で実行されていることを確認します。

aws eks describe-addon --addon-name vpc-cni --cluster-name $CLUSTER_NAME --region $AWS_REGION
{
    "addon": {
        "addonName": "vpc-cni",
        "clusterName": "eks-enhsubsel-demo",
        "status": "ACTIVE",
        "addonVersion": "v1.18.0-eksbuild.1",
        ....
    }
}

サブネットには /27 の CIDR が割り当てられているため、プライベートサブネットでは利用可能な IP アドレスがほとんどまたは全くないことに注目します。

aws ec2 describe-subnets --region $AWS_REGION \
--filters Name=tag:Name,Values="eksctl-eks-enhsubsel-demo-cluster/SubnetPrivate*" \
--query "Subnets[].{VPC:VpcId,SubnetId:SubnetId,AvailableIPs:AvailableIpAddressCount}" \
--output table
-----------------------------------------------------------------------
|                           DescribeSubnets                           |
+--------------+----------------------------+-------------------------+
| AvailableIPs |         SubnetId           |           VPC           |
+--------------+----------------------------+-------------------------+
|  16          |  subnet-08411e385d62f29da  |  vpc-07f75e9b1d954689a  |
|  7           |  subnet-0755097835150b642  |  vpc-07f75e9b1d954689a  |
|  0           |  subnet-0975a78066e7e76d6  |  vpc-07f75e9b1d954689a  |
+--------------+----------------------------+-------------------------+

サンプルアプリケーションをデプロイし、EKS クラスター内で IP アドレス枯渇のシナリオをシュミレーションします。

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 50
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      terminationGracePeriodSeconds: 0
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
          resources:
            requests:
              cpu: 50m
EOF

サブネット内の IP アドレスが不足しているため、Amazon VPC CNI が IP アドレスを割り当てることができず、多くの Pod が「ContainerCreating」状態であることに注目します。次に、VPC CNI の拡張サブネットディスカバリーの機能を使って、割り当て可能な IP アドレススペースを持つ新しい VPC サブネットを自動検出し、Pod に IP アドレスを割り当てる方法を確認します。

Amazon VPC は最大 5 つのセカンダリ CIDR ブロックをサポートしており、これにより VPC の IP アドレススペースを拡張できます。まず、Amazon EKS を作成した VPC にセカンダリ CIDR ブロック「10.1.0.0/16」を追加します。

export EKS_VPC_ID=$(aws eks describe-cluster --name $CLUSTER_NAME \
--region $AWS_REGION --query "cluster.resourcesVpcConfig.vpcId" --output text)
aws ec2 associate-vpc-cidr-block --vpc-id $EKS_VPC_ID \
--cidr-block "10.1.0.0/16" --region $AWS_REGION
{
    "CidrBlockAssociation": {
        "AssociationId": "vpc-cidr-assoc-06515a22930a5d6e9",
        "CidrBlock": "10.1.0.0/16",
        "CidrBlockState": {
            "State": "associating"
        }
    },
    "VpcId": "vpc-07f75e9b1d954689a"
}

セカンダリ CIDR ブロックの関連付けが完了するのを待ってから、セカンダリ CIDR ブロックから新しい VPC サブネットを作成します。また、VPC CNI がこれらのサブネットを自動検出できるように、サブネットに「kubernetes.io/role/cni=1」タグを付与します。

aws ec2 create-subnet --vpc-id $EKS_VPC_ID --region $AWS_REGION \
--availability-zone "$AWS_REGION"a --cidr-block 10.1.0.0/19 \
--tag-specifications "ResourceType=subnet,Tags=[{Key=kubernetes.io/role/cni,Value=1}]"

aws ec2 create-subnet --vpc-id $EKS_VPC_ID --region $AWS_REGION \
--availability-zone "$AWS_REGION"b --cidr-block 10.1.32.0/19 \
--tag-specifications "ResourceType=subnet,Tags=[{Key=kubernetes.io/role/cni,Value=1}]"

aws ec2 create-subnet --vpc-id $EKS_VPC_ID --region $AWS_REGION \
--availability-zone "$AWS_REGION"c --cidr-block 10.1.64.0/19 \
--tag-specifications "ResourceType=subnet,Tags=[{Key=kubernetes.io/role/cni,Value=1}]"

デフォルトの設定では、VPC CNI は Amazon EKS ワーカーノードのプライマリ ENI に関連付けられた VPC サブネットから、ENI のプライマリ IP アドレスとセカンダリ IP アドレスの両方を割り当てます。

aws ec2 describe-network-interfaces --region $AWS_REGION \
--query "NetworkInterfaces[*].{ID:NetworkInterfaceId,DNSName:PrivateDnsName,PrimaryIP:PrivateIpAddress,SecondaryIPs:PrivateIpAddresses[].PrivateIpAddress}" \
--filters Name=tag:cluster.k8s.amazonaws.com/name,Values=$CLUSTER_NAME \
--output table
--------------------------------------------------------------------------------------
|                              DescribeNetworkInterfaces                             |
+-------------------------------------------+-------------------------+--------------+
|                   DNSName                 |           ID            |  PrimaryIP   |
+-------------------------------------------+-------------------------+--------------+
|  ip-10-0-0-155.us-west-2.compute.internal |  eni-07f66d0e6b2408fc7  |  10.0.0.155  |
+--------------------------------------------+------------------------+--------------+
||                                   SecondaryIPs                                    ||
|+-----------------------------------------------------------------------------------+|
||  10.0.0.155                                                                      ||
||  10.0.0.136                                                                      ||
||  10.0.0.140                                                                      ||
||  10.0.0.141                                                                      ||
||  10.0.0.145                                                                      ||
||  10.0.0.150                                                                      ||
||  10.0.0.135                                                                      ||
||  10.0.0.151                                                                      ||
||  10.0.0.148                                                                      ||
||  10.0.0.149                                                                      ||
|+-----------------------------------------------------------------------------------+|
  .........
|+----------------------------------------------------------------------------------+|
|                              DescribeNetworkInterfaces                             |
+--------------------------------------------+-------------------------+-------------+
|                   DNSName                  |           ID           |  PrimaryIP   |
+--------------------------------------------+-------------------------+--------------+
|  ip-10-0-0-102.us-west-2.compute.internal |  eni-087692b80786865e0  |  10.0.0.102  |
+--------------------------------------------+-------------------------+--------------+
||                                   SecondaryIPs                                    ||
|+-----------------------------------------------------------------------------------+|
||  10.0.0.102                                                                      ||
||  10.0.0.105                                                                      ||
||  10.0.0.110                                                                      ||
||  10.0.0.126                                                                      ||
||  10.0.0.124                                                                      ||
||  10.0.0.125                                                                      ||
||  10.0.0.118                                                                      ||
||  10.0.0.100                                                                      ||
||  10.0.0.116                                                                      ||
||  10.0.0.117                                                                      ||
|+-----------------------------------------------------------------------------------+|

Amazon VPC CNI アドオンの環境変数「ENABLE_SUBNET_DISCOVERY」を確認して、新しい拡張サブネットディスカバリーの機能が有効になっているか確認します。kubectl を利用してこれを確認します。

kubectl describe ds aws-node -n kube-system | grep ENABLE_SUBNET_DISCOVERY

ENABLE_SUBNET_DISCOVERY: true

この記事の執筆時点では、拡張サブネットディスカバリーの機能は バージョン 1.18.0 以降のAmazon VPC CNI でデフォルトで有効になっています。環境変数が true に設定されていない場合は、kubectl または AWS CLI を使って設定することができます。

kubectl set env daemonset aws-node -n kube-system ENABLE_SUBNET_DISCOVERY=true \
-c aws-node

または、

aws eks update-addon --cluster-name $CLUSTER_NAME --region $AWS_REGION \
--addon-name vpc-cni \
--configuration-values '{"env":{"ENABLE_SUBNET_DISCOVERY":"true"}}'

この機能を有効にすると、VPC CNI は「kubernetes.io/role/cni」タグが付与された割り当て可能な IP アドレススペースを持つ VPC サブネットを探します。そして、それらのサブネットから追加の ENI を Amazon EKS ワーカーノードに接続し、Pod に IP アドレスを割り当てられるようにします。ウォークスルーでは、多くの Pod が「ContainerCreating」の状態だったため、VPC CNI は /19 の CIDR である新しいサブネットを自動的に検出し、既存のワーカーノードにそれらを接続しました。次のコマンドでこれを確認します。

kubectl get pods -o wide | grep ContainerCreating
<<EMPTY OUTPUT>>

ワーカーノードに接続されている ENI を確認すると、セカンダリ CIDR サブネットから追加の ENI が接続されており、Pod に 10.1.x.x の IP アドレス範囲が割り当てられていることがわかります。

aws ec2 describe-network-interfaces --region $AWS_REGION \
--query "NetworkInterfaces[*].{ID:NetworkInterfaceId,DNSName:PrivateDnsName,PrimaryIP:PrivateIpAddress,SecondaryIPs:PrivateIpAddresses[].PrivateIpAddress}" \
--filters Name=tag:cluster.k8s.amazonaws.com/name,Values=$CLUSTER_NAME \
--output table
--------------------------------------------------------------------------------------
|                              DescribeNetworkInterfaces                             |
+-------------------------------------------+-------------------------+--------------+
|                   DNSName                 |           ID            |  PrimaryIP   |
+-------------------------------------------+-------------------------+--------------+
|  ip-10-0-0-152.us-west-2.compute.internal |  eni-0525ae09d044a6688  |  10.0.0.152  |
+--------------------------------------------+-------------------------+--------------+
||                                   SecondaryIPs                                    ||
|+-----------------------------------------------------------------------------------+|
||  10.0.0.152                                                                      ||
||  10.0.0.144                                                                      ||
||  10.0.0.154                                                                      ||
||  10.0.0.147                                                                      ||
||  10.0.0.133                                                                      ||
||  10.0.0.157                                                                      ||
||  10.0.0.153                                                                      ||
||  10.0.0.158                                                                      ||
||  10.0.0.146                                                                      ||
||  10.0.0.132                                                                      ||
|+-----------------------------------------------------------------------------------+|
|                              DescribeNetworkInterfaces                              |
+--------------------------------------------+-------------------------+--------------+
|                   DNSName                  |           ID            |  PrimaryIP   |
+--------------------------------------------+-------------------------+--------------+
|  ip-10-1-79-53.us-west-2.compute.internal  |  eni-0b2632fa77e9fbf68  |  10.1.79.53  |
+--------------------------------------------+-------------------------+--------------+
||                                   SecondaryIPs                                    ||
|+-----------------------------------------------------------------------------------+|
||  10.1.79.53                                                                       ||
||  10.1.78.231                                                                      ||
||  10.1.75.23                                                                       ||
||  10.1.81.171                                                                      ||
||  10.1.95.26                                                                       ||
||  10.1.86.60                                                                       ||
||  10.1.76.92                                                                       ||
||  10.1.65.140                                                                      ||
||  10.1.75.174                                                                      ||
||  10.1.94.30                                                                       ||
|+-----------------------------------------------------------------------------------+|

クリーンアップ

AWS アカウントで継続的に課金が発生するのを避けるため、作成した EKS クラスターのリソースを必ず削除しておきます。

# Delete EKS cluster resources 
eksctl delete cluster -f cluster.yaml

留意すべき考慮事項

共有サブネット

この機能を複数の AWS アカウントに跨るシナリオ (VPC とサブネットを中央の AWS アカウントで作成し、参加者の AWS アカウントと共有して EKS クラスターをデプロイする) 場合、クラウターを起動する参加者の AWS アカウントでサブネットにタグを付与する必要があります。詳しいクォークスルーについては、「Use shared VPC subnets in Amazon EKS」を参照してください。

カスタムネットワーキング

IP アドレスの枯渇問題への対応として、Amazon VPC CNI の機能であるカスタムネットワーキングを利用することで、セカンダリ VPC の IP アドレス範囲から Pod に IP アドレスを割り当てることができます。VPC CNI でカスタムネットワーキングを有効にすると、セカンダリ VPC CIDR から作成された代替となるサブネット CIDR 範囲を含む ENIConfig というカスタムリソースで定義されたサブネット内に、セカンダリ ENI を作成することができます。VPC CNI は ENIConfig カスタムリソースで定義された CIDR 範囲から Pod に IP アドレスを割り当てます。さらに、Pod はノードのプライマリ ENI とは異なるセキュリティグループを利用できます。そのため、異なるネットワークと異なるセキュリティグループで Pod を実行する必要がある場合、カスタムネットワーキングを検討する価値があります。一方、拡張サブネットディスカバリーは、ENIConfig カスタムリソースの作成を必要としないため、設定のオーバーヘッドが少なく済みます。VPC CNI で両方の機能が有効になっている場合は、カスタムネットワーキングが優先されます。

Pod ネットワーキングのユースケース

この機能は、「Pods の SNAT」、「Pods のセキュリティグループ」、「Kubernetes ネットワークポリシーのクラスターを構成する」、「Amazon EC2 ノードで使用可能な IP アドレスの量を増やす」といった、他の VPC CNI のユースケースと組み合わせて利用できます。詳細な比較については、「Pod ネットワークのユースケースの選択」を参照してください。

まとめ

この記事では、Amazon VPC CNI ベースのサブネットディスカバリーの機能が運用オーバーヘッドを抑えながら、EKS クラスターの成長に合わせた IPv4 アドレスの割り当てに対する拡張性と柔軟性をどのように提供できるのか紹介しました。この機能が、どのようにクラスターサイズの変化に適応でき、昨今の IT 環境の動的なニーズをサポートしながらIP アドレスの管理を簡素化するか実演しました。EKS クラスターを安全にスケーリングするための推奨事項と追加の検討事項については、「Amazon EKS ベストプラクティスガイド」を参照してください。

Amazon VPC CNI のインストール手順については、Amazon EKS ユーザーガイドを参照してください。GitHub の AWS Containers Roadmap にコメントするか Issue を作成することで、Amazon VPC CNI プラグインへフィードバックを提供できます。

本記事は、Amazon VPC CNI introduces Enhanced Subnet Discovery (2024 年 4 月 4 日公開) を翻訳したものです。翻訳は、ソリューションアーキテクトの鈴木が担当しました。