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】Amazon EKS で Security Groups for Pods を導入して Pod 数の上限を検証してみた

Posted at

はじめに

Amazon EKS (Elastic Kubernetes Service) における Security Groups for Pods 機能は、Pod レベルでセキュリティグループを適用できる機能です。この機能を使うことで、Kubernetes の Pod に対して AWS のセキュリティグループを直接割り当て、きめ細かなネットワークセキュリティ制御が可能になります。

本記事では、EKS クラスターに Security Groups for Pods を導入し、インスタンスタイプごとに設定されている Pod 数の上限に達した場合の挙動を検証します。特に、Pod が Pending 状態になる条件と、その際のエラーメッセージを確認します。

対象読者

  • Amazon EKS を運用している方
  • Kubernetes の Pod セキュリティについて学びたい方
  • EKS の Security Groups for Pods 機能に興味がある方
  • インスタンスタイプごとの Pod 数制限について知りたい方

検証環境

  • AWS リージョン: ap-northeast-1
  • EKS バージョン: 1.30
  • インスタンスタイプ: m6a.xlarge
  • VPC CNI プラグインバージョン: v1.19.0-eksbuild.1

Security Groups for Pods の概要

機能の説明

Security Groups for Pods は、Amazon EKS の機能で、Kubernetes の Pod に AWS セキュリティグループを直接適用できます。通常の Kubernetes 環境では Pod レベルでのセキュリティグループ適用はできませんが、EKS ではこの機能を使うことで、Pod ごとに異なるセキュリティポリシーを適用できます。

この機能は Amazon VPC CNI プラグインの拡張機能として提供されており、Pod ごとに Branch ENI (Elastic Network Interface) を作成することで実現しています。

仕組み

Security Groups for Pods を有効にすると、以下のような仕組みで動作します:

  1. クラスターの各ノードに Trunk ENI が作成される
  2. Pod が作成されると、その Pod 用に Branch ENI が作成される
  3. Branch ENI にセキュリティグループが適用される
  4. Pod のネットワークトラフィックは Branch ENI を通過する

参考: Amazon EKS Pod のセキュリティグループ用に Amazon VPC CNI Plugin for Kubernetes を設定する - Amazon EKS

トランクネットワークインターフェイスが作成されると、Pod にはトランクネットワークインターフェイスまたは標準ネットワークインターフェイスのセカンダリ IP アドレスが割り当てられます。ノードが削除されると、トランクインターフェイスは自動的に削除されます。
後のステップで Pod のセキュリティグループをデプロイすると、VPC リソースコントローラーはブランチネットワークインターフェイスと呼ばれる特別なインターフェイスを aws-k8s-branch-eni の説明と共に作成し、セキュリティグループを関連付けます。ノードにアタッチされた標準ネットワークインターフェイスとトランクネットワークインターフェイスに加えて、ブランチネットワークインターフェイスが作成されます。

インスタンスタイプによる制限

重要なポイントとして、インスタンスタイプによって以下の制限があります:

  • 対応するインスタンスタイプが限られている(Nitro ベースのインスタンスのみ)
  • インスタンスタイプごとに作成できる Branch ENI(つまり SG for Pods を適用できる Pod)の数に上限がある

対応しているインスタンスタイプおよび Branch ENI の上限は amazon-vpc-resource-controller-k8s の limits.go から確認できます。

参考:Amazon EKS Pod のセキュリティグループポリシーを使用する - Amazon EKS

Pod が Pending 状態でスタックした場合、ノードのインスタンスタイプが limits.go のリストに含まれていることを確認します。

今回検証に使用する m6a.xlarge の場合、以下の制限があります:

  • 最大 18 個の Branch ENI(= 18 個の Pod に SG を適用可能)

前提条件

必要な権限とリソース

  • AWS アカウントと管理者権限
  • eksctl コマンドラインツール
  • kubectl コマンドラインツール
  • AWS CLI

インスタンスタイプの選択

Security Groups for Pods は全てのインスタンスタイプでサポートされているわけではありません。特に t2/t3 などの旧世代インスタンスでは使用できません。サポートされているのは主に Nitro ベースのインスタンスです。

サポートされているインスタンスは limits.go より確認できます。

limits.go より m6a.xlarge の記載を抜粋

"m6a.xlarge": {
    Interface:               4,
    IPv4PerInterface:        15,
    IsTrunkingCompatible:    true,  // この値が true であることが重要
    BranchInterface:         18,    // 最大 18 個の Branch ENI が作成可能
    DefaultNetworkCardIndex: 0,
    NetworkCards: []NetworkCard{
        {
            MaximumNetworkInterfaces: 4,
            NetworkCardIndex:         0,
        },
    },
    Hypervisor:  "nitro",
    IsBareMetal: false,
},

