Configurer la mise en réseau SR-IOV

Ce document décrit comment configurer la mise en réseau de la virtualisation d'entrée/sortie à racine unique (SR-IOV) pour le cloud distribué de Google. SR-IOV fournit une virtualisation d'E/S pour rendre une carte d'interface réseau (NIC) disponible en tant qu'appareil réseau dans le noyau Linux. Cela vous permet de gérer et d'attribuer les connexions réseau à vos pods. Les performances sont améliorées car les paquets se déplacent directement entre la carte d'interface réseau et le pod.

Utilisez cette fonctionnalité si vous avez besoin d'une mise en réseau rapide vers les charges de travail de vos pods. La mise en réseau SR-IOV pour Google Distributed Cloud vous permet de configurer les fonctions virtuelles (VF) sur les appareils compatibles des nœuds de votre cluster. Vous pouvez également spécifier le module de noyau spécifique à lier aux VF.

Cette fonctionnalité est disponible pour les clusters qui exécutent des charges de travail, à savoir les clusters hybrides, autonomes et d'utilisateur. La fonctionnalité de mise en réseau SR-IOV nécessite que le cluster comporte au moins deux nœuds.

Le processus de configuration comprend les étapes générales suivantes :

  1. Configurez le cluster pour activer la mise en réseau SR-IOV.
  2. Configurez l'opérateur SR-IOV, qui est une ressource personnalisée SriovOperatorConfig.
  3. Configurez les stratégies SR-IOV, ainsi que vos VF.
  4. Créez une ressource personnalisée NetworkAttachmentDefinition qui référence vos VF.

Conditions requises

La fonctionnalité de mise en réseau SR-IOV nécessite que les pilotes officiels des adaptateurs réseau soient présents sur les nœuds du cluster. Installez les pilotes avant d'utiliser l'opérateur SR-IOV. Par ailleurs, pour utiliser le module vfio-pci pour vos VF, assurez-vous que le module est disponible sur les nœuds où il doit être utilisé.

Activer la mise en réseau SR-IOV pour un cluster

Pour activer la mise en réseau SR-IOV pour Google Distributed Cloud, ajoutez les champs multipleNetworkInterfaces et sriovOperator à la section clusterNetwork de l'objet Cluster et définissez-les sur true.

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: cluster1
spec:
  clusterNetwork:
    multipleNetworkInterfaces: true
    sriovOperator: true
...

Le champ sriovOperator est modifiable après la création du cluster.

Configurer l'opérateur SR-IOV

La ressource personnalisée SriovOperatorConfig fournit une configuration globale pour la fonctionnalité de mise en réseau SR-IOV. Cette ressource personnalisée groupée porte le nom default et se trouve dans l'espace de noms gke-operators. La ressource personnalisée SriovOperatorConfig n'est honorée que pour ce nom et cet espace de noms.

Vous pouvez modifier cet objet à l'aide de la commande suivante :

kubectl -n gke-operators edit sriovoperatorconfigs.sriovnetwork.k8s.cni.cncf.io default

Voici un exemple de configuration de ressources personnalisées SriovOperatorConfig :

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovOperatorConfig
metadata:
  name: default
  namespace: gke-operators
spec:
  configDaemonNodeSelector:
    nodePool: "withSriov"
  disableDrain: false
  logLevel: 0

La section configDaemonNodeSelector vous permet de limiter les nœuds que l'opérateur SR-IOV peut gérer. Dans l'exemple précédent, l'opérateur est limité aux nœuds portant le libellé nodePool: withSriov. Si le champ configDaemonNodeSelector n'est pas spécifié, les libellés par défaut suivants sont appliqués :

beta.kubernetes.io/os: linux
node-role.kubernetes.io/worker: ""

Le champ disableDrain indique s'il faut effectuer une opération de drainage du nœud Kubernetes avant le redémarrage du nœud ou avant la modification d'une configuration de VF spécifique.

Créer des stratégies SR-IOV

Pour configurer des VF spécifiques dans votre cluster, vous devez créer une ressource personnalisée SriovNetworkNodePolicy dans l'espace de noms gke-operators.

Voici un exemple de fichier manifeste pour une ressource personnalisée SriovNetworkNodePolicy :

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
  namespace: gke-operators
spec:
  deviceType: "netdevice"
  mtu: 1600
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0
    deviceID: "1015"
    rootDevices:
    - 0000:01:00.0
    vendor: "15b3"
  numVfs: 4
  priority: 80
  resourceName: "mlnx"

La section nodeSelector vous permet de limiter davantage les nœuds sur lesquels les VF doivent être créés. Cette limitation s'ajoute aux sélecteurs de SriovOperatorConfig décrits dans la section précédente.

