このドキュメントでは、Multus CNI、IPVLAN CNI プラグイン、Whereabouts IPAM プラグインを使用して、複数のネットワーク インターフェースで Google Kubernetes Engine(GKE)の Pod を構成する方法について説明します。
IPVLAN CNI プラグインは、追加の Pod インターフェースにレイヤ 2 接続を提供し、Whereabouts IPAM プラグインは、それらに IP アドレスを動的に割り当てます。
この設定により、ネットワークの分離とセグメンテーションを強化するためにコントロール プレーンとデータプレーンのトラフィックを分離するなど、高度なネットワーク構成が可能になります。
このドキュメントは、組織のネットワークを設計するクラウド アーキテクトとネットワーク スペシャリストを対象としています。 Google Cloud のコンテンツで使用されている一般的なロールとタスクの例の詳細については、一般的な GKE ユーザーのロールとタスクをご覧ください。
このドキュメントを読む前に、次のコンセプトをよく理解しておいてください。
IPVLAN で Multus を使用するメリット
このソリューションを使用して複数のネットワーク インターフェースで Pod を構成することには、いくつかの重要なメリットがあります。レイヤ 2 モードで IPVLAN を使用して Multus を構成する主なユースケースは、レイヤ 2 の隣接性が必要なネットワーク セグメンテーションです。
- トラフィックの分離: セキュリティとパフォーマンスを強化するために、さまざまなタイプのトラフィックを分離します。たとえば、機密性の高い管理トラフィックをアプリケーション データ トラフィックから分離できます。
- コントロール プレーンとデータプレーンの分離: プライマリ ネットワーク インターフェースをコントロール プレーン トラフィック専用にし、高スループットのデータプレーン トラフィックをセカンダリ IPVLAN インターフェース経由で転送します。
- レイヤ 2 隣接性: 同じセカンダリ ネットワーク上の Pod 間で直接レイヤ 2 接続を必要とするアプリケーションの要件を満たします。
制限事項
Multus インターフェースで構成された Pod は、GKE の組み込みマルチネットワーキング機能を同時に使用できません。Pod のネットワーク構成では、Multus またはクラスタの組み込みマルチネットワーキングのいずれかを使用する必要があります。
Multus と IPVLAN、Whereabouts の連携の仕組み
Multus は、Pod を複数のネットワークに接続できるようにする CNI メタプラグインです。Multus はディスパッチャーとして機能し、他の CNI プラグインを呼び出して、NetworkAttachmentDefinition リソースに基づいてネットワーク インターフェースを構成します。追加のネットワークは、NetworkAttachmentDefinition を使用して定義します。これにより、そのネットワークで使用する CNI プラグイン(IPVLAN など)と IPAM プラグイン(Whereabouts など)が指定されます。
次の図は、IPVLAN プラグインと Whereabouts プラグインを使用した Multus アーキテクチャを示しています。Whereabouts プラグインは、Multus と IPVLAN を使用して、Pod の追加ネットワーク インターフェースの IP アドレス管理(IPAM)を処理します。
この図は、それぞれ 1 つの Pod を持つ 2 つのノードを示しています。各 Pod には、プライマリ インターフェースと追加のインターフェースがあります。2 つのプライマリ インターフェースは共有ネットワーク インターフェース カードに接続され、2 つの追加インターフェースは別の共有ネットワーク インターフェース カードに接続されます。
GKE で IPVLAN と Whereabouts を使用して Multus を使用する場合、通常 Pod のインターフェース構成は次のようになります。
- プライマリ インターフェース(
eth0): GKE Dataplane V2 がこのインターフェースを管理し、デフォルトのクラスタ接続を提供します。 - 追加のインターフェース(
net1など): Multus がこれらのインターフェースを管理します。Multus は、Pod のアノテーションで指定した各NetworkAttachmentDefinitionに対してレイヤ 2 モードで IPVLAN CNI プラグインを呼び出します。この構成により、セカンダリ VPC ネットワークへのレイヤ 2 接続が提供されます。 - IP アドレス管理(IPAM):
NetworkAttachmentDefinition内で Whereabouts IPAM プラグインを構成します。Whereabouts IPAM プラグインは、事前定義された範囲から追加の IPVLAN インターフェースに IP アドレスを動的に割り当てます。
複数のネットワークでの Pod のスケジューリング
Pod を作成してアノテーションで NetworkAttachmentDefinition を指定すると、GKE スケジューラはネットワーク要件を満たすノードにのみ Pod を配置します。スケジューラは、必要なセカンダリ ネットワーク インターフェースが構成されているノードプール内のノードを特定します。このノード識別プロセスにより、スケジューラは追加のネットワークに接続し、指定された範囲から IP アドレスを受信できるノードに Pod をスケジュールします。
以降のセクションでは、GKE クラスタで IPVLAN プラグインと Whereabouts プラグインを使用して Multus を構成する方法について説明します。
始める前に
作業を始める前に、次のタスクが完了していることを確認してください。
- Google Kubernetes Engine API を有効にする。 Google Kubernetes Engine API の有効化
- このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。gcloud CLI をインストール済みの場合は、
gcloud components updateコマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。
kubectlコマンドライン ツールをインストールします。- Dataplane V2、IP エイリアス、マルチネットワーキングが有効になっているバージョン 1.28 以降の GKE クラスタを設定します。方法については、Pod のマルチネットワーク サポートを設定するをご覧ください。マルチネットワーキングを有効にすると、Multi-IP-Subnet 機能と Persistent-IP HA Policy 機能も有効になります。これにより、ノード間の接続を手動で設定する必要がなくなります。
- 互換性を確保するため、GKE で検証済みの Multus CNI バージョン(v4.2.1 など)を使用します。
VPC を設定する
Multus で使用する Virtual Private Cloud(VPC)を設定するには(ノード ネットワーキング用のサブネットと Pod ネットワーキング用のセカンダリ範囲の作成を含む)、次の操作を行います。
新しい VPC を作成するか、既存の VPC を使用します。
gcloud compute networks create VPC_NAME \ --subnet-mode=customVPC_NAMEは、VPC の名前に置き換えます。この VPC 内に新しいサブネットを作成します。
gcloud compute networks subnets create SUBNET_NAME \ --range=PRIMARY_RANGE \ --network=VPC_NAME \ --region=REGION \ --secondary-range=SECONDARY_RANGE_NAME=SECONDARY_RANGE_CIDR次のように置き換えます。
SUBNET_NAME: 新しいサブネットの名前。PRIMARY_RANGE: サブネットのプライマリ CIDR 範囲(10.0.1.0/24など)。このコマンドでは、ノード インターフェースにこの範囲を使用します。VPC_NAME: VPC の名前。REGION: サブネットのリージョン(us-central1など)。SECONDARY_RANGE_NAME: サブネット内の Pod のセカンダリ IP アドレス範囲の名前。SECONDARY_RANGE_CIDR: Pod のセカンダリ CIDR 範囲(172.16.1.0/24など)。Pod の追加のインターフェースはこの範囲を使用します。
このコマンドは、追加のノード インターフェースのプライマリ CIDR 範囲と、追加の Pod インターフェースのセカンダリ範囲を持つサブネットを作成します。
GKE Standard クラスタを作成する
マルチネットワーキングを有効にして GKE Standard クラスタを作成します。
gcloud container clusters create CLUSTER_NAME \
--cluster-version=CLUSTER_VERSION \
--enable-dataplane-v2 \
--enable-ip-alias \
--enable-multi-networking
次のように置き換えます。
CLUSTER_NAME: 新しいクラスタの名前。CLUSTER_VERSION: GKE クラスタのバージョン。バージョン 1.28 以降を使用する必要があります。
マルチネットワーキングを有効にすると、Multus CNI で必要な複数のネットワーク インターフェースを持つノードプールを作成できます。
GKE Standard ノードプールを作成する
追加の VPC ネットワークに接続する GKE Standard ノードプールを作成します。
gcloud container node-pools create NODEPOOL_NAME \
--cluster CLUSTER_NAME \
--zone "ZONE" \
--additional-node-network network=VPC_NAME,subnetwork=SUBNET_NAME \
--additional-pod-network subnetwork=SUBNET_NAME,pod-ipv4-range=SECONDARY_RANGE_NAME,max-pods-per-node=8
次のように置き換えます。
NODEPOOL_NAME: 新しいノードプールの名前。CLUSTER_NAME: クラスタの名前。ZONE: ノードプールのゾーン(us-central1-cなど)。VPC_NAME: 追加の VPC の名前。SUBNET_NAME: サブネットの名前。SECONDARY_RANGE_NAME: サブネット内の Pod のセカンダリ IP アドレス範囲の名前。
このコマンドは、ノードに SUBNET_NAME の追加のネットワーク インターフェースがあり、これらのノードの Pod が SECONDARY_RANGE_NAME の IP アドレスを使用できるノードプールを作成します。
マルチネットワーキング機能を備えた GKE クラスタの作成の詳細については、Pod のマルチネットワーク サポートを設定するをご覧ください。
Multus Deployment を適用する
Pod の複数のネットワーク インターフェースを有効にするには、Multus CNI プラグインをインストールします。必要な DaemonSet とカスタム リソース定義(CRD)を含む次のマニフェストを multus-manifest.yaml として保存します。
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: ippools.whereabouts.cni.cncf.io spec: group: whereabouts.cni.cncf.io names: kind: IPPool listKind: IPPoolList plural: ippools singular: ippool scope: Namespaced versions: - name: v1alpha1 schema: openAPIV3Schema: description: IPPool is the Schema for the ippools API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources' type: string kind: description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' type: string metadata: type: object spec: description: IPPoolSpec defines the desired state of IPPool properties: allocations: additionalProperties: description: IPAllocation represents metadata about the pod/container owner of a specific IP properties: id: type: string podref: type: string required: - id type: object description: Allocations is the set of allocated IPs for the given range. Its indices are a direct mapping to the IP with the same index/offset for the pools range. type: object range: description: Range is a RFC 4632/4291-style string that represents an IP address and prefix length in CIDR notation type: string required: - allocations - range type: object type: object served: true storage: true status: acceptedNames: kind: "" plural: "" conditions: [] storedVersions: [] --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.4.1 name: overlappingrangeipreservations.whereabouts.cni.cncf.io spec: group: whereabouts.cni.cncf.io names: kind: OverlappingRangeIPReservation listKind: OverlappingRangeIPReservationList plural: overlappingrangeipreservations singular: overlappingrangeipreservation scope: Namespaced versions: - name: v1alpha1 schema: openAPIV3Schema: description: OverlappingRangeIPReservation is the Schema for the OverlappingRangeIPReservations API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object spec: description: OverlappingRangeIPReservationSpec defines the desired state of OverlappingRangeIPReservation properties: containerid: type: string podref: type: string required: - containerid type: object required: - spec type: object served: true storage: true status: acceptedNames: kind: "" plural: "" conditions: [] storedVersions: [] --- kind: ConfigMap apiVersion: v1 metadata: name: multus-cni-config namespace: kube-system labels: app: gke-multinet data: cni-conf.json: | { "name": "multus-cni-network", "type": "multus", "confDir": "/etc/cni/net.d", "namespaceIsolation": true, "logLevel": "verbose", "logFile": "/var/log/multus.log", "kubeconfig": "/var/lib/kubelet/kubeconfig", "clusterNetwork": "gke-pod-network" } --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: network-attachment-definitions.k8s.cni.cncf.io spec: group: k8s.cni.cncf.io scope: Namespaced names: plural: network-attachment-definitions singular: network-attachment-definition kind: NetworkAttachmentDefinition shortNames: - net-attach-def versions: - name: v1 served: true storage: true schema: openAPIV3Schema: description: 'NetworkAttachmentDefinition is a CRD schema specified by the Network Plumbing Working Group to express the intent for attaching pods to one or more logical or physical networks. More information available at: https://github.com/k8snetworkplumbingwg/multi-net-spec' type: object properties: apiVersion: description: 'APIVersion defines the versioned schema of this represen tation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object spec: description: 'NetworkAttachmentDefinition spec defines the desired state of a network attachment' type: object properties: config: description: 'NetworkAttachmentDefinition config is a JSON-formatted CNI configuration' type: string --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: multus-role rules: - apiGroups: ["k8s.cni.cncf.io"] resources: - '*' verbs: - '*' --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: whereabouts rules: - apiGroups: - whereabouts.cni.cncf.io resources: - ippools - overlappingrangeipreservations verbs: - get - list - watch - create - update - patch - delete - apiGroups: - coordination.k8s.io resources: - leases verbs: - create - apiGroups: - coordination.k8s.io resources: - leases resourceNames: - whereabouts verbs: - '*' - apiGroups: [""] resources: - pods verbs: - list - get --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: multus-role-binding subjects: - kind: Group name: system:nodes roleRef: kind: ClusterRole name: multus-role apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: whereabouts-role-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: whereabouts subjects: - kind: ServiceAccount name: whereabouts-sa namespace: kube-system --- apiVersion: v1 kind: ServiceAccount metadata: name: whereabouts-sa namespace: kube-system --- apiVersion: apps/v1 kind: DaemonSet metadata: name: gke-multinet namespace: kube-system labels: app: gke-multinet spec: selector: matchLabels: app: gke-multinet template: metadata: labels: app: gke-multinet spec: priorityClassName: system-node-critical hostNetwork: true tolerations: - operator: Exists serviceAccountName: whereabouts-sa containers: - name: whereabouts-gc command: [/ip-control-loop] args: - "--log-level=debug" - "--enable-pod-watch=false" - "--cron-schedule=* * * * *" image: gcr.io/gke-release/whereabouts:v0.7.0-gke.3@sha256:2bb8450a99d86c73b262f5ccd8c433d3e3abf17d36ee5c3bf1056a1fe479e8c2 env: - name: NODENAME valueFrom: fieldRef: apiVersion: v1 fieldPath: spec.nodeName - name: WHEREABOUTS_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "100m" memory: "50Mi" initContainers: - name: install-multus-config image: gcr.io/gke-release/multus-cni:v4.2.1-gke.6@sha256:25b48b8dbbf6c78a10452836f52dee456514783565b70633a168a39e6d322310 args: - "--cni-conf-dir=/host/etc/cni/net.d" - "--multus-conf-file=/tmp/multus-conf/00-multus.conf" - "--multus-log-level=verbose" - "--multus-kubeconfig-file-host=/var/lib/kubelet/kubeconfig" - "--skip-multus-binary-copy=true" - "--skip-config-watch=true" resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "100m" memory: "50Mi" securityContext: privileged: true volumeMounts: - name: cni mountPath: /host/etc/cni/net.d - name: multus-cfg mountPath: /tmp/multus-conf - name: install-whereabouts command: ["/bin/sh"] args: - -c - > SLEEP=false /install-cni.sh image: gcr.io/gke-release/whereabouts:v0.7.0-gke.3@sha256:2bb8450a99d86c73b262f5ccd8c433d3e3abf17d36ee5c3bf1056a1fe479e8c2 env: - name: NODENAME valueFrom: fieldRef: apiVersion: v1 fieldPath: spec.nodeName - name: WHEREABOUTS_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "100m" memory: "50Mi" securityContext: privileged: true volumeMounts: - name: cni mountPath: /host/etc/cni/net.d - name: cnibin mountPath: /host/opt/cni/bin - name: install-binary image: gcr.io/gke-release/multus-cni:v4.2.1-gke.6@sha256:25b48b8dbbf6c78a10452836f52dee456514783565b70633a168a39e6d322310 command: ["/gkecmd"] args: - "-operation=copy" - "-cni-bin-dir=/host/opt/cni/bin" resources: requests: cpu: "10m" memory: "100Mi" limits: cpu: "10m" memory: "100Mi" securityContext: privileged: true volumeMounts: - name: cnibin mountPath: /host/opt/cni/bin volumes: - hostPath: path: /var/lib/kubelet/kubeconfig type: File name: kubelet-credentials - name: cni hostPath: path: /etc/cni/net.d type: DirectoryOrCreate - name: cnibin hostPath: path: /home/kubernetes/bin type: DirectoryOrCreate - name: multus-cfg configMap: name: multus-cni-config items: - key: cni-conf.json path: 00-multus.conf updateStrategy: rollingUpdate: maxUnavailable: 2 type: RollingUpdate
マニフェストをクラスタに適用します。
kubectl apply -f multus-manifest.yaml
NetworkAttachmentDefinition マニフェストを作成する
Pod が追加のネットワークに接続できるようにするには、NetworkAttachmentDefinition マニフェストを作成します。このマニフェストは、Pod がネットワークに接続する方法を定義し、Whereabouts などの IPAM プラグインが割り当てる IP アドレス範囲を指定します。この範囲は、ノードの追加のネットワーク インターフェースを接続するサブネットの一部である必要があります。
このマニフェストを
nad.yamlとして保存します。このマニフェストでは、IPVLAN プラグインと Whereabouts プラグインを使用します。apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: NAD_NAME spec: config: '{ "cniVersion": "0.3.1", "plugins": [ { "type": "ipvlan", "master": "eth1", "mode": "l2", "ipam": { "type": "whereabouts", "range": SECONDARY_RANGE_NAME } } ] }'このマニフェストには次のフィールドが含まれています。
NAD_NAME:NetworkAttachmentDefinitionの名前。master: IPVLAN のmasterインターフェースとして機能するノードのセカンダリ ネットワーク インターフェースの名前。GKE では通常、セカンダリ ネットワーク インターフェースはeth1で始まり、順に名前が付けられます。インターフェース名を確認するには、SSH を使用してノードに接続し、ip addrコマンドを実行します。range: Pod インターフェースの IP アドレス範囲。Pod 用に作成したセカンダリ IPv4 範囲(SECONDARY_RANGE_NAME)と同じです。例:172.16.1.0/24。
マニフェストをクラスタに適用します。
kubectl apply -f nad.yaml
Pod を追加のネットワークに接続する
Pod を追加のネットワークに接続するには、Pod マニフェストに k8s.v1.cni.cncf.io/networks アノテーションを追加します。複数のネットワークの場合は、NetworkAttachmentDefinition 名のカンマ区切りリストを <namespace>/<nad-name> の形式で指定します。
次の例は、default Namespace の NAD_NAME という名前の NetworkAttachmentDefinition に適用する Pod マニフェストを示しています。
apiVersion: v1
kind: Pod
metadata:
name: samplepod
annotations:
k8s.v1.cni.cncf.io/networks: default/NAD_NAME
spec:
containers:
- name: sample-container
image: nginx
NAD_NAME は、作成した NetworkAttachmentDefinition の名前に置き換えます。
このマニフェストを適用すると、Kubernetes は NetworkAttachmentDefinition で指定されたネットワークに接続された追加のネットワーク インターフェース(net1)を使用して Pod を作成します。
Pod の追加 IP アドレスを確認する
Pod を追加のネットワークに接続した後に Pod が追加の IP アドレスを受信することを確認するには、Pod 内のネットワーク インターフェースを調べます。
samplepodを調べて追加の IP アドレスを確認するには、次のコマンドを使用します。$kubectl describe pod PODNAMEPODNAMEは、samplepodなどの Pod の名前に置き換えます。出力を確認します。
eth0インターフェースには、Pod のプライマリ IP アドレスがあります。Whereabouts プラグインは、追加の IP アドレスをnet1などの別のインターフェースに割り当てます。出力は次のようになります。
k8s.v1.cni.cncf.io/network-status: [{ "name": "gke-pod-network", "interface": "eth0", "ips": [ "10.104.3.4" ], "mac": "ea:e2:f6:ce:18:b5", "default": true, "dns": {}, "gateway": [ "\u003cnil\u003e" ] },{ "name": "default/my-nad", "interface": "net1", "ips": [ "10.200.1.1" ], "mac": "42:01:64:c8:c8:07", "dns": {} }] k8s.v1.cni.cncf.io/networks: default/my-nadこの例では、
10.104.5.19はeth0のプライマリ IP アドレスで、10.200.1.1はnet1の追加 IP アドレスです。
次のステップ
- Multus CNI の詳細を確認する。
- IPVLAN CNI の詳細を確認する。
- Whereabouts IPAM の詳細を確認する。