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:
- Redes de GKE.
- Redes de Kubernetes.
- Interfaz de red de contenedor (CNI).
- IPVLAN.
- Gestión de direcciones IP (IPAM).
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.
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 cadaNetworkAttachmentDefinitionque 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:
Crea una VPC o usa una que ya tengas:
gcloud compute networks create VPC_NAME \ --subnet-mode=customSustituye
VPC_NAMEpor el nombre de la VPC.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_CIDRHaz los cambios siguientes:
SUBNET_NAME: el nombre de la nueva subred.PRIMARY_RANGE: el intervalo CIDR principal de la subred, como10.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, comous-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, como172.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, comous-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.
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 tuNetworkAttachmentDefinition.master: el nombre de la interfaz de red secundaria del nodo, que actúa como interfazmasterpara IPVLAN. En GKE, las interfaces de red secundarias suelen empezar poreth1y se nombran de forma secuencial. Para confirmar el nombre de la interfaz, conéctate a un nodo mediante SSH y ejecuta el comandoip 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.
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:
Para inspeccionar el
samplepody verificar la dirección IP adicional, usa el siguiente comando:$kubectl describe pod PODNAMESustituye
PODNAMEpor el nombre de tu pod, comosamplepod.Examina el resultado. La interfaz
eth0tiene la dirección IP principal del Pod. El complemento Whereabouts asigna la dirección IP adicional a otra interfaz, comonet1.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-nadEn este ejemplo,
10.104.5.19es la dirección IP principal deeth0y10.200.1.1es la dirección IP adicional denet1.
Siguientes pasos
- Consulta más información sobre Multus CNI.
- Más información sobre IPVLAN CNI
- Más información sobre Whereabouts IPAM