Le champ deviceType spécifie le module de noyau à utiliser pour les VF. Les options disponibles pour deviceType sont les suivantes :

  • netdevice pour le module de noyau standard spécifique aux VF
  • vfio-pci pour le pilote VFIO-PCI

resourceName définit le nom par lequel les VF sont représentés dans le nœud Kubernetes.

Une fois le processus de configuration terminé, les nœuds de cluster sélectionnés contiennent la ressource définie, comme indiqué dans l'exemple suivant (notez la présence de gke.io/mlnx) :

apiVersion: v1
kind: Node
metadata:
  name: worker-01
spec:

status:
  allocatable:
    cpu: 47410m
    ephemeral-storage: "210725550141"
    gke.io/mlnx: "4"
    hugepages-1Gi: "0"
    hugepages-2Mi: "0"
    memory: 59884492Ki
    pods: "250"
  capacity:
    cpu: "48"
    ephemeral-storage: 228651856Ki
    gke.io/mlnx: "4"
    hugepages-1Gi: "0"
    hugepages-2Mi: "0"
    memory: 65516492Ki
    pods: "250"

L'opérateur ajoute toujours le préfixe gke.io/ à chaque ressource que vous définissez avec SriovNetworkNodePolicy.

Spécifier un sélecteur de carte d'interface réseau

Pour que SriovNetworkNodePolicy fonctionne correctement, spécifiez au moins un sélecteur dans la section nicSelector. Ce champ contient plusieurs options permettant d'identifier des fonctions physiques (PF) spécifiques dans vos nœuds de cluster. La plupart des informations requises par ce champ sont détectées automatiquement et enregistrées dans la ressource personnalisée SriovNetworkNodeState. Un objet sera présent pour chaque nœud que cet opérateur peut gérer.

Utilisez la commande suivante pour afficher tous les nœuds disponibles :

kubectl -n gke-operators get sriovnetworknodestates.sriovnetwork.k8s.cni.cncf.io -o yaml

Voici un exemple de nœud :

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodeState
metadata:
  name: worker-01
  namespace: gke-operators
spec:
  dpConfigVersion: "6368949"
status:
  interfaces:
  - deviceID: "1015"
    driver: mlx5_core
    eSwitchMode: legacy
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9c
    mtu: 1500
    name: enp1s0f0
    pciAddress: "0000:01:00.0"
    totalvfs: 4
    vendor: 15b3
  - deviceID: "1015"
    driver: mlx5_core
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9d
    mtu: 1500
    name: enp1s0f1
    pciAddress: "0000:01:00.1"
    totalvfs: 2
    vendor: 15b3
  syncStatus: Succeeded

Définir le partitionnement des fonctions physiques (PF)

Portez une attention particulière au champ pfNames de la section nicSelector. En plus de définir la valeur PF exacte à utiliser, il vous permet de spécifier les VF exactes à utiliser pour la PF spécifiée et la ressource définie dans la règle.

Exemple :

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
  namespace: gke-operators
spec:
  deviceType: "netdevice"
  mtu: 1600
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#3-6
    deviceID: "1015"
    rootDevices:
    - 0000:01:00.0
    vendor: "15b3"
  numVfs: 7
  priority: 80
  resourceName: "mlnx"

