41 Configuración de funciones de telecomunicaciones #
Esta sección documenta y explica la configuración de las funciones específicas para telecomunicaciones en clústeres desplegados mediante SUSE Edge for Telco.
Se utiliza el método de despliegue de aprovisionamiento de red dirigida, descrito en la sección sobre aprovisionamiento automatizado (Capítulo 42, Aprovisionamiento de red dirigida totalmente automatizado).
En esta sección se tratan los siguientes temas:
Imagen del kernel en tiempo real (Sección 41.1, “Imagen del kernel en tiempo real”): imagen que se usará para el kernel en tiempo real.
Argumentos del kernel para baja latencia y alto rendimiento (Sección 41.2, “Argumentos del kernel para baja latencia y alto rendimiento”): los argumentos que debe utilizar el kernel en tiempo real para conseguir el máximo rendimiento y una baja latencia al ejecutar cargas de trabajo de telecomunicaciones.
Fijación de CPU mediante Tuned y argumentos del kernel (Sección 41.3, “Fijación de CPU mediante Tuned y argumentos del kernel”): aislamiento de las CPU mediante argumentos del kernel y el perfil Tuned.
Configuración de la CNI (Sección 41.4, “Configuración de la CNI”): la configuración de la CNI que usará el clúster de Kubernetes.
Configuración de SR-IOV (Sección 41.5, “SR-IOV”): la configuración de SR-IOV que usarán las cargas de trabajo de Kubernetes.
Configuración de DPDK (Sección 41.6, “DPDK”): la configuración de DPDK que usará el sistema.
Tarjeta de aceleración vRAN (Sección 41.7, “Aceleración vRAN (
Intel ACC100/ACC200
)”): configuración de la tarjeta de aceleración que usarán las cargas de trabajo de Kubernetes.Páginas enormes (Sección 41.8, “Páginas enormes”): configuración de páginas enormes (huge) que usarán las cargas de trabajo de Kubernetes.
Fijación de CPU en Kubernetes (Sección 41.9, “Fijación de CPU en Kubernetes”): configuración de Kubernetes y las aplicaciones para aprovechar la fijación de CPU.
Configuración de programación compatible con NUMA (Sección 41.10, “Programación compatible con NUMA”): configuración de programación compatible con NUMA que usarán las cargas de trabajo de Kubernetes.
Configuración de MetalLB (Sección 41.11, “MetalLB”): configuración de MetalLB que usarán las cargas de trabajo de Kubernetes.
Configuración del registro privado (Sección 41.12, “Configuración del registro privado”): configuración del registro privado que usarán las cargas de trabajo de Kubernetes.
Configuración del protocolo de tiempo de precisión (Sección 41.13, “Protocolo de tiempo de precisión (PTP)”): archivos de configuración para ejecutar perfiles PTP de telecomunicaciones.
41.1 Imagen del kernel en tiempo real #
Usar una imagen de kernel en tiempo real no es necesariamente mejor que usar un kernel estándar. Se trata de un kernel diferente, optimizado para un caso práctico concreto. El kernel en tiempo real está optimizado para reducir la latencia a costa del rendimiento. No se recomienda el uso del kernel en tiempo real para fines generales, pero en nuestro caso, es el kernel recomendado para cargas de trabajo de telecomunicaciones, donde la latencia es un factor clave.
Hay cuatro funciones principales:
Ejecución determinista:
Se consigue una mayor previsibilidad: se garantiza que los procesos empresariales críticos se completan a tiempo, siempre, y ofrece un servicio de alta calidad, incluso con cargas elevadas del sistema. Al proteger los recursos clave del sistema para los procesos de alta prioridad, se garantiza una mayor previsibilidad para las aplicaciones en las que el tiempo es importante.
Baja fluctuación:
La baja fluctuación basada en la tecnología altamente determinista ayuda a mantener las aplicaciones sincronizadas con el mundo real. Esto ayuda a los servicios que necesitan cálculos continuos y repetidos.
Herencia de prioridad:
La herencia de prioridad hace referencia a la capacidad de un proceso de subir de prioridad si existe un proceso de mayor prioridad que requiere que el de menor prioridad finalice antes para poder completar su tarea. SUSE Linux Enterprise Real Time resuelve estos problemas de inversión de prioridad para los procesos críticos.
Interrupciones de subprocesos:
En un sistema operativo de uso general, no se pueden interrumpir los procesos que se ejecutan en modo de interrupción. Con SUSE Linux Enterprise Real Time, estas interrupciones se encapsulan en subprocesos del kernel, que son interrumpibles. De esta forma, los procesos de mayor prioridad definidos por el usuario pueden interrumpir tanto interrupciones duras como suaves.
En nuestro caso, si ha instalado una imagen en tiempo real como
SUSE Linux Micro RT
, el kernel en tiempo real ya está instalado. Puede descargar la imagen del kernel en tiempo real del Centro de servicios al cliente de SUSE.
41.2 Argumentos del kernel para baja latencia y alto rendimiento #
Es importante configurar los argumentos del kernel para que el kernel en tiempo real funcione correctamente y ofrezca el mejor rendimiento y una baja latencia para ejecutar cargas de trabajo de telecomunicaciones. Hay algunos conceptos importantes que hay que tener en cuenta al configurar los argumentos del kernel para este caso práctico:
Elimine
kthread_cpus
cuando use el kernel en tiempo real de SUSE. Este parámetro controla en qué CPU se crean los subprocesos del kernel. También controla qué CPU están permitidas para el PID 1 y para cargar módulos del kernel (el ayudante del espacio de usuario kmod). Este parámetro no se reconoce y no tiene ningún efecto.Use
isolcpus
,nohz_full
,rcu_nocbs
eirqaffinity
para aislar los núcleos de CPU. Para obtener una lista completa de las técnicas de fijación de CPU, consulte el capítulo sobre fijación de CPU mediante Tuned y argumentos del kernel (Sección 41.3, “Fijación de CPU mediante Tuned y argumentos del kernel”).Añade los indicadores
domain,nohz,managed_irq
al argumento del kernelisolcpus
. Si no se añade ningún indicador,isolcpus
equivale a especificar solo el indicadordomain
. Esto aísla las CPU especificadas de la programación, incluidas las tareas del kernel. El indicadornohz
detiene la marca del programador en las CPU especificadas (si solo se puede ejecutar una tarea en una CPU), y el indicadormanaged_irq
evita el enrutamiento de interrupciones externas gestionadas (dispositivos) en las CPU especificadas. Tenga en cuenta que las líneas IRQ de los dispositivos NVMe están totalmente gestionadas por el kernel y, como consecuencia, se enrutarán a los núcleos no aislados (de mantenimiento). Por ejemplo, la línea de comandos que se proporciona al final de esta sección dará como resultado que solo se asignen cuatro colas (más una cola de administración/control) en el sistema:for I in $(grep nvme0 /proc/interrupts | cut -d ':' -f1); do cat /proc/irq/${I}/effective_affinity_list; done | column 39 0 19 20 39
Este comportamiento evita cualquier interrupción causada por la E/S del disco en cualquier aplicación sensible al tiempo que se ejecute en los núcleos aislados, pero puede requerir atención y un diseño cuidadoso para las cargas de trabajo centradas en el almacenamiento.
Ajuste las marcas (ticks, interrupciones periódicas del temporizador del kernel):
skew_tick=1
: a veces, las marcas pueden ocurrir simultáneamente. En lugar de que todas las CPU reciban su marca de temporizador exactamente al mismo tiempo,skew_tick=1
hace que se produzcan en momentos ligeramente distintos. Esto ayuda a reducir la fluctuación del sistema, lo que se traduce en tiempos de respuesta a las interrupciones más consistentes y más bajos (un requisito esencial para las aplicaciones sensibles a la latencia).nohz=on
: detiene la marca del temporizador periódico en las CPU inactivas.nohz_full=<núcleos-cpu>
: detiene la marca del temporizador periódico en las CPU especificadas que están dedicadas a aplicaciones en tiempo real.
Inhabilite la gestión de excepciones de comprobación de máquina (MCE) especificando
mce=off
. Las MCE son errores de hardware detectados por el procesador y desactivarlas puede evitar que los registros sean excesivamente grandes.Añada
nowatchdog
para inhabilitar el watchdog de bloqueo suave, que se implementa como un temporizador que se ejecuta en el contexto de interrupción dura del temporizador. Cuando caduca (es decir, cuando se detecta un bloqueo suave), muestra una advertencia (en el contexto de interrupción dura) y ejecuta cualquier objetivo de latencia. Incluso si no caduca nunca, pasa a la lista de temporizadores, lo que aumenta ligeramente la sobrecarga de cada interrupción del temporizador. Esta opción también inhabilita el watchdog de NMI, por lo que las NMI no pueden interferir.nmi_watchdog=0
inhabilita el watchdog de NMI (interrupción no enmascarable). Se puede omitir si se usanowatchdog
.RCU (Read-Copy-Update, leer-copiar-actualizar) es un mecanismo del kernel que permite el acceso simultáneo y sin bloqueos de muchos lectores a datos compartidos. Una retrollamada RCU, una función que se activa tras un "periodo de gracia", garantiza que todos los lectores anteriores hayan terminado, de modo que los datos antiguos puedan recuperarse de forma segura. Ajustamos RCU, especialmente para cargas de trabajo sensibles, con el fin de descargar estas retrollamadas de CPU dedicadas (fijadas), evitando que las operaciones del kernel interfieran con tareas críticas y sensibles al tiempo.
Especifique las CPU fijadas en
rcu_nocbs
para que las retrollamadas de RCU no se ejecuten en ellas. Esto ayuda a reducir la fluctuación y la latencia de las cargas de trabajo en tiempo real.rcu_nocb_poll
hace que las CPU sin retrollamada realicen sondeos periódicos para comprobar si es necesario gestionar la retrollamada. Esto puede reducir la sobrecarga de interrupciones.rcupdate.rcu_cpu_stall_suppress=1
suprime las advertencias de bloqueo de la CPU por RCU, que en ocasiones pueden ser falsos positivos en sistemas en tiempo real con mucha carga.rcupdate.rcu_expedited=1
acelera el período de gracia para las operaciones RCU, lo que hace que las secciones críticas de lectura sean más receptivas.rcupdate.rcu_normal_after_boot=1
, cuando se usa con rcu_expedited, permite que RCU vuelva al funcionamiento normal (no acelerado) después del arranque del sistema.rcupdate.rcu_task_stall_timeout=0
inhabilita el detector de bloqueo de tareas RCU, lo que evita posibles advertencias o interrupciones del sistema provocadas por tareas RCU de larga duración.rcutree.kthread_prio=99
establece la prioridad del subproceso del kernel de retrollamadas de RCU al máximo posible (99), lo que garantiza que se programen y gestionen las retrollamadas de RCU con rapidez cuando sea necesario.
Añada
ignition.platform.id=openstack
para Metal3 y Cluster API a fin de aprovisionar/desaprovisionar correctamente el clúster. Esto lo utiliza el agente Python de Metal3, que tiene su origen en Openstack Ironic.Elimine
intel_pstate=passive
. Esta opción configuraintel_pstate
para que funcione con reguladores cpufreq genéricos; pero, para que esto funcione, inhabilita los estados P gestionados por hardware (HWP
) como efecto secundario. Para reducir la latencia del hardware, no se recomienda utilizar esta opción para cargas de trabajo en tiempo real.Reemplace
intel_idle.max_cstate=0 processor.max_cstate=1
poridle=poll
. Para evitar las transiciones de estado C, se usa la opciónidle=poll
para inhabilitar las transiciones de estado C y mantener la CPU en el estado C más alto. La opciónintel_idle.max_cstate=0
inhabilitaintel_idle
, por lo que se usaacpi_idle
, yacpi_idle.max_cstate=1
establece el estado C máximo para acpi_idle. En arquitecturas AMD64/Intel 64, el primer estado C de ACPI es siemprePOLL
, pero usa una funciónpoll_idle()
, que puede introducir una pequeña latencia al leer el reloj periódicamente y reiniciar el bucle principal endo_idle()
después de un tiempo de espera (esto también implica borrar y establecer el indicador de tareaTIF_POLL
). Por el contrario,idle=poll
se ejecuta en un bucle cerrado, esperando activamente a que se reprogramen las tareas. Esto minimiza la latencia al salir del estado de inactividad, pero a costa de mantener la CPU funcionando a toda velocidad en el subproceso inactivo.Desactive C1E en BIOS. Es importante desactivar el estado C1E en el BIOS para evitar que la CPU entre en el estado C1E cuando está inactiva. El estado C1E es un estado de bajo consumo que puede introducir latencia cuando la CPU está inactiva.
El resto de esta documentación trata sobre parámetros adicionales, incluyendo las páginas enormes e IOMMU.
Se proporciona un ejemplo de argumentos del kernel para un servidor Intel de 32 núcleos, que incluye los ajustes mencionados anteriormente:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll
Aquí hay otro ejemplo de configuración para un servidor AMD de 64
núcleos. Entre los 128 procesadores lógicos (0-127
), los
primeros 8 núcleos (0-7
) se destinan a tareas de
mantenimiento, mientras que los 120 núcleos restantes
(8-127
) se fijan para las aplicaciones:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=575291cf-74e8-42cf-8f2c-408a20dc00b8 skew_tick=1 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack amd_iommu=on iommu=pt irqaffinity=0-7 isolcpus=domain,nohz,managed_irq,8-127 nohz_full=8-127 rcu_nocbs=8-127 mce=off nohz=on net.ifnames=0 nowatchdog nmi_watchdog=0 nosoftlockup quiet rcu_nocb_poll rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll
41.3 Fijación de CPU mediante Tuned y argumentos del kernel #
tuned
es una herramienta de ajuste del sistema que
supervisa las condiciones del sistema para optimizar el rendimiento usando
varios perfiles predefinidos. Una característica clave es su capacidad para
aislar los núcleos de la CPU para cargas de trabajo específicas, como
aplicaciones en tiempo real. Esto evita que el sistema operativo utilice
esos núcleos y aumente potencialmente la latencia.
Para habilitar y configurar esta función, lo primero es crear un perfil para
los núcleos de CPU que se deseen aislar. En este ejemplo, dedicamos 60 de
los 64 núcleos (1-30,33-62
) a la aplicación y los 4
núcleos restantes para tareas de mantenimiento. Tenga en cuenta que el
diseño de las CPU aisladas depende en gran medida de las aplicaciones en
tiempo real.
$ echo "export tuned_params" >> /etc/grub.d/00_tuned
$ echo "isolated_cores=1-30,33-62" >> /etc/tuned/cpu-partitioning-variables.conf
$ tuned-adm profile cpu-partitioning
Tuned (re)started, changes applied.
A continuación, debemos modificar la opción GRUB para aislar los núcleos de CPU y otros parámetros importantes para el uso de las CPU. Es importante personalizar las opciones siguientes con las especificaciones reales de su hardware:
Parámetro | Valor | Descripción |
---|---|---|
isolcpus | domain,nohz,managed_irq,1-30,33-62 | Aísla los núcleos 1-30 y 33-62. |
skew_tick | 1 | Esta opción permite al kernel distribuir las interrupciones del temporizador entre las CPU aisladas. |
nohz | on | Si está habilitada, la interrupción periódica del temporizador del kernel
(la "marca") se detendrá en cualquier núcleo de CPU que esté inactivo. Esto
beneficia principalmente a las CPU de mantenimiento
( |
nohz_full | 1-30,33-62 | En el caso de los núcleos aislados, esto detiene la marca incluso si la CPU está ejecutando una sola tarea activa. Es decir, hace que la CPU funcione en modo totalmente sin marcas (o "dyntick"). El kernel solo proporcionará interrupciones del temporizador cuando sean realmente necesarias. |
rcu_nocbs | 1-30,33-62 | Esta opción descarga el procesamiento de retrollamada de RCU de los núcleos de CPU especificados. |
rcu_nocb_poll | Cuando esta opción está definida, las CPU sin retrollamada de RCU realizarán sondeos periódicos para comprobar si es necesario gestionar las retrollamadas, en lugar de que se activen explícitamente por otras CPU. Esto puede reducir la sobrecarga de interrupciones. | |
irqaffinity | 0,31,32,63 | Esta opción permite al kernel ejecutar las interrupciones en los núcleos de mantenimiento. |
idle | poll | Esto minimiza la latencia al salir del estado inactivo, pero a costa de mantener la CPU funcionando a toda velocidad en el subproceso inactivo. |
nmi_watchdog | 0 | Esta opción inhabilita únicamente el watchdog de NMI. Se puede omitir si se
ha definido |
nowatchdog | Esta opción inhabilita el watchdog de bloqueo suave, que se implementa como un temporizador que se ejecuta en el contexto de interrupción dura del temporizador. |
Los siguientes comandos modifican la configuración de GRUB y aplican los cambios mencionados anteriormente para que estén presentes en el próximo arranque:
Edite el archivo /etc/default/grub
con los parámetros
anteriores. El archivo tendrá este aspecto:
GRUB_CMDLINE_LINUX="BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll"
Actualice la configuración de GRUB:
$ transactional-update grub.cfg
$ reboot
Para comprobar que los parámetros se han aplicado después del rearranque, puede utilizar el siguiente comando para comprobar la línea de comandos del kernel:
$ cat /proc/cmdline
Puede usar otro guion para ajustar la configuración de la CPU, que básicamente realiza los siguientes pasos:
Definir el regulador de la CPU como
performance
.Desactivar la migración del temporizador a las CPU aisladas.
Migrar los subprocesos kdaemon a las CPU de mantenimiento.
Definir la latencia de las CPU aisladas en el valor más bajo posible.
Retrasar las actualizaciones de vmstat a 300 segundos.
El guion está disponible en el repositorio de ejemplos de SUSE Edge for Telco.
41.4 Configuración de la CNI #
41.4.1 Cilium #
Cilium
es el complemento de CNI predeterminado para SUSE
Edge for Telco. Para habilitar Cilium en el clúster RKE2 como complemento
predeterminado hay que configurar lo siguiente en el archivo
/etc/rancher/rke2/config.yaml
:
cni:
- cilium
Esto también se puede especificar con argumentos de línea de comandos, es
decir, con --cni=cilium
en la línea del servidor del
archivo /etc/systemd/system/rke2-server
.
Para usar el operador de red SR-IOV
descrito en la
siguiente sección (Sección 41.5, “SR-IOV”), use
Multus
con otro complemento de CNI, como
Cilium
o Calico
, como complemento
secundario.
cni:
- multus
- cilium
Para obtener más información sobre los complementos de CNI, visite Network Options (Opciones de red).
41.5 SR-IOV #
SR-IOV permite que un dispositivo, como un adaptador de red, divida el
acceso a sus recursos entre varias funciones de hardware
PCIe
. Hay diferentes formas de desplegar
SR-IOV
, y aquí mostramos dos:
Opción 1: usar los complementos de dispositivo de CNI
SR-IOV
y un mapa de configuración para configurarlo correctamente.Opción 2 (recomendada): usar el chart de Helm de
SR-IOV
en Rancher Prime para facilitar este despliegue.
Opción 1: Instalación de complementos de dispositivo de CNI SR-IOV y un mapa de configuración para configurarlo correctamente
Prepare el mapa de configuración para el complemento de dispositivo
Obtenga la información para rellenar el mapa de configuración desde el
comando lspci
:
$ lspci | grep -i acc
8a:00.0 Processing accelerators: Intel Corporation Device 0d5c
$ lspci | grep -i net
19:00.0 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
19:00.1 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
19:00.2 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
19:00.3 Ethernet controller: Broadcom Inc. and subsidiaries BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (rev 11)
51:00.0 Ethernet controller: Intel Corporation Ethernet Controller E810-C for QSFP (rev 02)
51:00.1 Ethernet controller: Intel Corporation Ethernet Controller E810-C for QSFP (rev 02)
51:01.0 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:01.1 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:01.2 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:01.3 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.0 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.1 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.2 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
51:11.3 Ethernet controller: Intel Corporation Ethernet Adaptive Virtual Function (rev 02)
El mapa de configuración es un archivo JSON
que describe
los dispositivos utilizando filtros para detectarlos, y crea grupos para las
interfaces. Lo importante es comprender qué son los filtros y los
grupos. Los filtros se usan para detectar los dispositivos y los grupos,
para crear las interfaces.
Es posible establecer filtros como:
vendorID:
8086
(Intel)deviceID:
0d5c
(tarjeta Accelerator)driver:
vfio-pci
(controlador)pfNames:
p2p1
(nombre de interfaz física)
También es posible definir filtros con una sintaxis de interfaz más compleja, por ejemplo:
pfNames:
["eth1#1,2,3,4,5,6"]
o[eth1#1-6]
(nombre de interfaz física)
Para los grupos, es posible crear un grupo para la tarjeta
FEC
y otro para la tarjeta Intel
, o
incluso crear un prefijo en función de nuestro caso de uso:
resourceName:
pci_sriov_net_bh_dpdk
resourcePrefix:
Rancher.io
Hay muchas combinaciones posibles para descubrir y crear el grupo de
recursos necesario para asignar funciones virtuales
a los
pods.
Para obtener más información sobre los filtros y los grupos, consulte sr-iov network device plug-in (Complemento de dispositivo de red sr-iov).
Después de configurar los filtros y los grupos que coincidan con las interfaces del hardware y el caso de uso, el mapa de configuración siguiente muestra un ejemplo útil:
apiVersion: v1
kind: ConfigMap
metadata:
name: sriovdp-config
namespace: kube-system
data:
config.json: |
{
"resourceList": [
{
"resourceName": "intel_fec_5g",
"devicetype": "accelerator",
"selectors": {
"vendors": ["8086"],
"devices": ["0d5d"]
}
},
{
"resourceName": "intel_sriov_odu",
"selectors": {
"vendors": ["8086"],
"devices": ["1889"],
"drivers": ["vfio-pci"],
"pfNames": ["p2p1"]
}
},
{
"resourceName": "intel_sriov_oru",
"selectors": {
"vendors": ["8086"],
"devices": ["1889"],
"drivers": ["vfio-pci"],
"pfNames": ["p2p2"]
}
}
]
}
Prepare el archivo
daemonset
para desplegar el complemento de dispositivo.
El complemento de dispositivo admite varias arquitecturas
(arm
, amd
o
ppc64le
), por lo que se puede usar el mismo archivo para
diferentes arquitecturas, desplegando un daemonset
para
cada arquitectura.
apiVersion: v1
kind: ServiceAccount
metadata:
name: sriov-device-plugin
namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-sriov-device-plugin-amd64
namespace: kube-system
labels:
tier: node
app: sriovdp
spec:
selector:
matchLabels:
name: sriov-device-plugin
template:
metadata:
labels:
name: sriov-device-plugin
tier: node
app: sriovdp
spec:
hostNetwork: true
nodeSelector:
kubernetes.io/arch: amd64
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
serviceAccountName: sriov-device-plugin
containers:
- name: kube-sriovdp
image: rancher/hardened-sriov-network-device-plugin:v3.7.0-build20240816
imagePullPolicy: IfNotPresent
args:
- --log-dir=sriovdp
- --log-level=10
securityContext:
privileged: true
resources:
requests:
cpu: "250m"
memory: "40Mi"
limits:
cpu: 1
memory: "200Mi"
volumeMounts:
- name: devicesock
mountPath: /var/lib/kubelet/
readOnly: false
- name: log
mountPath: /var/log
- name: config-volume
mountPath: /etc/pcidp
- name: device-info
mountPath: /var/run/k8s.cni.cncf.io/devinfo/dp
volumes:
- name: devicesock
hostPath:
path: /var/lib/kubelet/
- name: log
hostPath:
path: /var/log
- name: device-info
hostPath:
path: /var/run/k8s.cni.cncf.io/devinfo/dp
type: DirectoryOrCreate
- name: config-volume
configMap:
name: sriovdp-config
items:
- key: config.json
path: config.json
Después de aplicar el mapa de configuración y el
daemonset
, se desplegará el complemento de dispositivo y se detectarán las interfaces, que estarán disponibles para los pods.$ kubectl get pods -n kube-system | grep sriov kube-system kube-sriov-device-plugin-amd64-twjfl 1/1 Running 0 2m
Compruebe qué interfaces se han detectado y están disponibles en los nodos para los pods:
$ kubectl get $(kubectl get nodes -oname) -o jsonpath='{.status.allocatable}' | jq { "cpu": "64", "ephemeral-storage": "256196109726", "hugepages-1Gi": "40Gi", "hugepages-2Mi": "0", "intel.com/intel_fec_5g": "1", "intel.com/intel_sriov_odu": "4", "intel.com/intel_sriov_oru": "4", "memory": "221396384Ki", "pods": "110" }
La tarjeta
FEC
esintel.com/intel_fec_5g
y su valor es 1.La función virtual
VF
esintel.com/intel_sriov_odu
ointel.com/intel_sriov_oru
si la despliega con un complemento de dispositivo y el mapa de configuración sin charts de Helm.
Si no hay interfaces, no tiene mucho sentido continuar, ya que la interfaz no estará disponible para los pods. Revise primero el mapa de configuración y los filtros para resolver el problema.
Opción 2 (recomendada): instalación con Rancher mediante el chart de Helm para la CNI SR-IOV y los complementos de dispositivo
Consiga Helm si no está presente:
$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Instale SR-IOV.
helm install sriov-crd oci://registry.suse.com/edge/charts/sriov-crd -n sriov-network-operator
helm install sriov-network-operator oci://registry.suse.com/edge/charts/sriov-network-operator -n sriov-network-operator
Compruebe los crd y los pods de los recursos desplegados:
$ kubectl get crd
$ kubectl -n sriov-network-operator get pods
Compruebe la etiqueta de los nodos.
Con todos los recursos en ejecución, la etiqueta aparece automáticamente en su nodo:
$ kubectl get nodes -oyaml | grep feature.node.kubernetes.io/network-sriov.capable
feature.node.kubernetes.io/network-sriov.capable: "true"
Revise el
daemonset
para comprobar si las entradassriov-network-config-daemon
ysriov-rancher-nfd-worker
nuevas están activas y listas:
$ kubectl get daemonset -A
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
calico-system calico-node 1 1 1 1 1 kubernetes.io/os=linux 15h
sriov-network-operator sriov-network-config-daemon 1 1 1 1 1 feature.node.kubernetes.io/network-sriov.capable=true 45m
sriov-network-operator sriov-rancher-nfd-worker 1 1 1 1 1 <none> 45m
kube-system rke2-ingress-nginx-controller 1 1 1 1 1 kubernetes.io/os=linux 15h
kube-system rke2-multus-ds 1 1 1 1 1 kubernetes.io/arch=amd64,kubernetes.io/os=linux 15h
En unos minutos (la actualización puede tardar hasta 10 minutos), los nodos
se detectan y se configuran capacidad de SR-IOV
:
$ kubectl get sriovnetworknodestates.sriovnetwork.openshift.io -A
NAMESPACE NAME AGE
sriov-network-operator xr11-2 83s
Compruebe las interfaces detectadas.
Las interfaces detectadas deben ser la dirección PCI del dispositivo de
red. Compruebe esta información con el comando lspci
en
el host.
$ kubectl get sriovnetworknodestates.sriovnetwork.openshift.io -n kube-system -oyaml
apiVersion: v1
items:
- apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetworkNodeState
metadata:
creationTimestamp: "2023-06-07T09:52:37Z"
generation: 1
name: xr11-2
namespace: sriov-network-operator
ownerReferences:
- apiVersion: sriovnetwork.openshift.io/v1
blockOwnerDeletion: true
controller: true
kind: SriovNetworkNodePolicy
name: default
uid: 80b72499-e26b-4072-a75c-f9a6218ec357
resourceVersion: "356603"
uid: e1f1654b-92b3-44d9-9f87-2571792cc1ad
spec:
dpConfigVersion: "356507"
status:
interfaces:
- deviceID: "1592"
driver: ice
eSwitchMode: legacy
linkType: ETH
mac: 40:a6:b7:9b:35:f0
mtu: 1500
name: p2p1
pciAddress: "0000:51:00.0"
totalvfs: 128
vendor: "8086"
- deviceID: "1592"
driver: ice
eSwitchMode: legacy
linkType: ETH
mac: 40:a6:b7:9b:35:f1
mtu: 1500
name: p2p2
pciAddress: "0000:51:00.1"
totalvfs: 128
vendor: "8086"
syncStatus: Succeeded
kind: List
metadata:
resourceVersion: ""
Si su interfaz no se detecta, asegúrese de que esté presente en el siguiente mapa de configuración:
$ kubectl get cm supported-nic-ids -oyaml -n sriov-network-operator
Si su dispositivo no aparece, edite el mapa de configuración y añada los
valores correctos que se deban detectar (puede que sea necesario reiniciar
el daemonset sriov-network-config-daemon
).
Cree la directiva
NetworkNodePolicy
para configurar lasfunciones virtuales
.
Se crearán algunas funciones virtuales
(numVfs
) desde el dispositivo
(rootDevices
) y se configurarán con el controlador
deviceType
y el MTU
:
El campo resourceName
no debe contener caracteres
especiales y debe ser único en todo el clúster. En el ejemplo se usa
deviceType: vfio-pci
porque dpdk
se
usará junto a sr-iov
. Si no utiliza
dpdk
, el valor de deviceType debe ser
deviceType: netdevice
(valor predeterminado).
apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetworkNodePolicy
metadata:
name: policy-dpdk
namespace: sriov-network-operator
spec:
nodeSelector:
feature.node.kubernetes.io/network-sriov.capable: "true"
resourceName: intelnicsDpdk
deviceType: vfio-pci
numVfs: 8
mtu: 1500
nicSelector:
deviceID: "1592"
vendor: "8086"
rootDevices:
- 0000:51:00.0
Valide las configuraciones:
$ kubectl get $(kubectl get nodes -oname) -o jsonpath='{.status.allocatable}' | jq
{
"cpu": "64",
"ephemeral-storage": "256196109726",
"hugepages-1Gi": "60Gi",
"hugepages-2Mi": "0",
"intel.com/intel_fec_5g": "1",
"memory": "200424836Ki",
"pods": "110",
"rancher.io/intelnicsDpdk": "8"
}
Cree la red sr-iov (opcional, si se necesita una red diferente):
apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetwork
metadata:
name: network-dpdk
namespace: sriov-network-operator
spec:
ipam: |
{
"type": "host-local",
"subnet": "192.168.0.0/24",
"rangeStart": "192.168.0.20",
"rangeEnd": "192.168.0.60",
"routes": [{
"dst": "0.0.0.0/0"
}],
"gateway": "192.168.0.1"
}
vlan: 500
resourceName: intelnicsDpdk
Compruebe la red creada:
$ kubectl get network-attachment-definitions.k8s.cni.cncf.io -A -oyaml
apiVersion: v1
items:
- apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
annotations:
k8s.v1.cni.cncf.io/resourceName: rancher.io/intelnicsDpdk
creationTimestamp: "2023-06-08T11:22:27Z"
generation: 1
name: network-dpdk
namespace: sriov-network-operator
resourceVersion: "13124"
uid: df7c89f5-177c-4f30-ae72-7aef3294fb15
spec:
config: '{ "cniVersion":"0.4.0", "name":"network-dpdk","type":"sriov","vlan":500,"vlanQoS":0,"ipam":{"type":"host-local","subnet":"192.168.0.0/24","rangeStart":"192.168.0.10","rangeEnd":"192.168.0.60","routes":[{"dst":"0.0.0.0/0"}],"gateway":"192.168.0.1"}
}'
kind: List
metadata:
resourceVersion: ""
41.6 DPDK #
DPDK
(Data Plane Development Kit, kit de desarrollo del
plano de datos) es un conjunto de bibliotecas y controladores para el
procesamiento rápido de paquetes. Se utiliza para acelerar las cargas de
trabajo de procesamiento de paquetes que se ejecutan en una amplia variedad
de arquitecturas de CPU. DPDK incluye bibliotecas de plano de datos y
controladores de controlador de interfaz de red (NIC
)
optimizados para lo siguiente:
Un gestor de colas implementa colas sin bloqueo.
Un gestor de búferes preasigna búferes de tamaño fijo.
Un gestor de memoria asigna pools de objetos en la memoria y usa un anillo para almacenar los objetos libres; esto garantiza que los objetos se distribuyan de forma equitativa en todos los canales
DRAM
.Los controladores en modo de sondeo (Poll mode drivers,
PMD
) están diseñados para funcionar sin notificaciones asíncronas, lo que reduce la sobrecarga.Un marco de paquetes como un conjunto de bibliotecas que sirven de ayuda para desarrollar el procesamiento de paquetes.
Los siguientes pasos muestran cómo habilitar DPDK
y cómo
crear funciones virtuales
a partir de las
NIC
que se utilizarán en las interfaces de
DPDK
:
Instale el paquete de
DPDK
:
$ transactional-update pkg install dpdk dpdk-tools libdpdk-23
$ reboot
Parámetros del kernel:
Para usar DPDK, emplee algunos controladores para habilitar ciertos parámetros en el kernel:
Parámetro | Valor | Descripción |
---|---|---|
iommu | pt | Esta opción permite el uso del controlador |
intel_iommu o amd_iommu | on | Esta opción permite el uso de |
Para habilitar los parámetros, añádalos al archivo
/etc/default/grub
:
GRUB_CMDLINE_LINUX="BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll"
Actualice la configuración de GRUB y rearranque el sistema para aplicar los cambios:
$ transactional-update grub.cfg
$ reboot
Cargue el módulo del kernel
vfio-pci
y habiliteSR-IOV
en las tarjetasNIC
:
$ modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
Cree algunas funciones virtuales (
VF
) a partir de las tarjetasNIC
.
Para crear funciones virtuales
, por ejemplo, para dos
NIC
distintas, se requieren los siguientes comandos:
$ echo 4 > /sys/bus/pci/devices/0000:51:00.0/sriov_numvfs
$ echo 4 > /sys/bus/pci/devices/0000:51:00.1/sriov_numvfs
Vincule las nuevas funciones virtuales con el controlador
vfio-pci
:
$ dpdk-devbind.py -b vfio-pci 0000:51:01.0 0000:51:01.1 0000:51:01.2 0000:51:01.3 \
0000:51:11.0 0000:51:11.1 0000:51:11.2 0000:51:11.3
Compruebe que la configuración se haya aplicado correctamente:
$ dpdk-devbind.py -s
Network devices using DPDK-compatible driver
============================================
0000:51:01.0 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.1 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.2 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.3 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:01.0 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:11.1 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:21.2 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
0000:51:31.3 'Ethernet Adaptive Virtual Function 1889' drv=vfio-pci unused=iavf,igb_uio
Network devices using kernel driver
===================================
0000:19:00.0 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em1 drv=bnxt_en unused=igb_uio,vfio-pci *Active*
0000:19:00.1 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em2 drv=bnxt_en unused=igb_uio,vfio-pci
0000:19:00.2 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em3 drv=bnxt_en unused=igb_uio,vfio-pci
0000:19:00.3 'BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1751' if=em4 drv=bnxt_en unused=igb_uio,vfio-pci
0000:51:00.0 'Ethernet Controller E810-C for QSFP 1592' if=eth13 drv=ice unused=igb_uio,vfio-pci
0000:51:00.1 'Ethernet Controller E810-C for QSFP 1592' if=rename8 drv=ice unused=igb_uio,vfio-pci
41.7 Aceleración vRAN (Intel ACC100/ACC200
) #
A medida que los proveedores de servicios de comunicaciones pasan de las
redes 4G a las 5G, muchos están adoptando arquitecturas de redes de acceso
por radio virtualizadas (vRAN
) para obtener una mayor
capacidad de canal y facilitar el despliegue de servicios y aplicaciones
basados en la periferia. Las soluciones vRAN son perfectas para ofrecer
servicios de baja latencia con la flexibilidad de aumentar o disminuir la
capacidad en función del volumen de tráfico en tiempo real y la demanda de
la red.
Una de las cargas de trabajo de 4G y 5G que más recursos informáticos
consume es la FEC
de la capa 1 (L1
) de
la RAN, que resuelve los errores de transmisión de datos en canales de
comunicación poco fiables o con ruido. La tecnología FEC
detecta y corrige un número limitado de errores en los datos 4G o 5G, lo que
elimina la necesidad de retransmisión. Dado que la transacción de
aceleración de FEC
no contiene información sobre el
estado de las celdas, se puede virtualizar fácilmente, de forma que se puede
aprovechar la agrupación y facilitar la migración de celdas.
Parámetros del kernel
Para habilitar la aceleración vRAN
, es preciso habilitar
los siguientes parámetros del kernel (si aún no están presentes):
Parámetro | Valor | Descripción |
---|---|---|
iommu | pt | Esta opción permite el uso de vfio para las interfaces DPDK. |
intel_iommu o amd_iommu | on | Esta opción permite el uso de vfio para las funciones virtuales. |
Modifique el archivo GRUB /etc/default/grub
para
añadirlos a la línea de comandos del kernel:
GRUB_CMDLINE_LINUX="BOOT_IMAGE=/boot/vmlinuz-6.4.0-9-rt root=UUID=77b713de-5cc7-4d4c-8fc6-f5eca0a43cf9 skew_tick=1 rd.timeout=60 rd.retry=45 console=ttyS1,115200 console=tty0 default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0 ignition.platform.id=openstack intel_iommu=on iommu=pt irqaffinity=0,31,32,63 isolcpus=domain,nohz,managed_irq,1-30,33-62 nohz_full=1-30,33-62 nohz=on mce=off net.ifnames=0 nosoftlockup nowatchdog nmi_watchdog=0 quiet rcu_nocb_poll rcu_nocbs=1-30,33-62 rcupdate.rcu_cpu_stall_suppress=1 rcupdate.rcu_expedited=1 rcupdate.rcu_normal_after_boot=1 rcupdate.rcu_task_stall_timeout=0 rcutree.kthread_prio=99 security=selinux selinux=1 idle=poll"
Actualice la configuración de GRUB y rearranque el sistema para aplicar los cambios:
$ transactional-update grub.cfg
$ reboot
Para verificar que los parámetros se han aplicado después del rearranque, compruebe la línea de comandos:
$ cat /proc/cmdline
Cargue los módulos del kernel vfio-pci para habilitar la aceleración
vRAN
:
$ modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
Obtenga información de la interfaz Acc100:
$ lspci | grep -i acc
8a:00.0 Processing accelerators: Intel Corporation Device 0d5c
Vincule la interfaz física (
PF
) con el controladorvfio-pci
:
$ dpdk-devbind.py -b vfio-pci 0000:8a:00.0
Cree las funciones virtuales (
VF
) a partir de la interfaz física (PF
).
Cree dos VF
desde la PF
y vincúlelas
con vfio-pci
así:
$ echo 2 > /sys/bus/pci/devices/0000:8a:00.0/sriov_numvfs
$ dpdk-devbind.py -b vfio-pci 0000:8b:00.0
Configure acc100 con el archivo de configuración propuesto:
$ pf_bb_config ACC100 -c /opt/pf-bb-config/acc100_config_vf_5g.cfg
Tue Jun 6 10:49:20 2023:INFO:Queue Groups: 2 5GUL, 2 5GDL, 2 4GUL, 2 4GDL
Tue Jun 6 10:49:20 2023:INFO:Configuration in VF mode
Tue Jun 6 10:49:21 2023:INFO: ROM version MM 99AD92
Tue Jun 6 10:49:21 2023:WARN:* Note: Not on DDR PRQ version 1302020 != 10092020
Tue Jun 6 10:49:21 2023:INFO:PF ACC100 configuration complete
Tue Jun 6 10:49:21 2023:INFO:ACC100 PF [0000:8a:00.0] configuration complete!
Compruebe las nuevas funciones virtuales creadas desde la interfaz física FEC:
$ dpdk-devbind.py -s
Baseband devices using DPDK-compatible driver
=============================================
0000:8a:00.0 'Device 0d5c' drv=vfio-pci unused=
0000:8b:00.0 'Device 0d5d' drv=vfio-pci unused=
Other Baseband devices
======================
0000:8b:00.1 'Device 0d5d' unused=
41.8 Páginas enormes #
Cuando un proceso utiliza RAM
, la CPU
lo marca como utilizado por ese proceso. Por motivos de eficiencia, la
CPU
asigna RAM
en bloques de
4K
bytes, que es el valor predeterminado en muchas
plataformas. Esos bloques se denominan páginas. Las páginas se pueden
intercambiar en el disco, etc.
Dado que el espacio de direcciones del proceso es virtual, la
CPU
y el sistema operativo deben recordar qué páginas
pertenecen a cada proceso y dónde se almacena cada página. Cuanto más
páginas haya, más tiempo llevará la búsqueda de asignación de
memoria. Cuando un proceso usa 1 GB
de memoria, eso
supone 262 144 entradas que buscar (1 GB
/ 4
K
). Si una entrada de la tabla de páginas consume 8 bytes, eso
supone 2 MB
(262 144 * 8) que buscar.
La mayoría de las arquitecturas actuales de CPU
admiten
páginas más grandes que las predeterminadas, lo que reduce el número de
entradas que la CPU/SO
debe buscar.
Parámetros del kernel
Para habilitar estas páginas enormes (huge pages), debemos añadir los siguientes parámetros del kernel. En este ejemplo, configuramos 40 páginas de 1 GB, aunque el tamaño de la página enorme y el número exacto de ellas deben adaptarse a los requisitos de memoria de su aplicación:
Parámetro | Valor | Descripción |
---|---|---|
hugepagesz | 1G | Esta opción permite establecer el tamaño de las páginas enormes en 1 G |
hugepages | 40 | Este es el número de páginas enormes definidas anteriormente |
default_hugepagesz | 1G | Este es el valor predeterminado para obtener las páginas enormes |
Modifique el archivo GRUB /etc/default/grub
para añadir
estos parámetros en GRUB_CMDLINE_LINUX
:
default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0
Actualice la configuración de GRUB y rearranque el sistema para aplicar los cambios:
$ transactional-update grub.cfg
$ reboot
Para comprobar que los parámetros se han aplicado después del rearranque, puede consultar la línea de comandos:
$ cat /proc/cmdline
Uso de páginas enormes
Para usar las páginas enormes, debe montarlas:
$ mkdir -p /hugepages
$ mount -t hugetlbfs nodev /hugepages
Despliegue una carga de trabajo de Kubernetes creando los recursos y los volúmenes:
...
resources:
requests:
memory: "24Gi"
hugepages-1Gi: 16Gi
intel.com/intel_sriov_oru: '4'
limits:
memory: "24Gi"
hugepages-1Gi: 16Gi
intel.com/intel_sriov_oru: '4'
...
...
volumeMounts:
- name: hugepage
mountPath: /hugepages
...
volumes:
- name: hugepage
emptyDir:
medium: HugePages
...
41.9 Fijación de CPU en Kubernetes #
41.9.1 Requisito previo #
Debe tener la CPU
ajustada al perfil de rendimiento
descrito en esta sección (Sección 41.3, “Fijación de CPU mediante Tuned y argumentos del kernel”).
41.9.2 Configuración de Kubernetes para la fijación de CPU #
Configure los argumentos de kubelet para implementar la gestión de la CPU en
el clúster RKE2
. Añada el siguiente bloque de
configuración, como se muestra en el ejemplo siguiente, al archivo
/etc/rancher/rke2/config.yaml
. Asegúrese de especificar
los núcleos de CPU de mantenimiento en los argumentos
kubelet-reserved
y system-reserved
:
kubelet-arg:
- "cpu-manager-policy=static"
- "cpu-manager-policy-options=full-pcpus-only=true"
- "cpu-manager-reconcile-period=0s"
- "kubelet-reserved=cpu=0,31,32,63"
- "system-reserved=cpu=0,31,32,63"
41.9.3 Aprovechamiento de CPU fijadas para cargas de trabajo #
Hay tres formas de utilizar esa función utilizando la directiva
estática
definida en kubelet, dependiendo de las solicitudes y los
límites que defina en su carga de trabajo:
Clase de calidad de servicio
BestEffort
: si no se define ninguna solicitud o límite para laCPU
, el pod se programa en la primeraCPU
disponible en el sistema.Este es un ejemplo de uso de la clase de calidad de servicio
BestEffort
:spec: containers: - name: nginx image: nginx
Clase de calidad de servicio
Burstable
: si se define una solicitud para la CPU que no se ajusta a los límites establecidos, o si no hay ninguna solicitud de CPU.Ejemplos de uso de la clase de calidad de servicio
Burstable
:spec: containers: - name: nginx image: nginx resources: limits: memory: "200Mi" requests: memory: "100Mi"
o
spec: containers: - name: nginx image: nginx resources: limits: memory: "200Mi" cpu: "2" requests: memory: "100Mi" cpu: "1"
Clase de calidad de servicio
Guaranteed
: si define una solicitud de CPU que es igual a los límites.Ejemplo de uso de la clase de calidad de servicio
Guaranteed
:spec: containers: - name: nginx image: nginx resources: limits: memory: "200Mi" cpu: "2" requests: memory: "200Mi" cpu: "2"
41.10 Programación compatible con NUMA #
El acceso a la memoria no uniforme o arquitectura de memoria no uniforme
(NUMA
) es un diseño de memoria física utilizado en la
arquitectura SMP
(multiprocesadores) en la que el tiempo
de acceso a la memoria depende de la ubicación de la memoria con respecto al
procesador. En NUMA
, un procesador puede acceder a su
propia memoria local más rápido que a la memoria no local; es decir, la
memoria local de otro procesador o la memoria compartida entre procesadores.
41.10.1 Identificación de nodos NUMA #
Para identificar los nodos NUMA
, utilice el siguiente
comando en su sistema:
$ lscpu | grep NUMA
NUMA node(s): 1
NUMA node0 CPU(s): 0-63
En este ejemplo, solo tenemos un nodo NUMA
que muestra 64
CPU
.
NUMA
debe estar habilitado en el
BIOS
. Si dmesg
no tiene registros de
la inicialización de NUMA durante el arranque, es posible que los mensajes
relacionados con NUMA
del búfer del anillo del kernel se
hayan sobrescrito.
41.11 MetalLB #
MetalLB
es una implementación de equilibrador de carga
para clústeres bare metal de Kubernetes que utiliza protocolos de
enrutamiento estándar como L2
y BGP
como protocolos de anuncios. Se trata de un equilibrador de carga de red que
se puede utilizar para exponer servicios de un clúster de Kubernetes al
mundo exterior que necesite utilizar el tipo de servicios de Kubernetes
LoadBalancer
con bare metal.
Para habilitar MetalLB
en el clúster
RKE2
, se deben seguir estos pasos:
Instale
MetalLB
con este comando:
$ kubectl apply <<EOF -f
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: metallb
namespace: kube-system
spec:
chart: oci://registry.suse.com/edge/charts/metallb
targetNamespace: metallb-system
version: 303.0.0+up0.14.9
createNamespace: true
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: endpoint-copier-operator
namespace: kube-system
spec:
chart: oci://registry.suse.com/edge/charts/endpoint-copier-operator
targetNamespace: endpoint-copier-operator
version: 303.0.0+up0.2.1
createNamespace: true
EOF
Cree la configuración
IpAddressPool
yL2advertisement
:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: kubernetes-vip-ip-pool
namespace: metallb-system
spec:
addresses:
- 10.168.200.98/32
serviceAllocation:
priority: 100
namespaces:
- default
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: ip-pool-l2-adv
namespace: metallb-system
spec:
ipAddressPools:
- kubernetes-vip-ip-pool
Cree el servicio de punto final para exponer la
IP virtual
:
apiVersion: v1
kind: Service
metadata:
name: kubernetes-vip
namespace: default
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: rke2-api
port: 9345
protocol: TCP
targetPort: 9345
- name: k8s-api
port: 6443
protocol: TCP
targetPort: 6443
sessionAffinity: None
type: LoadBalancer
Compruebe que se ha creado la
IP virtual
y que los pods deMetalLB
se están ejecutando:
$ kubectl get svc -n default
$ kubectl get pods -n default
41.12 Configuración del registro privado #
Es posible configurar Containerd
para que se conecte a
registros privados y los use para extraer imágenes privadas en cada nodo.
Durante el inicio, RKE2
comprueba si existe un archivo
registries.yaml
en /etc/rancher/rke2/
y ordena a containerd
que use cualquier registro definido
en el archivo. Si desea utilizar un registro privado, cree este archivo como
usuario root en cada nodo que vaya a utilizar el registro.
Para añadir el registro privado, cree el archivo
/etc/rancher/rke2/registries.yaml
con el siguiente
contenido:
mirrors:
docker.io:
endpoint:
- "https://registry.example.com:5000"
configs:
"registry.example.com:5000":
auth:
username: xxxxxx # this is the registry username
password: xxxxxx # this is the registry password
tls:
cert_file: # path to the cert file used to authenticate to the registry
key_file: # path to the key file for the certificate used to authenticate to the registry
ca_file: # path to the ca file used to verify the registry's certificate
insecure_skip_verify: # may be set to true to skip verifying the registry's certificate
o sin autenticación:
mirrors:
docker.io:
endpoint:
- "https://registry.example.com:5000"
configs:
"registry.example.com:5000":
tls:
cert_file: # path to the cert file used to authenticate to the registry
key_file: # path to the key file for the certificate used to authenticate to the registry
ca_file: # path to the ca file used to verify the registry's certificate
insecure_skip_verify: # may be set to true to skip verifying the registry's certificate
Para que los cambios en el registro surtan efecto, debe configurar este archivo antes de iniciar RKE2 en el nodo, o bien reiniciar RKE2 en cada nodo configurado.
Para obtener más información, consulte containerd registry configuration rke2 (Configuración del registro containerd en RKE2).
41.13 Protocolo de tiempo de precisión (PTP) #
El protocolo de tiempo de precisión (PTP) es un protocolo de red desarrollado por el IEEE (Instituto de Ingenieros Eléctricos y Electrónicos) para permitir la sincronización del tiempo en submicrosegundos en una red informática. Desde su creación y durante las últimas dos décadas, el PTP se ha utilizado en muchos sectores. Recientemente, se ha observado un aumento de su adopción en las redes de telecomunicaciones como elemento fundamental para las redes 5G. Aunque se trata de un protocolo relativamente sencillo, su configuración puede variar significativamente en función de la aplicación. Por ese motivo, se han definido y estandarizado múltiples perfiles.
En esta sección solo se tratan los perfiles específicos de telecomunicaciones. Por lo tanto, se dará por sentado que la NIC cuenta con capacidad de marcación de tiempo y con un reloj de hardware PTP (PHC). Hoy en día, todos los adaptadores de red para telecomunicaciones incluyen compatibilidad con PTP en el hardware, pero puede verificarlo con el siguiente comando:
# ethtool -T p1p1
Time stamping parameters for p1p1:
Capabilities:
hardware-transmit
software-transmit
hardware-receive
software-receive
software-system-clock
hardware-raw-clock
PTP Hardware Clock: 0
Hardware Transmit Timestamp Modes:
off
on
Hardware Receive Filter Modes:
none
all
Sustituya p1p1
por el nombre de la interfaz que se
utilizará para PTP.
Las siguientes secciones explican cómo instalar y configurar PTP en SUSE Edge específicamente, pero se espera que el usuario esté familiarizado con los conceptos básicos de PTP. Para obtener una breve descripción general de PTP y la implementación incluida en SUSE Edge for Telco, consulte https://documentation.suse.com/sles/html/SLES-all/cha-tuning-ptp.html.
41.13.1 Instalación de los componentes de software de PTP #
En SUSE Edge for Telco, la implementación de PTP la proporciona el paquete
linuxptp
, que incluye dos componentes:
ptp4l
: un daemon que controla el PHC en la NIC y ejecuta el protocolo PTPphc2sys
: un daemon que mantiene el reloj del sistema sincronizado con el PHC sincronizado por PTP en la NIC
Ambos daemons son necesarios para que la sincronización del sistema funcione correctamente y deben estar configurados adecuadamente según su configuración. Esto se explica en la Sección 41.13.2, “Configuración de PTP para despliegues de telecomunicaciones”.
La mejor manera, y la más fácil, de integrar PTP en su clúster descendente
es añadir el paquete linuxptp
en
packageList
en el archivo de definición de Edge Image
Builder (EIB). De esta forma, el software del plano de control de PTP se
instalará automáticamente durante el aprovisionamiento del clúster. Consulte
la documentación de EIB (Sección 3.3.4, “Configuración de paquetes RPM”)
para obtener más información sobre la instalación de paquetes.
Esto es un ejemplo de manifiesto de EIB con linuxptp
:
apiVersion: 1.0
image:
imageType: RAW
arch: x86_64
baseImage: {micro-base-rt-image-raw}
outputImageName: eibimage-slmicrort-telco.raw
operatingSystem:
time:
timezone: America/New_York
kernelArgs:
- ignition.platform.id=openstack
- net.ifnames=1
systemd:
disable:
- rebootmgr
- transactional-update.timer
- transactional-update-cleanup.timer
- fstrim
- time-sync.target
enable:
- ptp4l
- phc2sys
users:
- username: root
encryptedPassword: ${ROOT_PASSWORD}
packages:
packageList:
- jq
- dpdk
- dpdk-tools
- libdpdk-23
- pf-bb-config
- open-iscsi
- tuned
- cpupower
- linuxptp
sccRegistrationCode: ${SCC_REGISTRATION_CODE}
El paquete linuxptp
incluido en SUSE Edge for Telco no
habilita ptp4l
ni phc2sys
de forma
predeterminada. Si sus archivos de configuración específicos del sistema se
despliegan en el momento del aprovisionamiento (consulte la Sección 41.13.3, “Integración de Cluster API”), deben habilitarse. Para ello, añádalos a la sección
systemd
del manifiesto, como en el ejemplo anterior.
Siga el proceso habitual para crear la imagen que se describe en la documentación de EIB (Sección 3.4, “Creación de la imagen”) y utilícela para desplegar su clúster. Si no tiene experiencia con EIB, comience por el Capítulo 11, Edge Image Builder.
41.13.2 Configuración de PTP para despliegues de telecomunicaciones #
Muchas aplicaciones de telecomunicaciones requieren una sincronización
estricta de fase y tiempo con poca desviación. Por eso, se definieron dos
perfiles orientados a las telecomunicaciones: el ITU-T G.8275.1 y el ITU-T
G.8275.2. Ambos tienen una alta tasa de mensajes de sincronización y otras
características distintivas, como el uso de un algoritmo de reloj maestro
óptimo (BMCA) alternativo. Este comportamiento exige ajustes específicos en
el archivo de configuración utilizado por ptp4l
, que se
proporcionan en las siguientes secciones como referencia.
Ambas secciones solo cubren el caso de un reloj normal con una configuración de recepción de hora.
Los perfiles de este tipo deben utilizarse en una infraestructura PTP bien planificada.
Es posible que su red PTP específica requiera ajustes de configuración adicionales. Asegúrese de revisar y adaptar los ejemplos proporcionados si es necesario.
41.13.2.1 Perfil ITU-T G.8275.1 de PTP #
El perfil G.8275.1 tiene las siguientes especificaciones:
Se ejecuta directamente en Ethernet y requiere soporte de red completo (los nodos/conmutadores adyacentes deben ser compatibles con PTP).
La configuración predeterminada del dominio es 24.
La comparación de conjuntos de datos se basa en el algoritmo G.8275.x y sus valores
localPriority
después depriority2
.
Copie el siguiente contenido en un archivo llamado
/etc/ptp4l-G.8275.1.conf
:
# Telecom G.8275.1 example configuration [global] domainNumber 24 priority2 255 dataset_comparison G.8275.x G.8275.portDS.localPriority 128 G.8275.defaultDS.localPriority 128 maxStepsRemoved 255 logAnnounceInterval -3 logSyncInterval -4 logMinDelayReqInterval -4 announceReceiptTimeout 3 serverOnly 0 ptp_dst_mac 01:80:C2:00:00:0E network_transport L2
Una vez creado el archivo, debe hacerse referencia a él en
/etc/sysconfig/ptp4l
para que el daemon se inicie
correctamente. Puede hacerlo cambiando la línea OPTIONS=
por:
OPTIONS="-f /etc/ptp4l-G.8275.1.conf -i $IFNAME --message_tag ptp-8275.1"
En concreto:
-f
requiere el nombre del archivo de configuración que se va a utilizar; en este caso,/etc/ptp4l-G.8275.1.conf
.-i
requiere el nombre de la interfaz que se va a utilizar. Sustituya$IFNAME
por el nombre real de la interfaz.--message_tag
permite identificar mejor la salida de ptp4l en los registros del sistema y es opcional.
Una vez completados los pasos anteriores, se debe (re)iniciar el daemon
ptp4l
:
# systemctl restart ptp4l
Compruebe el estado de sincronización observando los registros con:
# journalctl -e -u ptp4l
41.13.2.2 Perfil ITU-T G.8275.2 de PTP #
El perfil G.8275.2 tiene las siguientes especificaciones:
Funciona con IP y no requiere soporte de red completo (los nodos/conmutadores adyacentes pueden no ser compatibles con PTP).
La configuración predeterminada del dominio es 44.
La comparación de conjuntos de datos se basa en el algoritmo G.8275.x y sus valores
localPriority
después depriority2
.
Copie el siguiente contenido en un archivo llamado
/etc/ptp4l-G.8275.2.conf
:
# Telecom G.8275.2 example configuration [global] domainNumber 44 priority2 255 dataset_comparison G.8275.x G.8275.portDS.localPriority 128 G.8275.defaultDS.localPriority 128 maxStepsRemoved 255 logAnnounceInterval 0 serverOnly 0 hybrid_e2e 1 inhibit_multicast_service 1 unicast_listen 1 unicast_req_duration 60 logSyncInterval -5 logMinDelayReqInterval -4 announceReceiptTimeout 2 # # Customize the following for slave operation: # [unicast_master_table] table_id 1 logQueryInterval 2 UDPv4 $PEER_IP_ADDRESS [$IFNAME] unicast_master_table 1
Asegúrese de sustituir los siguientes marcadores de posición:
$PEER_IP_ADDRESS
: la dirección IP del siguiente nodo PTP con el que se va a comunicar, como el reloj maestro o el reloj fronterizo que proporcionará la sincronización.$IFNAME
: indica aptp4l
qué interfaz debe utilizar para PTP.
Una vez creado el archivo, debe referenciarse en
/etc/sysconfig/ptp4l
junto con el nombre de la interfaz
que se utilizará para PTP para que el daemon se inicie correctamente. Puede
hacerlo cambiando la línea OPTIONS=
por:
OPTIONS="-f /etc/ptp4l-G.8275.2.conf --message_tag ptp-8275.2"
En concreto:
-f
requiere el nombre del archivo de configuración que se va a utilizar. En este caso, es/etc/ptp4l-G.8275.2.conf
.--message_tag
permite identificar mejor la salida de ptp4l en los registros del sistema y es opcional.
Una vez completados los pasos anteriores, se debe (re)iniciar el daemon
ptp4l
:
# systemctl restart ptp4l
Compruebe el estado de sincronización observando los registros con:
# journalctl -e -u ptp4l
41.13.2.3 Configuración de phc2sys #
Aunque no es obligatorio, se recomienda completar totalmente la
configuración de ptp4l
antes de pasar a
phc2sys
. phc2sys
no requiere un
archivo de configuración y sus parámetros de ejecución se pueden controlar
únicamente a través de la variable OPTIONS=
presente en
/etc/sysconfig/ptp4l
, de forma similar a
ptp4l
:
OPTIONS="-s $IFNAME -w"
Donde $IFNAME
es el nombre de la interfaz ya configurada
en ptp4l que se utilizará como fuente para el reloj del sistema. Esto se
utiliza para identificar la fuente de PHC.
41.13.3 Integración de Cluster API #
Cada vez que se despliega un clúster mediante un clúster de gestión y un
aprovisionamiento de red dirigido, tanto el archivo de configuración como
las dos variables de configuración de /etc/sysconfig
se
pueden desplegar en el host en el momento del aprovisionamiento. A
continuación, se muestra un extracto de una definición de clúster, centrado
en un objeto RKE2ControlPlane
modificado que despliega el
mismo archivo de configuración G.8275.1 en todos los hosts:
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: RKE2ControlPlane
metadata:
name: single-node-cluster
namespace: default
spec:
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: Metal3MachineTemplate
name: single-node-cluster-controlplane
replicas: 1
version: ${RKE2_VERSION}
rolloutStrategy:
type: "RollingUpdate"
rollingUpdate:
maxSurge: 0
registrationMethod: "control-plane-endpoint"
serverConfig:
cni: canal
agentConfig:
format: ignition
cisProfile: cis
additionalUserData:
config: |
variant: fcos
version: 1.4.0
systemd:
units:
- name: rke2-preinstall.service
enabled: true
contents: |
[Unit]
Description=rke2-preinstall
Wants=network-online.target
Before=rke2-install.service
ConditionPathExists=!/run/cluster-api/bootstrap-success.complete
[Service]
Type=oneshot
User=root
ExecStartPre=/bin/sh -c "mount -L config-2 /mnt"
ExecStart=/bin/sh -c "sed -i \"s/BAREMETALHOST_UUID/$(jq -r .uuid /mnt/openstack/latest/meta_data.json)/\" /etc/rancher/rke2/config.yaml"
ExecStart=/bin/sh -c "echo \"node-name: $(jq -r .name /mnt/openstack/latest/meta_data.json)\" >> /etc/rancher/rke2/config.yaml"
ExecStartPost=/bin/sh -c "umount /mnt"
[Install]
WantedBy=multi-user.target
storage:
files:
- path: /etc/ptp4l-G.8275.1.conf
overwrite: true
contents:
inline: |
# Telecom G.8275.1 example configuration
[global]
domainNumber 24
priority2 255
dataset_comparison G.8275.x
G.8275.portDS.localPriority 128
G.8275.defaultDS.localPriority 128
maxStepsRemoved 255
logAnnounceInterval -3
logSyncInterval -4
logMinDelayReqInterval -4
announceReceiptTimeout 3
serverOnly 0
ptp_dst_mac 01:80:C2:00:00:0E
network_transport L2
mode: 0644
user:
name: root
group:
name: root
- path: /etc/sysconfig/ptp4l
overwrite: true
contents:
inline: |
## Path: Network/LinuxPTP
## Description: Precision Time Protocol (PTP): ptp4l settings
## Type: string
## Default: "-i eth0 -f /etc/ptp4l.conf"
## ServiceRestart: ptp4l
#
# Arguments when starting ptp4l(8).
#
OPTIONS="-f /etc/ptp4l-G.8275.1.conf -i $IFNAME --message_tag ptp-8275.1"
mode: 0644
user:
name: root
group:
name: root
- path: /etc/sysconfig/phc2sys
overwrite: true
contents:
inline: |
## Path: Network/LinuxPTP
## Description: Precision Time Protocol (PTP): phc2sys settings
## Type: string
## Default: "-s eth0 -w"
## ServiceRestart: phc2sys
#
# Arguments when starting phc2sys(8).
#
OPTIONS="-s $IFNAME -w"
mode: 0644
user:
name: root
group:
name: root
kubelet:
extraArgs:
- provider-id=metal3://BAREMETALHOST_UUID
nodeName: "localhost.localdomain"
Además de otras variables, la definición anterior debe completarse con el nombre de la interfaz y con los demás objetos de Cluster API, como se describe en el Capítulo 42, Aprovisionamiento de red dirigida totalmente automatizado.
Este enfoque solo resulta útil si el hardware del clúster es uniforme y se necesita la misma configuración en todos los hosts, incluido el nombre de la interfaz.
Existen enfoques alternativos que se tratarán en futuras versiones.
En este punto, los hosts deberían tener una pila PTP operativa y en ejecución, y comenzarán a negociar su función PTP.