Configurar Multus con IPVLAN y Whereabouts

En este documento se explica cómo configurar pods en Google Kubernetes Engine (GKE) con varias interfaces de red mediante Multus CNI, el complemento IPVLAN CNI y el complemento Whereabouts IPAM.

El plugin CNI IPVLAN proporciona conectividad de capa 2 para interfaces de pod adicionales, y el plugin IPAM Whereabouts les asigna direcciones IP de forma dinámica.

Esta configuración permite usar configuraciones de red avanzadas, como separar el tráfico del plano de control y del plano de datos para mejorar el aislamiento y la segmentación de la red.

Este documento está dirigido a arquitectos de nube y especialistas en redes que diseñan y definen la arquitectura de la red de su organización. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido de Google Cloud , consulta Roles y tareas habituales de los usuarios de GKE.

Antes de leer este documento, asegúrate de que conoces los siguientes conceptos:

Ventajas de usar Multus con IPVLAN

Configurar tus pods con varias interfaces de red mediante esta solución te ofrece varias ventajas clave. Los principales casos prácticos para configurar Multus con IPVLAN en el modo de capa 2 son la segmentación de la red que requiere la adyacencia de la capa 2:

  • Aislamiento del tráfico: aísla diferentes tipos de tráfico para mejorar la seguridad y el rendimiento. Por ejemplo, puedes separar el tráfico de gestión sensible del tráfico de datos de la aplicación.
  • Separación del plano de control y del plano de datos: dedica la interfaz de red principal al tráfico del plano de control y dirige el tráfico del plano de datos de alto rendimiento a través de una interfaz IPVLAN secundaria.
  • Adyacencia de capa 2: cumple los requisitos de las aplicaciones que necesitan conectividad directa de capa 2 entre pods de la misma red secundaria.

Limitaciones

Los pods configurados con interfaces de Multus no pueden usar simultáneamente las funciones de multirredes integradas de GKE. La configuración de red de un pod debe usar Multus o la función de multirred integrada del clúster.

Cómo funciona Multus con IPVLAN y Whereabouts

Multus es un metaplugin de CNI que permite que los pods se conecten a varias redes. Multus actúa como un distribuidor que llama a otros complementos de CNI para configurar interfaces de red basadas en recursos NetworkAttachmentDefinition. Para definir cada red adicional, se usa un NetworkAttachmentDefinition, que especifica qué complemento de CNI (como IPVLAN) y qué complemento de IPAM (como Whereabouts) se deben usar en esa red.

En el siguiente diagrama se muestra la arquitectura de Multus con los complementos IPVLAN y Whereabouts.El complemento Whereabouts funciona con Multus e IPVLAN para gestionar la gestión de direcciones IP (IPAM) de las interfaces de red adicionales de los pods.

Diagrama que muestra cómo funcionan conjuntamente Multus, IPVLAN y Whereabouts en GKE.
Imagen 1. Arquitectura de Multus con los complementos IPVLAN y Whereabouts.

En este diagrama se muestran dos nodos, cada uno con un Pod. Cada pod tiene una interfaz principal y otra adicional. Las dos interfaces principales se conectan a una tarjeta de interfaz de red compartida, y las dos interfaces adicionales se conectan a otra tarjeta de interfaz de red compartida.

Cuando se usa Multus con IPVLAN y Whereabouts en GKE, los pods suelen tener la siguiente configuración de interfaz:

  • Interfaz principal (eth0): GKE Dataplane V2 gestiona esta interfaz, que proporciona conectividad de clúster predeterminada.
  • Interfaces adicionales (net1, etc.): Multus gestiona estas interfaces. Multus invoca el complemento CNI de IPVLAN en el modo de capa 2 para cada NetworkAttachmentDefinition que especifiques en las anotaciones de un pod. Esta configuración proporciona conectividad de capa 2 a una red de VPC secundaria.
  • Gestión de direcciones IP (IPAM): configura el complemento IPAM de Whereabouts en NetworkAttachmentDefinition. El complemento Whereabouts IPAM asigna dinámicamente direcciones IP a las interfaces IPVLAN adicionales de un intervalo predefinido.