Dans l'exemple précédent, la ressource gke.io/mlnx n'utilise que des VF numérotées de 3 à 6 et ne présente que quatre VF disponibles. Étant donné que les VF sont toujours créées à partir de l'index zéro, le nombre de VF demandé numVfs doit être au moins égal à la valeur de fermeture de la plage (en comptant à partir de zéro). Cette logique de numérotation explique pourquoi numVfs est défini sur 7 dans l'exemple précédent. Si vous définissez une plage comprise entre 3 et 4 (enp65s0f0#3-4), votre valeur numVfs doit être au moins égale à 5.

Lorsque le partitionnement n'est pas spécifié, numVfs définit la plage de VF utilisée, qui démarre toujours à partir de zéro. Par exemple, si vous définissez numVfs=3 sans spécifier de partitionnement, les VF 0-2 sont utilisées.

Comprendre la priorité des stratégies

Vous pouvez spécifier plusieurs objets SriovNetworkNodePolicy pour gérer différents fournisseurs ou différentes configurations de VF. La gestion de plusieurs objets et fournisseurs peut s'avérer problématique lorsque plusieurs stratégies font référence au même PF. Pour gérer ces situations, le champ priority résout les conflits par nœud.

Voici la logique de priorité des stratégies PF qui se chevauchent :

  1. Une stratégie de priorité plus élevée n'écrase une stratégie de priorité inférieure que lorsque le partitionnement des PF se chevauche.

  2. Les stratégies de priorité identique sont fusionnées :

    1. Les stratégies sont triées par nom et traitées dans cet ordre
    2. Les stratégies dont le partitionnement des PF se chevauche sont écrasées
    3. Les stratégies avec un partitionnement des PF sans chevauchement sont fusionnées et s'affichent toutes

Une stratégie de priorité élevée est une stratégie dont la valeur numérique est inférieure dans le champ priority. Par exemple, la priorité est plus élevée pour une stratégie avec la valeur priority: 10 que pour une stratégie avec la valeur priority: 20.

Les sections suivantes fournissent des exemples de stratégies pour différentes configurations de partitionnement.

PF partitionnés

Le déploiement des deux fichiers manifestes SriovNetworkNodePolicy suivants génère deux ressources disponibles : gke.io/dev-kernel et gke.io/dev-vfio. Chaque ressource possède deux VF qui ne se chevauchent pas.

kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
spec:
  deviceType: "netdevice"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#0-1
  numVfs: 2
  priority: 70
  resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
  name: policy-2
spec:
  deviceType: "vfio-pci"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#2-3
  numVfs: 4
  priority: 70
  resourceName: "dev-vfio"

Chevauchement du partitionnement des PF

En déployant les deux fichiers manifestes SriovNetworkNodePolicy suivants, seule la ressource gke.io/dev-vfio est disponible. La plage de VF policy-1 est 0-2, qui chevauche policy-2. En raison de la dénomination, policy-2 est traité après policy-1. Par conséquent, seule la ressource spécifiée dans policy-2, gke.io/dev-vfio, est disponible.

kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
spec:
  deviceType: "netdevice"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0
  numVfs: 3
  priority: 70
  resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
  name: policy-2
spec:
  deviceType: "vfio-pci"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#2-3
  numVfs: 4
  priority: 70
  resourceName: "dev-vfio"

Partitionnement de PF sans chevauchement avec des priorités différentes

Le déploiement des deux fichiers manifestes SriovNetworkNodePolicy suivants génère deux ressources disponibles : gke.io/dev-kernel et gke.io/dev-vfio. Chaque ressource possède deux VF qui ne se chevauchent pas. Même si policy-1 possède une priorité plus élevée que policy-2, car le partitionnement des PF ne se chevauche pas, nous fusionnons les deux stratégies.

kind: SriovNetworkNodePolicy
metadata:
  name: policy-1
spec:
  deviceType: "netdevice"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0
  numVfs: 2
  priority: 10
  resourceName: "dev-kernel"
kind: SriovNetworkNodePolicy
metadata:
  name: policy-2
spec:
  deviceType: "vfio-pci"
  nodeSelector:
    baremetal.cluster.gke.io/node-pool: node-pool-1
  nicSelector:
    pfNames:
    - enp65s0f0#2-3
  numVfs: 4
  priority: 70
  resourceName: "dev-vfio"

Vérifier l'état de configuration de la stratégie SR-IOV

Lorsque vous appliquez les stratégies SR-IOV, vous pouvez suivre et afficher la configuration finale des nœuds dans la ressource personnalisée SriovNetworkNodeState pour le nœud spécifique. Dans la section status, le champ syncStatus représente l'étape actuelle du daemon de configuration. L'état Succeeded indique que la configuration est terminée. La section spec de la ressource personnalisée SriovNetworkNodeState définit l'état final de la configuration des VF pour ce nœud, en fonction du nombre de stratégies et de leurs priorités. Toutes les VF créées seront listées dans la section status pour les PF spécifiées.

Voici un exemple de ressource personnalisée SriovNetworkNodeState :

apiVersion: sriovnetwork.k8s.cni.cncf.io/v1
kind: SriovNetworkNodeState
metadata:
  name: worker-02
  namespace: gke-operators
spec:
  dpConfigVersion: "9022068"
  interfaces:
  - linkType: eth
    name: enp1s0f0
    numVfs: 2
    pciAddress: "0000:01:00.0"
    vfGroups:
    - deviceType: netdevice
      policyName: policy-1
      resourceName: mlnx
      vfRange: 0-1
status:
  interfaces:
  - Vfs:
    - deviceID: "1016"
      driver: mlx5_core
      mac: 96:8b:39:d8:89:d2
      mtu: 1500
      name: enp1s0f0np0v0
      pciAddress: "0000:01:00.2"
      vendor: 15b3
      vfID: 0
    - deviceID: "1016"
      driver: mlx5_core
      mac: 82:8e:65:fe:9b:cb
      mtu: 1500
      name: enp1s0f0np0v1
      pciAddress: "0000:01:00.3"
      vendor: 15b3
      vfID: 1
    deviceID: "1015"
    driver: mlx5_core
    eSwitchMode: legacy
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9c
    mtu: 1500
    name: enp1s0f0
    numVfs: 2
    pciAddress: "0000:01:00.0"
    totalvfs: 2
    vendor: 15b3
  - deviceID: "1015"
    driver: mlx5_core
    linkSpeed: 10000 Mb/s
    linkType: ETH
    mac: 1c:34:da:5c:2b:9d
    mtu: 1500
    name: enp1s0f1
    pciAddress: "0000:01:00.1"
    totalvfs: 2
    vendor: 15b3
  syncStatus: Succeeded

Créer une ressource personnalisée NetworkAttachmentDefinition

Une fois que vous avez configuré les VF sur le cluster et qu'elles sont visibles dans le nœud Kubernetes en tant que ressource, vous devez créer un NetworkAttachmentDefinition qui référence la ressource. Créez la référence avec une annotation k8s.v1.cni.cncf.io/resourceName. Voici un exemple de fichier manifeste NetworkAttachmentDefinition qui référence la ressource gke.io/mlnx :

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: gke-sriov-1
  annotations:
    k8s.v1.cni.cncf.io/resourceName: gke.io/mlnx
spec:
  config: '{
      "cniVersion": "0.3.0",
      "name": "mynetwork",
      "type": "sriov",
      "ipam": {
        "type": "whereabouts",
        "range": "21.0.108.0/21",
        "range_start": "21.0.111.16",
        "range_end": "21.0.111.18"
      }
    }'