実装手順

STEP1: EKS クラスターの作成

まずは Security Groups for Pods をサポートする EKS クラスターを作成します。

  1. クラスター設定ファイルを作成します:
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: sg-for-pods-cluster
  region: ap-northeast-1
  version: '1.30'
iam:
  withOIDC: true # required

cloudWatch:
  clusterLogging:
    enableTypes:
      - audit
      - api
      - authenticator
      - controllerManager
      - scheduler

managedNodeGroups:
  - name: managed-ng-1
    instanceType: m6a.xlarge  # Nitro ベースのインスタンスを選択
    minSize: 1
    maxSize: 2
    desiredCapacity: 1
    volumeSize: 20
  1. クラスターを作成します:
eksctl create cluster -f clusterconfig.yaml

クラスターの作成には約 15〜20 分かかります。

STEP2: Security Groups for Pods の有効化

参考:Amazon EKS Pod のセキュリティグループ用に Amazon VPC CNI Plugin for Kubernetes を設定する - Amazon EKS

  1. まず、現在の VPC CNI プラグインのバージョンを確認します:
kubectl describe daemonset aws-node --namespace kube-system | grep amazon-k8s-cni: | cut -d : -f 3

出力例:

v1.19.0-eksbuild.1
  1. クラスターロールに必要な IAM ポリシーを追加します:
cluster_role=$(aws eks describe-cluster --name sg-for-pods-cluster --query cluster.roleArn --output text | cut -d / -f 2)
aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSVPCResourceController --role-name $cluster_role
  1. aws-node DaemonSet で ENABLE_POD_ENI 変数を true に設定します:
kubectl set env daemonset aws-node -n kube-system ENABLE_POD_ENI=true
  1. 設定が反映されたことを確認します:
kubectl describe daemonset aws-node -n kube-system | grep ENABLE_POD_ENI

出力例:

ENABLE_POD_ENI: true
  1. CNINode カスタムリソースが作成されたことを確認します:
kubectl get cninode -A

出力例:

NAME                                               FEATURES
ip-192-168-14-83.ap-northeast-1.compute.internal   [{"name":"SecurityGroupsForPods"}]
  1. AWS コンソールで、Trunk ENI が作成されたことを確認します:

Description には「aws-k8s-trunk-eni」と表示されます。

STEP3: セキュリティグループポリシーの作成と適用

参考:Amazon EKS Pod のセキュリティグループポリシーを使用する - Amazon EKS

  1. Pod 用のセキュリティグループを作成します:

AWS コンソールから、クラスターと同じ VPC 内にセキュリティグループを作成します。今回は検証のため、インバウンドおよびアウトバウンドですべてのトラフィック (0.0.0.0/0) を許可する設定にします。

  1. Kubernetes 名前空間を作成します:

ここでは my-namespace としています。

kubectl create namespace my-namespace
  1. SecurityGroupPolicy リソースを作成します:
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
  name: my-security-group-policy
  namespace: my-namespace
spec:
  podSelector:
    matchLabels:
      role: my-role
  securityGroups:
    groupIds:
      - sg-xxxxxxxx  # 作成したセキュリティグループの ID に置き換えてください
  1. SecurityGroupPolicy をクラスターに適用します:
kubectl apply -f my-security-group-policy.yaml

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

  1. サンプルアプリケーションの YAML ファイルを作成します:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  namespace: my-namespace
  labels:
    app: my-app
spec:
  replicas: 4  # まずは少ない数の Pod から始める
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        role: my-role  # SecurityGroupPolicy の podSelector と一致させる
    spec:
      terminationGracePeriodSeconds: 120
      containers:
      - name: nginx
        image: public.ecr.aws/nginx/nginx:1.23
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
  namespace: my-namespace
  labels:
    app: my-app
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  1. アプリケーションをデプロイします:
kubectl apply -f sample-application.yaml
  1. Pod の状態を確認します:
kubectl get pods -n my-namespace

出力例:

NAME                             READY   STATUS    RESTARTS   AGE
my-deployment-asdfqwer-29l8g   1/1     Running   0          56s
my-deployment-asdfqwer-9jnjn   1/1     Running   0          56s
my-deployment-asdfqwer-frsvs   1/1     Running   0          56s
my-deployment-asdfqwer-lqjdn   1/1     Running   0          56s

STEP5: Pod の詳細情報の確認

  1. Pod の詳細情報を確認します:
kubectl describe pods -n my-namespace my-deployment-asdfqwer-29l8g

注目すべき点:

  • Annotations セクションに vpc.amazonaws.com/pod-eni 情報がある
  • Events セクションに SecurityGroupRequested イベントがある