Programación de pods con varias redes

Cuando creas un pod y especificas un NetworkAttachmentDefinition en sus anotaciones, el programador de GKE coloca el pod solo en un nodo que pueda cumplir los requisitos de red. El programador identifica los nodos de un grupo de nodos que tienen configurada la interfaz de red secundaria necesaria. Este proceso de identificación de nodos asegura que el programador programe el pod en un nodo que pueda conectarse a la red adicional y recibir una dirección IP del intervalo especificado.

En las siguientes secciones se explica cómo configurar Multus con los complementos IPVLAN y Whereabouts en tu clúster de GKE.

Antes de empezar

Antes de empezar, asegúrate de que has realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si quieres usar Google Cloud CLI para esta tarea, instálala y, a continuación, inicialízala. Si ya has instalado la CLI de gcloud, obtén la versión más reciente ejecutando el comando gcloud components update. Es posible que las versiones anteriores de la interfaz de línea de comandos de gcloud no admitan la ejecución de los comandos de este documento.
  • Instala la herramienta de línea de comandos kubectl.
  • Configura un clúster de GKE que ejecute la versión 1.28 o una posterior con Dataplane V2, alias de IP y multirred habilitados. Para saber cómo hacerlo, consulta Configurar la compatibilidad con varias redes en los Pods. Al habilitar la función de multirred, también se habilitan las funciones de política de alta disponibilidad de subred de IP múltiple e IP persistente, que eliminan la necesidad de configurar manualmente la conectividad entre nodos.
  • Usa una versión de Multus CNI validada por GKE (como la 4.2.1) para que sea compatible.

Configurar una VPC

Para configurar la nube privada virtual (VPC) que se va a usar con Multus, lo que incluye la creación de una subred para la red de nodos y rangos secundarios para la red de pods, sigue estos pasos:

  1. Crea una VPC o usa una que ya tengas:

    gcloud compute networks create VPC_NAME \
    --subnet-mode=custom
    

    Sustituye VPC_NAME por el nombre de la VPC.

  2. Crea una subred en esta VPC:

    gcloud compute networks subnets create SUBNET_NAME \
        --range=PRIMARY_RANGE \
        --network=VPC_NAME \
        --region=REGION \
        --secondary-range=SECONDARY_RANGE_NAME=SECONDARY_RANGE_CIDR
    

    Haz los cambios siguientes:

    • SUBNET_NAME: el nombre de la nueva subred.
    • PRIMARY_RANGE: el intervalo CIDR principal de la subred, como 10.0.1.0/24. Este comando usa este intervalo para las interfaces de nodo.
    • VPC_NAME: el nombre de la VPC.
    • REGION: la región de la subred, como us-central1.
    • SECONDARY_RANGE_NAME: nombre del intervalo de direcciones IP secundario de los pods de la subred.
    • SECONDARY_RANGE_CIDR: el intervalo CIDR secundario de los pods, como 172.16.1.0/24. Las interfaces adicionales de los pods usan este intervalo.

    Este comando crea una subred con un intervalo CIDR principal para una interfaz de nodo adicional y un intervalo secundario para las interfaces de pod adicionales.

Crear un clúster estándar de GKE

Crea un clúster estándar de GKE con la función de multirred habilitada:

gcloud container clusters create CLUSTER_NAME \
    --cluster-version=CLUSTER_VERSION \
    --enable-dataplane-v2 \
    --enable-ip-alias \
    --enable-multi-networking

Haz los cambios siguientes:

  • CLUSTER_NAME: el nombre del nuevo clúster.
  • CLUSTER_VERSION: la versión de tu clúster de GKE. Debes usar la versión 1.28 o una posterior.

Si habilitas la función de varias redes, puedes crear grupos de nodos con varias interfaces de red, lo que requiere Multus CNI.

Crear un grupo de nodos estándar de GKE

Crea un grupo de nodos Estándar de GKE conectado a redes de VPC adicionales:

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