NetworkAttachmentDefinition doit avoir sriov comme type de CNI. Référencez toutes les ressources personnalisées NetworkAttachmentDefinition déployées dans vos pods avec une annotation k8s.v1.cni.cncf.io/networks.

Voici un exemple de référence à la ressource personnalisée NetworkAttachmentDefinition précédente dans un pod :

apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: gke-sriov-1
spec:
  containers:
  ...

Lorsque vous référencez une ressource personnalisée NetworkAttachmentDefinition dans des charges de travail, vous n'avez pas à vous soucier des définitions de ressources des pods, ni des emplacements dans des nœuds spécifiques, qui sont effectués automatiquement pour vous.

L'exemple suivant montre une ressource personnalisée NetworkAttachmentDefinition avec une configuration VLAN. Dans cet exemple, chaque VF appartient au VLAN 100 :

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: gke-sriov-vlan-100
  annotations:
    k8s.v1.cni.cncf.io/resourceName: gke.io/mlnx
spec:
  config: '{
      "cniVersion": "0.3.0",
      "name": "mynetwork",
      "type": "sriov",
      "vlan": 100,
      "ipam": {
        "type": "whereabouts",
        "range": "21.0.100.0/21"
      }
    }'

Informations supplémentaires

Les sections suivantes contiennent des informations qui vous aideront à configurer la mise en réseau SR-IOV.

Redémarrages de nœuds

Lorsque l'opérateur SR-IOV configure les nœuds, un redémarrage des nœuds peut s'avérer nécessaire. Le redémarrage des nœuds peut être nécessaire lors de la configuration des VF ou du noyau. La configuration du noyau implique d'activer la prise en charge de la fonctionnalité SR-IOV dans le système d'exploitation.

Cartes réseau compatibles

Le tableau suivant regroupe les adaptateurs réseau compatibles avec les clusters en version 1.30.x :

Nom ID fournisseur ID de l'appareil ID de l'appareil de VF
Intel i40e XXV710 8086 158a 154c
Intel i40e 25G SFP28 8086 158b 154c
Intel i40e 10G X710 SFP 8086 1572 154c
Intel i40e XXV710 N3000 8086 0d58 154c
Intel i40e 40G XL710 QSFP 8086 1583 154c
Intel ice Columbiaville E810-CQDA2 2CQDA2 8086 1 592 1889
Intel ice Columbiaville E810-XXVDA4 8086 1593 1889
Intel ice Columbiaville E810-XXVDA2 8086 159b 1889
Nvidia mlx5 ConnectX-4 15b3 1013 1014
Nvidia mlx5 ConnectX-4LX 15b3 1015 1016
Nvidia mlx5 ConnectX-5 15b3 1017 1018
Nvidia mlx5 ConnectX-5 Ex 15b3 1019 101a
Nvidia mlx5 ConnectX-6 15b3 101b 101c
Nvidia mlx5 ConnectX-6_Dx 15b3 101d 101e
Nvidia mlx5 MT42822 BlueField-2 integrated ConnectX-6 Dx 15b3 a2d6 101e
Broadcom bnxt BCM57414 2x25G 14e4 16d7 16dc
Broadcom bnxt BCM75508 2x100G 14e4 1750 1806