Annotations:      vpc.amazonaws.com/pod-eni:
                    [{"eniId":"eni-08ebf4f50eedbc88f","ifAddress":"0e:9b:d7:18:01:a3","privateIp":"192.168.31.236","ipv6Addr":"","vlanId":2,"subnetCidr":"192....
Events:
  Type     Reason                  Age   From                     Message
  ----     ------                  ----  ----                     -------
  Normal   Scheduled               109s  default-scheduler        Successfully assigned my-namespace/my-deployment-asdfqwer-29l8g to ip-192-168-14-83.ap-northeast-1.compute.internal
  Normal   SecurityGroupRequested  109s  vpc-resource-controller  Pod will get the following Security Groups [sg-xxxxxxxx]
  Warning  FailedCreatePodSandBox  109s  kubelet                  Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "d9b9b6ad0d2ebe550dd7a3bdefb20afcf37134a568da9443b90bc663087b095e": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to assign an IP address to container
  Normal   ResourceAllocated       108s  vpc-resource-controller  Allocated [{"eniId":"eni-08ebf4f50eedbc88f","ifAddress":"0e:9b:d7:18:01:a3","privateIp":"192.168.31.236","ipv6Addr":"","vlanId":2,"subnetCidr":"192.168.0.0/19","subnetV6Cidr":""}] to the pod
  Normal   Pulling                 108s  kubelet                  Pulling image "public.ecr.aws/nginx/nginx:1.23"
  Normal   Pulled                  104s  kubelet                  Successfully pulled image "public.ecr.aws/nginx/nginx:1.23" in 3.959s (3.959s including waiting). Image size: 57001878 bytes.
  Normal   Created                 104s  kubelet                  Created container nginx
  Normal   Started                 104s  kubelet                  Started container nginx

注意: FailedCreatePodSandBox のエラーが表示されていますが、その後 ResourceAllocated イベントがあれば問題ありません。これは AWS の公式ドキュメントでも言及されている既知の挙動です。

参考:Amazon EKS Pod のセキュリティグループポリシーを使用する - Amazon EKS

kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace を実行したときに次のようなメッセージが表示されている場合は、無視しても問題ありません
add cmd: failed to assign an IP address to container

  1. AWS コンソールで、Branch ENI が作成されていることを確認します:

各 Pod に対して、「branch」タイプの ENI が作成されているはずです。

STEP6: セキュリティグループの動作確認

  1. Pod に接続して動作確認します:
kubectl exec -it -n my-namespace my-deployment-asdfqwer-29l8g -- /bin/bash
  1. Pod 内から Service への接続を確認します:
curl my-app

出力例:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
  1. セキュリティグループの効果を確認するため、アウトバウンドルールを削除します:

AWS コンソールから、先ほど作成したセキュリティグループのアウトバウンドルールをすべて削除します。

  1. 再度 Pod 内から Service への接続を試みます:
curl my-app

出力例:

curl: (6) Could not resolve host: my-app

これは CoreDNS への接続ができなくなり、名前解決ができなくなったためです。セキュリティグループが正しく機能していることを示しています。

STEP7: Pod 数の上限検証

m6a.xlarge インスタンスでは最大 18 個の Branch ENI を作成できるため、Security Groups for Pods を適用できる Pod 数の上限は 18 個です。この上限を超えた場合の挙動を検証します。

  1. サンプルアプリケーションの replicas を 19 に変更します:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  namespace: my-namespace
  labels:
    app: my-app
spec:
  replicas: 19  # 上限の 18 を超える 19 に設定
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        role: my-role
    spec:
      terminationGracePeriodSeconds: 120
      containers:
      - name: nginx
        image: public.ecr.aws/nginx/nginx:1.23
        ports:
        - containerPort: 80
  1. 変更を適用します:
kubectl apply -f sample-application.yaml
  1. Pod の状態を確認します:
kubectl get pods -n my-namespace

出力例:

NAME                             READY   STATUS    RESTARTS   AGE
my-deployment-asdfqwer-44wgv   1/1     Running   0          14s
my-deployment-asdfqwer-5qzqq   1/1     Running   0          14s
my-deployment-asdfqwer-7whm2   1/1     Running   0          14s
my-deployment-asdfqwer-8zd2r   1/1     Running   0          14s
my-deployment-asdfqwer-bbgcx   1/1     Running   0          14s
my-deployment-asdfqwer-bppbq   1/1     Running   0          14s
my-deployment-asdfqwer-hj2sm   1/1     Running   0          14s
my-deployment-asdfqwer-hktvp   1/1     Running   0          14s
my-deployment-asdfqwer-jsf2l   1/1     Running   0          14s
my-deployment-asdfqwer-mmxb7   1/1     Running   0          14s
my-deployment-asdfqwer-n5tvp   1/1     Running   0          14s
my-deployment-asdfqwer-nlkq9   1/1     Running   0          14s
my-deployment-asdfqwer-nnzhn   1/1     Running   0          14s
my-deployment-asdfqwer-q7wld   1/1     Running   0          14s
my-deployment-asdfqwer-t4z52   1/1     Running   0          14s
my-deployment-asdfqwer-wjxch   1/1     Running   0          14s
my-deployment-asdfqwer-wtb85   1/1     Running   0          14s
my-deployment-asdfqwer-wxmfh   1/1     Running   0          14s
my-deployment-asdfqwer-zhld2   0/1     Pending   0          14s

予想通り、19 個目の Pod が Pending 状態になっています。これは m6a.xlarge インスタンスで作成できる Branch ENI の上限が 18 個であるためです。

  1. Pending 状態の Pod の詳細を確認します:
kubectl describe pods my-deployment-asdfqwer-zhld2 -n my-namespace

出力例:

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  49s   default-scheduler  0/1 nodes are available: 1 Insufficient vpc.amazonaws.com/pod-eni. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.

エラーメッセージから、vpc.amazonaws.com/pod-eni リソース(Branch ENI)が不足していることが原因で Pod がスケジュールできないことがわかります。

検証結果と考察

Security Groups for Pods の動作確認

  1. 正常な動作

    • Security Groups for Pods を有効化すると、Trunk ENI が各ノードに作成される
    • Pod が作成されると、その Pod 用に Branch ENI が作成される
    • Pod に指定したセキュリティグループが適用される
    • セキュリティグループのルールに従ってトラフィックが制御される
  2. Pod 数の上限

    • m6a.xlarge インスタンスでは最大 18 個の Branch ENI を作成可能
    • 19 個目の Pod は Pending 状態になり、Insufficient vpc.amazonaws.com/pod-eni エラーが発生

インスタンスタイプによる制限

各インスタンスタイプによって作成できる Branch ENI の数が異なります。一部の例を示します:

インスタンスタイプ 最大 Branch ENI 数
m6a.xlarge 18
m5.large 9
c5.xlarge 18
r5.2xlarge 38

インスタンスタイプを選択する際は、必要な Pod 数に対して十分な Branch ENI をサポートしているかを確認することが重要です。

注意点

  1. 既知の警告メッセージ

    Pod の詳細情報に FailedCreatePodSandBox というエラーが表示されることがありますが、その後に ResourceAllocated イベントがあれば問題ありません。AWS の公式ドキュメントでも言及されている既知の挙動です。

  2. インスタンスタイプの互換性

    すべてのインスタンスタイプが Security Groups for Pods をサポートしているわけではありません。特に T2/T3 などの旧世代インスタンスはサポートされていません。

  3. ENI 数の制限

    Security Groups for Pods を使用すると、各 Pod に Branch ENI が割り当てられるため、インスタンスの ENI 制限に達する可能性があります。大規模なデプロイメントを計画する場合は、この制限を考慮する必要があります。

応用例と考察

マルチノード環境での動作

今回は単一ノードでの検証でしたが、マルチノード環境では各ノードごとに Branch ENI の上限があります。例えば、m6a.xlarge インスタンスを 3 台使用する場合、最大 18 × 3 = 54 個の Pod に Security Groups を適用できます。

異なるセキュリティグループの適用

複数の SecurityGroupPolicy を作成し、異なるラベルを持つ Pod に異なるセキュリティグループを適用することも可能です。これにより、マイクロサービスアーキテクチャにおいて、サービスごとに異なるセキュリティポリシーを適用できます。

まとめ

Amazon EKS の Security Groups for Pods 機能は、Kubernetes の Pod レベルでセキュリティグループを適用できる機能です。この機能を使用することで、以下のメリットがあります:

  • Pod ごとに異なるセキュリティグループを適用できる
  • AWS のセキュリティグループの細かい制御を Kubernetes の Pod に適用できる
  • マイクロサービスアーキテクチャにおいて、サービスごとに異なるセキュリティポリシーを適用できる

一方で、以下の制限や注意点があります:

  • インスタンスタイプによって作成できる Branch ENI の数に上限がある
  • すべてのインスタンスタイプがサポートされているわけではない
  • Pod 数が増えると、ENI の数も増加する

今回の検証では、m6a.xlarge インスタンスで最大 18 個の Pod に Security Groups を適用でき、19 個目の Pod は Pending 状態になることを確認しました。この結果は AWS のドキュメントに記載されている制限と一致しています。

Security Groups for Pods を導入する際は、インスタンスタイプごとの Branch ENI の上限を考慮し、必要な Pod 数に対して適切なインスタンスタイプを選択することが重要です。

この記事が Security Groups for Pods の理解と実装の一助となれば幸いです。実際の環境に導入する際は、アプリケーションの要件に合わせて適切に設計・実装してください。

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?