Haz los cambios siguientes:

  • NODEPOOL_NAME: el nombre del nuevo grupo de nodos.
  • CLUSTER_NAME: el nombre de tu clúster.
  • ZONE: la zona del grupo de nodos, como us-central1-c.
  • VPC_NAME: el nombre de la VPC adicional.
  • SUBNET_NAME: el nombre de la subred.
  • SECONDARY_RANGE_NAME: el nombre del intervalo de direcciones IP secundarias de los pods de la subred.

Este comando crea un grupo de nodos en el que los nodos tienen una interfaz de red adicional en SUBNET_NAME y los pods de estos nodos pueden usar direcciones IP de SECONDARY_RANGE_NAME.

Para obtener más información sobre cómo crear clústeres de GKE con funciones de multirred, consulta el artículo sobre cómo configurar la compatibilidad con varias redes para pods.

Aplica el despliegue de Multus

Para habilitar varias interfaces de red en tus pods, instala el complemento Multus CNI. Guarda el siguiente archivo de manifiesto, que incluye el DaemonSet y la definición de recurso personalizado (CRD) obligatorios, como 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

A continuación, aplica el manifiesto a tu clúster:

kubectl apply -f multus-manifest.yaml

Crear un manifiesto de NetworkAttachmentDefinition

Para permitir que los pods se conecten a redes adicionales, crea un manifiesto NetworkAttachmentDefinition. Este manifiesto define cómo se conectan los pods a una red y especifica el intervalo de direcciones IP que asigna un complemento de IPAM, como Whereabouts. Este intervalo debe formar parte de la subred que conecta las interfaces de red adicionales de tus nodos.

  1. Guarda este archivo de manifiesto como nad.yaml. Este manifiesto usa los complementos IPVLAN y 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
            }
          }
        ]
      }'
    

    El manifiesto incluye los siguientes campos:

    • NAD_NAME: el nombre de tu NetworkAttachmentDefinition.
    • master: el nombre de la interfaz de red secundaria del nodo, que actúa como interfaz master para IPVLAN. En GKE, las interfaces de red secundarias suelen empezar por eth1 y se nombran de forma secuencial. Para confirmar el nombre de la interfaz, conéctate a un nodo mediante SSH y ejecuta el comando ip addr.
    • range: el intervalo de direcciones IP de las interfaces de los pods, que es el mismo que el intervalo IPv4 secundario que has creado para los pods (SECONDARY_RANGE_NAME). Por ejemplo, 172.16.1.0/24.
  2. Aplica el manifiesto a tu clúster:

    kubectl apply -f nad.yaml
    

Asignar pods a redes adicionales

Para adjuntar un Pod a una red adicional, añade la anotación k8s.v1.cni.cncf.io/networks al manifiesto del Pod. Si se trata de varias cadenas, proporciona una lista de nombres de NetworkAttachmentDefinition separados por comas con el siguiente formato: <namespace>/<nad-name>.

En el siguiente ejemplo se muestra un manifiesto de Pod que se adjunta al NetworkAttachmentDefinition llamado NAD_NAME en el espacio de nombres default:

apiVersion: v1
kind: Pod
metadata:
  name: samplepod
  annotations:
    k8s.v1.cni.cncf.io/networks: default/NAD_NAME
spec:
  containers:
  - name: sample-container
    image: nginx

Sustituye NAD_NAME por el nombre del NetworkAttachmentDefinition que has creado.

Cuando aplicas este manifiesto, Kubernetes crea el pod con una interfaz de red adicional (net1) conectada a la red que especifica NetworkAttachmentDefinition.

Verificar la dirección IP adicional del Pod

Para verificar que el pod recibe una dirección IP adicional después de conectarlo a una red adicional, inspecciona las interfaces de red del pod:

  1. Para inspeccionar el samplepod y verificar la dirección IP adicional, usa el siguiente comando:

    $kubectl describe pod PODNAME
    

    Sustituye PODNAME por el nombre de tu pod, como samplepod.

  2. Examina el resultado. La interfaz eth0 tiene la dirección IP principal del Pod. El complemento Whereabouts asigna la dirección IP adicional a otra interfaz, como net1.

    El resultado debería ser similar al siguiente:

    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
    

    En este ejemplo, 10.104.5.19 es la dirección IP principal de eth0 y 10.200.1.1 es la dirección IP adicional de net1.

Siguientes pasos