41 Configuração dos recursos de telecomunicações #
Esta seção documenta e explica a configuração dos recursos específicos de telecomunicações nos clusters implantados pelo SUSE Edge for Telco.
O método de implantação de provisionamento de rede direcionado é usado, conforme descrito na seção sobre provisionamento automatizado (Capítulo 42, Provisionamento de rede direcionado totalmente automatizado).
Os seguintes tópicos são abordados nesta seção:
Imagem do kernel para tempo real (Seção 41.1, “Imagem do kernel para tempo real”): que será usada pelo kernel Real-Time.
Argumentos do kernel para baixa latência e alto desempenho (Seção 41.2, “Argumentos do kernel para baixa latência e alto desempenho”): usados pelo kernel Real-Time para máximo desempenho e baixa latência na execução de cargas de trabalho de telecomunicações.
Fixação de CPU via TuneD e argumentos do kernel (Seção 41.3, “Fixação de CPU via TuneD e argumentos do kernel”): isolamento de CPUs por meio de argumentos do kernel e perfil do TuneD.
Configuração da CNI (Seção 41.4, “Configuração da CNI”): usada pelo cluster Kubernetes.
Configuração do SR-IOV (Seção 41.5, “SR-IOV”): usada pelas cargas de trabalho Kubernetes.
Configuração do DPDK (Seção 41.6, “DPDK”): usada pelo sistema.
Placa aceleradora vRAN (Seção 41.7, “Aceleração vRAN (
Intel ACC100/ACC200
)”): configuração da placa aceleradora usada pelas cargas de trabalho Kubernetes.HugePages (Seção 41.8, “HugePages”): configuração do HugePages usada pelas cargas de trabalho Kubernetes.
Fixação de CPU no Kubernetes (Seção 41.9, “Fixação da CPU em Kubernetes”): configuração do Kubernetes e de aplicativos para aproveitar a fixação de CPU.
Configuração da programação com reconhecimento de NUMA (Seção 41.10, “Programação com reconhecimento de NUMA”): usada pelas cargas de trabalho Kubernetes.
Configuração do Metal LB (Seção 41.11, “MetalLB”): usada pelas cargas de trabalho Kubernetes.
Configuração do registro particular (Seção 41.12, “Configuração do registro particular”): usada pelas cargas de trabalho Kubernetes.
Configuração do Precision Time Protocol (Seção 41.13, “Precision Time Protocol”): arquivos de configuração para execução de perfis de telecomunicações PTP.
41.1 Imagem do kernel para tempo real #
A imagem do kernel Real-Time não é necessariamente melhor do que o kernel padrão. Trata-se de um kernel diferente adaptado a um caso de uso específico. O kernel Real-Time é adaptado para latência mais baixa em detrimento da taxa de transferência. Ele não é recomendado para fins de uso geral; mas, no nosso caso, esse é o kernel recomendado para cargas de trabalho de telecomunicações em que a latência é um fator importante.
Há quatro recursos principais:
Execução determinística:
Aumente a previsibilidade: garanta que os processos de negócios críticos sejam sempre concluídos dentro do prazo e ofereçam um serviço de alta qualidade, mesmo com cargas pesadas do sistema. Ao proteger os recursos importantes do sistema nos processos de alta prioridade, você garante maior previsibilidade para aplicativos urgentes.
Baixa instabilidade:
A baixa instabilidade decorrente da tecnologia altamente determinística ajuda a manter a sincronização dos aplicativos com o mundo real. Isso ajuda os serviços que precisam de cálculo contínuo e repetido.
Herança de prioridade:
A herança de prioridade refere-se à capacidade de um processo de prioridade mais baixa assumir a prioridade mais alta quando há um processo de maior prioridade que requer a conclusão do processo de menor prioridade para então finalizar sua tarefa. O SUSE Linux Enterprise Real Time resolve esses problemas de inversão de prioridade para processos de extrema importância.
Interrupções de threads:
Os processos executados no modo de interrupção em um sistema operacional de uso geral não são preemptíveis. Com o SUSE Linux Enterprise Real Time, essas interrupções foram encapsuladas pelos threads do kernel, que são interrompíveis e permitem a preempção de interrupções fixas e flexíveis por processos de prioridade mais alta definidos pelo usuário.
No nosso caso, se você instalou uma imagem em tempo real, como
SUSE Linux Micro RT
, o kernel Real-Time já está instalado. Você pode fazer download da imagem do kernel Real-Time pelo SUSE Customer Center.
41.2 Argumentos do kernel para baixa latência e alto desempenho #
É importante configurar os argumentos do kernel para que o kernel Real-Time funcione corretamente, apresentando o melhor desempenho e a baixa latência para executar as cargas de trabalho de telecomunicações. Há alguns conceitos importantes para manter em mente na hora de configurar os argumentos do kernel para este caso de uso:
Remova o
kthread_cpus
ao usar o kernel Real-Time da SUSE. Esse parâmetro controla em quais CPUs os threads do kernel serão criados. Ele também controla quais CPUs têm permissão para PID 1 e para carregar módulos do kernel (o auxiliar de espaço do usuário kmod). Esse parâmetro não é reconhecido e não tem nenhum efeito.Isole os núcleos da CPU usando
isolcpus
,nohz_full
,rcu_nocbs
eirqaffinity
. Para acessar a lista completa de técnicas de fixação de CPU, consulte o capítulo Fixação de CPU via TuneD e argumentos do kernel (Seção 41.3, “Fixação de CPU via TuneD e argumentos do kernel”).Adicione os sinalizadores
domain,nohz,managed_irq
ao argumento do kernelisolcpus
. Sem os sinalizadores, oisolcpus
equivale a especificar apenas o sinalizadordomain
. Isso isola as CPUs especificadas da programação, incluindo as tarefas do kernel. O sinalizadornohz
interrompe o tick do programador nas CPUs especificadas (se apenas uma tarefa for executável em determinada CPU), e o sinalizadormanaged_irq
evita o roteamento de interrupções externas gerenciadas (dispositivos) nas CPUs especificadas. Observe que as linhas da IRQ dos dispositivos NVMe são totalmente gerenciadas pelo kernel e serão roteadas para os núcleos não isolados (manutenção) como consequência. Por exemplo, a linha de comando inserida no fim desta seção resultará apenas em quatro filas (mais uma fila de admin/controle) alocadas no 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
Esse comportamento impede interrupções causadas por E/S do disco em qualquer aplicativo urgente executado nos núcleos isolados, mas pode exigir atenção e definição cuidadosa para cargas de trabalho com foco em armazenamento.
Ajuste os ticks (interrupções periódicas do temporizador do kernel):
skew_tick=1
: os ticks às vezes podem ocorrer ao mesmo tempo. Em vez de todas as CPUs receberem o tick do temporizador exatamente no mesmo momento, oskew_tick=1
faz com que ele ocorra em horários um pouco diferentes. Isso ajuda a reduzir a instabilidade do sistema, resultando em tempos de resposta mais consistentes e com menos interrupções (um requisito essencial para aplicativos sensíveis à latência).nohz=on
: interrompe o tick periódico do temporizador em CPUs ociosas.nohz_full=<núcleos-cpu>
: interrompe o tick periódico do temporizador nas CPUs especificadas que são dedicadas a aplicativos em tempo real.
Desabilite o processamento de exceção de verificação de máquina (MCE, Machine Check Exception) especificando
mce=off
. As MCEs são erros do hardware detectados pelo processador, e sua desabilitação pode evitar registros com muito ruído.Adicione
nowatchdog
para desabilitar o watchdog de bloqueio flexível que é implementado como um temporizador em execução no contexto de interrupção fixa do temporizador. Quando ele expira (ou seja, um bloqueio flexível é detectado), um aviso é exibido (no contexto de interrupção fixa), executando os destinos de latência. Mesmo que nunca expire, ele é incluído na lista do temporizador, o que aumenta levemente a sobrecarga de cada interrupção do temporizador. Essa opção também desabilita o watchdog de NMI, assim as NMIs não podem interferir.nmi_watchdog=0
desabilita o watchdog de NMI (interrupção não mascarável). Para omiti-lo, usenowatchdog
.RCU (Read-Copy-Update, Ler-Copiar-Atualizar) é um mecanismo que permite o acesso simultâneo e sem bloqueio de vários leitores aos dados compartilhados. O retorno de chamada RCU, função acionada após um "período extra", garante que todos os leitores anteriores tenham finalizado para que os dados antigos possam ser recuperados com segurança. Ajustamos o RCU, especificamente para cargas de trabalho confidenciais, para descarregar esses retornos de chamada das CPUs dedicadas (fixadas), evitando que as operações do kernel interfiram em tarefas críticas e urgentes.
Especifique as CPUs fixadas em
rcu_nocbs
para que os retornos de chamada RCU não sejam executados nelas. Isso ajuda a reduzir a instabilidade e a latência para cargas de trabalho em tempo real.O
rcu_nocb_poll
faz com que as CPUs sem retorno de chamada realizem sondagens regulares para ver se há necessidade de gerenciar retornos de chamadas. Isso pode reduzir a sobrecarga de interrupções.rcupdate.rcu_cpu_stall_suppress=1
suprime os avisos de parada de RCU da CPU, que às vezes podem ser falsos positivos nos sistemas em tempo real com carga elevada.rcupdate.rcu_expedited=1
acelera o período extra das operações RCU, o que torna as seções críticas do lado da leitura mais responsivas.rcupdate.rcu_normal_after_boot=1
, quando usado com rcu_expedited, permite que o RCU volte à operação normal (não acelerada) após a inicialização do sistema.rcupdate.rcu_task_stall_timeout=0
desabilita o detector de paradas de tarefas do RCU, evitando possíveis avisos ou paralisações do sistema provocadas por tarefas do RCU de longa duração.rcutree.kthread_prio=99
define a prioridade do thread do kernel de retorno de chamada RCU como a mais alta possível (99), garantindo que ele seja programado e processe os retornos de chamada RCU prontamente, quando necessário.
Adicione o
ignition.platform.id=openstack
para que o Metal3 e a Cluster API provisionem/desprovisionem o cluster com sucesso. Ele é usado pelo agente Metal3 Python, que teve sua origem no Openstack Ironic.Remova
intel_pstate=passive
. Essa opção configura ointel_pstate
para operar com controladores cpufreq genéricos. No entanto, para que isso funcione, ele desabilita os estados P gerenciados pelo hardware (HWP
) como efeito colateral. Para reduzir a latência do hardware, essa opção não é recomendada para cargas de trabalho em tempo real.Substitua
intel_idle.max_cstate=0 processor.max_cstate=1
poridle=poll
. Para evitar transições de estado C, a opçãoidle=poll
é usada para desabilitar essas transições e manter a CPU no estado C mais alto. A opçãointel_idle.max_cstate=0
desabilitaintel_idle
para queacpi_idle
seja usado e, em seguida, oacpi_idle.max_cstate=1
define o estado C máximo para acpi_idle. Nas arquiteturas AMD64/Intel 64, o primeiro estado C da ACPI sempre éPOLL
, mas ela usa uma funçãopoll_idle()
, que pode gerar uma pequena latência com a leitura periódica do relógio e a reinicialização do loop principal emdo_idle()
após o tempo limite (isso também envolve limpar e definir o sinalizador da tarefaTIF_POLL
). Por outro lado,idle=poll
é executado em um loop restrito, mantendo-se em espera ocupada até que uma tarefa seja reprogramada. Isso minimiza a latência de sair do estado ocioso, mas à custa de manter a CPU em execução na máxima velocidade no thread ocioso.Desabilite C1E no BIOS. Essa opção é importante para desabilitar o estado C1E no BIOS para evitar que a CPU entre no estado C1E quando estiver ociosa. C1E é um estado de baixo consumo que pode gerar latência quando a CPU está ociosa.
O restante desta documentação aborda parâmetros adicionais, incluindo HugePages e IOMMU.
Este é um exemplo de argumentos do kernel para um servidor Intel de 32 núcleos, incluindo os ajustes já mencionados:
$ 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
Este é outro exemplo de configuração para um servidor AMD de 64
núcleos. Dentre os 128 processadores lógicos (0-127
), os
primeiros 8 núcleos (0-7
) são destinados à manutenção,
enquanto os 120 núcleos restantes (8-127
) são fixados
para os aplicativos:
$ 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 Fixação de CPU via TuneD e argumentos do kernel #
tuned
é uma ferramenta de ajuste de sistema que monitora
as condições do sistema para otimizar o desempenho usando vários perfis
predefinidos. Um recurso importante é sua capacidade de isolar os núcleos da
CPU para cargas de trabalho específicas, como os aplicativos em tempo
real. Isso impede que o sistema operacional use esses núcleos e,
possivelmente, aumente a latência.
Para habilitar e configurar esse recurso, a primeira etapa é criar um perfil
para os núcleos da CPU que desejamos isolar. Neste exemplo, dos 64 núcleos,
dedicamos 60 (1-30,33-62
) para o aplicativo e os 4
restantes são usados para manutenção. Observe que o design das CPUs isoladas
depende significativamente dos aplicativos em tempo 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.
Na sequência, precisamos modificar a opção GRUB para isolar os núcleos da CPU e outros parâmetros importantes para uso da CPU. É importante personalizar as seguintes opções com suas especificações de hardware atuais:
parâmetro | valor | descrição |
---|---|---|
isolcpus | domain,nohz,managed_irq,1-30,33-62 | Isolar os núcleos 1-30 e 33-62. |
skew_tick | 1 | Essa opção permite que o kernel distribua as interrupções do temporizador entre as CPUs isoladas. |
nohz | on | Quando habilitada, a interrupção periódica do temporizador do kernel
("tick") vai parar em qualquer núcleo da CPU que esteja ocioso. Isso
beneficia principalmente as CPUs de manutenção
( |
nohz_full | 1-30,33-62 | Para os núcleos isolados, esse processo interrompe o tick, mesmo quando a CPU está executando uma única tarefa ativa. Dessa forma, ele faz com que a CPU seja executada no modo sem ticks total (ou "dyntick"). O kernel apenas enviará interrupções do temporizador quando forem de fato necessárias. |
rcu_nocbs | 1-30,33-62 | Essa opção descarrega o processamento de retorno de chamada RCU dos núcleos especificados da CPU. |
rcu_nocb_poll | Quando essa opção é definida, as CPUs sem retorno de chamada RCU fazem uma sondagem regular para ver se o processamento de retornos de chamada é necessário, em vez de ser explicitamente ativadas por outras CPUs. Isso pode reduzir a sobrecarga das interrupções. | |
irqaffinity | 0,31,32,63 | Essa opção permite que o kernel execute as interrupções nos núcleos de manutenção. |
idle | poll | Isso minimiza a latência de sair do estado ocioso, mas à custa de manter a CPU em execução na velocidade máxima no thread ocioso. |
nmi_watchdog | 0 | Essa opção desabilita apenas o watchdog de NMI. Para omiti-la, defina
|
nowatchdog | Essa opção desabilita o watchdog de bloqueio flexível, que é implementado como um temporizador executado no contexto de interrupção fixa do temporizador. |
Os seguintes comandos modificam a configuração do GRUB e aplicam as alterações mencionadas acima para que estejam presentes na próxima inicialização:
Edite o arquivo /etc/default/grub
com os parâmetros
acima, e ele terá esta aparência:
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"
Atualize a configuração do GRUB:
$ transactional-update grub.cfg
$ reboot
Para validar a aplicação dos parâmetros após a reinicialização, é possível usar o seguinte comando para verificar a linha de comando do kernel:
$ cat /proc/cmdline
Existe outro script que pode ser usado para ajustar a configuração da CPU que, basicamente, executa as seguintes etapas:
Definir o controlador da CPU como
performance
.Cancelar a definição da migração do temporizador para as CPUs isoladas.
Migrar os threads kdaemon para as CPUs de manutenção.
Definir a latência das CPUs isoladas como o valor mais baixo possível.
Atrasar as atualizações de vmstat para 300 segundos.
O script está disponível no repositório de exemplos do SUSE Edge for Telco.
41.4 Configuração da CNI #
41.4.1 Cilium #
Cilium
é o plug-in de CNI padrão para o SUSE Edge for
Telco. Para habilitar o Cilium no cluster RKE2 como plug-in padrão, as
seguintes configurações são necessárias no arquivo
/etc/rancher/rke2/config.yaml
:
cni:
- cilium
Também é possível especificar isso com argumentos de linha de comando, ou
seja, --cni=cilium
na linha do servidor no arquivo
/etc/systemd/system/rke2-server
.
Para usar o operador de rede SR-IOV
descrito na próxima
seção (Seção 41.5, “SR-IOV”), use o
Multus
com outro plug-in de CNI, como
Cilium
ou Calico
, como o plug-in
secundário.
cni:
- multus
- cilium
41.5 SR-IOV #
O SR-IOV permite que um dispositivo, por exemplo, adaptador de rede, separe
o acesso a seus recursos entre várias funções de hardware
PCIe
. Há diversas maneiras de implantar o
SR-IOV
e, neste documento, mostramos duas opções
diferentes:
Opção 1: usar os plug-ins de dispositivo CNI
SR-IOV
e um mapa de configuração para configurá-lo de maneira apropriada.Opção 2 (recomendada): usar o gráfico Helm do
SR-IOV
do Rancher Prime para facilitar a implantação.
Opção 1 – Instalação dos plug-ins de dispositivo CNI SR-IOV e um mapa de configuração para configurá-lo de maneira apropriada
Preparar o mapa de configuração para o plug-in de dispositivo
Obtenha as informações para preencher o mapa de configuração executando o
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)
O mapa de configuração consiste em um arquivo JSON
que
descreve os dispositivos usando filtros para descobri-los e cria grupos para
as interfaces. O principal é entender os filtros e os grupos. Os filtros são
usados para descobrir os dispositivos, e os grupos para criar as interfaces.
É possível definir os filtros desta maneira:
vendorID:
8086
(Intel)deviceID:
0d5c
(placa aceleradora)driver:
vfio-pci
(driver)pfNames:
p2p1
(nome da interface física)
É possível também definir os filtros para corresponder à uma sintaxe de interface mais complexa, por exemplo:
pfNames:
["eth1#1,2,3,4,5,6"]
ou[eth1#1-6]
(nome da interface física)
Em relação aos grupos, podemos criar um para a placa FEC
e outro para a placa Intel
, e até criar um prefixo
dependendo do nosso caso de uso:
resourceName:
pci_sriov_net_bh_dpdk
resourcePrefix:
Rancher.io
Há inúmeras combinações para descobrir e criar o grupo de recursos para
alocar algumas VFs
aos pods.
Para obter mais informações sobre filtros e grupos, visite sr-iov network device plug-in (Plug-in de dispositivo de rede sr-iov).
Depois de definir os filtros e os grupos para corresponder as interfaces, dependendo do hardware e do caso de uso, o seguinte mapa de configuração mostrará um exemplo para ser usado:
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"]
}
}
]
}
Preparar o arquivo
daemonset
para implantar o plug-in de dispositivo
O plug-in de dispositivo oferece suporte a várias arquiteturas
(arm
, amd
,
ppc64le
), portanto, é possível usar o mesmo arquivo para
arquiteturas diferentes ao implantar vários daemonset
para cada arquitetura.
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
Depois de aplicar o mapa de configuração e o
daemonset
, o plug-in de dispositivo será implantado, e as interfaces serão descobertas e estarão disponíveis para os pods.$ kubectl get pods -n kube-system | grep sriov kube-system kube-sriov-device-plugin-amd64-twjfl 1/1 Running 0 2m
Verifique as interfaces descobertas e disponíveis nos nós usados pelos 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" }
O
FEC
éintel.com/intel_fec_5g
e o valor é 1.A
VF
éintel.com/intel_sriov_odu
ouintel.com/intel_sriov_oru
, se você a implantar com um plug-in de dispositivo e um mapa de configuração sem gráficos Helm.
Se não há interfaces neste ponto, não faz muito sentido continuar porque a interface não estará disponível para os pods. Revise o mapa de configuração e os filtros para resolver o problema primeiro.
Opção 2 (recomendada) – Instalação usando o Rancher com gráficos Helm para plug-ins de dispositivo CNI SR-IOV
Obtenha o Helm se não estiver presente:
$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Instale o 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
Verifique os recursos crd e os pods implantados:
$ kubectl get crd
$ kubectl -n sriov-network-operator get pods
Verifique o rótulo nos nós.
Com todos os recursos em execução, o rótulo aparecerá automaticamente em seu nó:
$ kubectl get nodes -oyaml | grep feature.node.kubernetes.io/network-sriov.capable
feature.node.kubernetes.io/network-sriov.capable: "true"
Revise o
daemonset
para ver os novossriov-network-config-daemon
esriov-rancher-nfd-worker
já ativos e prontos:
$ 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
Em poucos minutos (a atualização pode levar até 10 minutos), os nós são
detectados e configurados com os recursos do SR-IOV
:
$ kubectl get sriovnetworknodestates.sriovnetwork.openshift.io -A
NAMESPACE NAME AGE
sriov-network-operator xr11-2 83s
Verifique as interfaces detectadas.
As interfaces descobertas devem ser o endereço PCI do dispositivo de
rede. Verifique essa informação com o comando lspci
no
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: ""
Se a sua interface não foi detectada neste momento, verifique se ela está presente no próximo mapa de configuração:
$ kubectl get cm supported-nic-ids -oyaml -n sriov-network-operator
Se o seu dispositivo não estiver presente lá, edite o mapa de configuração
adicionando os valores corretos a serem descobertos (deve ser necessário
reiniciar o daemonset sriov-network-config-daemon
).
Crie a
política NetworkNode
para configurar asVFs
.
Serão criadas algumas VFs
(numVfs
) do
dispositivo (rootDevices
), e ela será configurada com o
deviceType
do driver e a MTU
:
O campo resourceName
não deve conter caracteres especiais
e deve ser exclusivo em todo o cluster. O exemplo usa deviceType:
vfio-pci
porque dpdk
será usado em conjunto com
sr-iov
. Se você não usar dpdk
, o
deviceType deverá ser deviceType: netdevice
(valor
padrão).
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 as configurações:
$ 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"
}
Crie a rede sr-iov (opcional, caso seja necessária uma rede 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
Verifique a rede criada:
$ 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) é um conjunto de
bibliotecas e drivers para processamento rápido de pacotes. Ele é usado para
acelerar as cargas de trabalho de processamento de pacotes executadas em uma
ampla variedade de arquiteturas de CPU. O DPDK inclui as bibliotecas de
plano de controle e os drivers otimizados de placa de interface de rede
(NIC
) para o seguinte:
Um gerenciador de fila que implementa filas sem bloqueio.
Um gerenciador de buffer que pré-aloca buffers de tamanho fixo.
Um gerenciador de memória que aloca pools de objetos na memória e usa um anel para armazenar objetos livres; garante que os objetos sejam igualmente distribuídos por todos os canais
DRAM
.Drivers de modo de sondagem (
PMD
) desenvolvidos para operar sem notificações assíncronas, reduzindo a sobrecarga.Uma estrutura de pacotes como um conjunto de bibliotecas auxiliares para desenvolver o processamento de pacotes.
As seguintes etapas mostram como habilitar o DPDK
e criar
VFs
das NICs
usadas pelas interfaces
do DPDK
:
Instale o pacote
DPDK
:
$ transactional-update pkg install dpdk dpdk-tools libdpdk-23
$ reboot
Parâmetros do kernel:
Para usar o DPDK, aplique alguns drivers para habilitar determinados parâmetros no kernel:
parâmetro | valor | descrição |
---|---|---|
iommu | pt | Essa opção permite usar o driver |
intel_iommu ou amd_iommu | on | Essa opção permite usar o |
Para habilitar os parâmetros, adicione-os ao arquivo
/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"
Atualize a configuração do GRUB e reinicialize o sistema para aplicar as alterações:
$ transactional-update grub.cfg
$ reboot
Carregue o módulo do kernel
vfio-pci
e habilite oSR-IOV
nasNICs
:
$ modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
Crie algumas funções virtuais (
VFs
) dasNICs
.
Por exemplo, para criar VFs
para duas
NICs
diferentes, os seguintes comandos são necessários:
$ 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 as novas VFs ao driver
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
Verifique se a configuração foi aplicada corretamente:
$ 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 Aceleração vRAN (Intel ACC100/ACC200
) #
À medida que os provedores de serviços de comunicação migram da rede 4G para
5G, muitos deles estão adotando as arquiteturas de rede de acesso por rádio
virtualizada (vRAN
) para maior capacidade dos canais e
implantação mais fácil dos serviços e aplicativos de borda. As soluções vRAN
estão no local ideal para oferecer serviços de baixa latência com
flexibilidade para aumentar ou reduzir a capacidade de acordo com o volume
do tráfego e da demanda em tempo real na rede.
Uma das cargas de trabalho 4G e 5G com uso mais intenso de recursos é a
FEC
da RAN de camada 1 (L1
), que
resolve os erros de transmissão de dados por meio de canais de comunicação
incertos ou ruidosos. A tecnologia FEC
detecta e corrige
um número limitado de erros em dados 4G ou 5G, eliminando a necessidade de
retransmissão. Como a transação de aceleração da FEC
não
contém informações de estado da célula, é possível virtualizá-la com
facilidade para aproveitar os benefícios dos agrupamentos e facilitar a
migração de células.
Parâmetros do kernel
Para habilitar a aceleração da vRAN
, precisamos habilitar
os seguintes parâmetros do kernel (se ainda não estiverem presentes):
parâmetro | valor | descrição |
---|---|---|
iommu | pt | Essa opção permite usar vfio paras as interfaces do DPDK. |
intel_iommu ou amd_iommu | on | Essa opção permite usar vfio para VFs. |
Modifique o arquivo GRUB /etc/default/grub
para
adicioná-los à linha de comando do 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"
Atualize a configuração do GRUB e reinicialize o sistema para aplicar as alterações:
$ transactional-update grub.cfg
$ reboot
Para verificar se os parâmetros foram aplicados após a reinicialização, consulte a linha de comando:
$ cat /proc/cmdline
Carregue os módulos do kernel vfio-pci para habilitar a aceleração da
vRAN
:
$ modprobe vfio-pci enable_sriov=1 disable_idle_d3=1
Obtenha as informações da interface Acc100:
$ lspci | grep -i acc
8a:00.0 Processing accelerators: Intel Corporation Device 0d5c
Vincule a interface física (
PF
) ao drivervfio-pci
:
$ dpdk-devbind.py -b vfio-pci 0000:8a:00.0
Crie as funções virtuais (
VFs
) da interface física (PF
).
Crie 2 VFs
da PF
e vincule a elas o
vfio-pci
seguindo estas etapas:
$ echo 2 > /sys/bus/pci/devices/0000:8a:00.0/sriov_numvfs
$ dpdk-devbind.py -b vfio-pci 0000:8b:00.0
Configure a acc100 com o arquivo de configuração proposto:
$ 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!
Verifique as novas VFs criadas da PF 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 HugePages #
Quando um processo usa RAM
, a CPU
a
marca como usada por esse processo. Para manter a eficiência, a
CPU
aloca a RAM
em blocos de
4K
bytes, que é o valor padrão em muitas
plataformas. Esses blocos são chamados de páginas. As páginas podem ser
substituídas por discos, entre outros.
Como o espaço do endereço do processo é virtual, a CPU
e
o sistema operacional precisam memorizar quais páginas pertencem a qual
processo, e onde cada página é armazenada. Quanto maior o número de páginas,
mais longa a pesquisa de mapeamento de memória. Quando um processo usa
1 GB
de memória, isso equivale a 262144 entradas para
pesquisa (1 GB
/4 K
). Se uma entrada da
tabela de páginas consome 8 bytes, isso equivale a 2 MB
(262144 * 8) para pesquisa.
As arquiteturas de CPU
mais atuais oferecem suporte às
páginas maiores que o padrão, o que reduz o número de entradas para a
CPU/SO
pesquisar.
Parâmetros do kernel
Para habilitar o HugePages, devemos adicionar os seguintes parâmetros do kernel. Neste exemplo, configuramos 40 páginas de 1G, portanto, o tamanho e o número exato de páginas enormes devem ser adaptados aos requisitos de memória do seu aplicativo:
parâmetro | valor | descrição |
---|---|---|
hugepagesz | 1G | Essa opção permite definir o tamanho das páginas enormes como 1 G |
hugepages | 40 | Esse é o número de páginas enormes definido antes |
default_hugepagesz | 1G | Esse é o valor padrão para obter as páginas enormes |
Modifique o arquivo GRUB /etc/default/grub
para adicionar
esses parâmetros a GRUB_CMDLINE_LINUX
:
default_hugepagesz=1G hugepagesz=1G hugepages=40 hugepagesz=2M hugepages=0
Atualize a configuração do GRUB e reinicialize o sistema para aplicar as alterações:
$ transactional-update grub.cfg
$ reboot
Para validar se os parâmetros foram aplicados após a reinicialização, verifique a linha de comando:
$ cat /proc/cmdline
Usando o HugePages
Para usar o HugePages, precisamos montá-lo:
$ mkdir -p /hugepages
$ mount -t hugetlbfs nodev /hugepages
Implante a carga de trabalho Kubernetes criando os recursos e os volumes:
...
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 Fixação da CPU em Kubernetes #
41.9.1 Pré-requisito #
A CPU
deve estar ajustada de acordo com o perfil de
desempenho abordado nesta seção (Seção 41.3, “Fixação de CPU via TuneD e argumentos do kernel”).
41.9.2 Configurar o Kubernetes para fixação da CPU #
Configure os argumentos de kubelet para implementar o gerenciamento da CPU
no cluster RKE2
. Adicione o seguinte bloco de
configuração, como no exemplo abaixo, ao arquivo
/etc/rancher/rke2/config.yaml
. Especifique os núcleos da
CPU de manutenção nos argumentos kubelet-reserved
e
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 Aproveitando as CPUs fixadas para as cargas de trabalho #
Há três maneiras de usar este recurso com a política
estática
definida no kubelet, dependendo das solicitações e dos
limites definidos em sua carga de trabalho:
Classe de QoS
BestEffort
: se você não definir uma solicitação ou um limite deCPU
, o pod será programado na primeiraCPU
disponível no sistema.Um exemplo de uso da classe de QoS
BestEffort
é:spec: containers: - name: nginx image: nginx
Classe de QoS
Burstable
: se você definir uma solicitação de CPU que não é igual aos limites, ou se não houver solicitações de CPU.Alguns exemplos de uso da classe de QoS
Burstable
são:spec: containers: - name: nginx image: nginx resources: limits: memory: "200Mi" requests: memory: "100Mi"
ou
spec: containers: - name: nginx image: nginx resources: limits: memory: "200Mi" cpu: "2" requests: memory: "100Mi" cpu: "1"
Classe de QoS
Guaranteed
: se você definir uma solicitação de CPU igual aos limites.Um exemplo de uso da classe de QoS
Guaranteed
é:spec: containers: - name: nginx image: nginx resources: limits: memory: "200Mi" cpu: "2" requests: memory: "200Mi" cpu: "2"
41.10 Programação com reconhecimento de NUMA #
Acesso não uniforme à memória ou arquitetura não uniforme de acesso à
memória (NUMA
, Non-Uniform Memory Access ou Non-Uniform
Memory Architecture) é um projeto de memória física usado na arquitetura
SMP
(multiprocessadores), em que o tempo de acesso à
memória depende do local da memória relativo ao processador. No
NUMA
, um processador pode acessar a própria memória local
com mais rapidez do que a memória não local, ou seja, a memória local de
outro processador ou a memória compartilhada entre processadores.
41.10.1 Identificando os nós NUMA #
Para identificar os nós NUMA
, execute o seguinte comando
em seu sistema:
$ lscpu | grep NUMA
NUMA node(s): 1
NUMA node0 CPU(s): 0-63
Para este exemplo, temos apenas um nó NUMA
com 64
CPUs
.
É necessário habilitar o NUMA
no
BIOS
. Se o dmesg
não tem registros de
inicialização do NUMA durante o bootup, as mensagens relacionadas ao
NUMA
no buffer de anel do kernel podem ter sido
substituídas.
41.11 MetalLB #
MetalLB
é uma implementação de balanceador de carga para
clusters Kubernetes bare metal, que usa os protocolos de roteamento padrão,
como L2
e BGP
, como protocolos de
anúncio. Trata-se de um balanceador de carga de rede que pode ser usado para
expor serviços em um cluster Kubernetes ao ambiente externo por causa da
necessidade de usar serviços do Kubernetes do tipo
LoadBalancer
com bare metal.
Para habilitar o MetalLB
no cluster
RKE2
, são necessárias as seguintes etapas:
Instale o
MetalLB
usando o seguinte 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
Crie a configuração de
IpAddressPool
eL2advertisement
:
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
Crie o serviço de endpoint para expor o
VIP
:
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
Verifique se o
VIP
foi criado e se os pods doMetalLB
estão em execução:
$ kubectl get svc -n default
$ kubectl get pods -n default
41.12 Configuração do registro particular #
É possível configurar o Containerd
para conexão com os
registros particulares e usá-los para extrair as imagens particulares de
cada nó.
Na inicialização, o RKE2
verifica se existe um arquivo
registries.yaml
em /etc/rancher/rke2/
e instrui o containerd
a usar os registros definidos no
arquivo. Para usar um registro particular, crie esse arquivo como raiz em
cada nó que usará o registro.
Para adicionar o registro particular, crie o arquivo
/etc/rancher/rke2/registries.yaml
com o seguinte
conteúdo:
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
ou sem autenticação:
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 as alterações no registro entrem em vigor, você precisa configurar esse arquivo antes de iniciar o RKE2 no nó ou reiniciar o RKE2 em cada nó configurado.
41.13 Precision Time Protocol #
Precision Time Protocol (PTP) é um protocolo de rede desenvolvido pelo Institute of Electrical and Electronics Engineers (IEEE) para permitir a sincronização de tempo em submicrossegundos em uma rede de computadores. Desde a sua origem e durante as duas últimas décadas, o PTP tem sido usado em diversos setores. Recentemente, observamos uma crescente adoção nas redes de telecomunicações como elemento essencial a redes 5G. Apesar de ser um protocolo relativamente simples, sua configuração pode mudar bastante de acordo com o aplicativo. Por essa razão, foram definidos e padronizados vários perfis.
Nesta seção, apenas os perfis específicos de telecomunicações serão apresentados. Portanto, vamos considerar o recurso de marcação de data e hora e um relógio de hardware PTP (PHC, PTP Hardware Clock) na NIC. Hoje em dia, todos os adaptadores de rede para telecomunicações contam com suporte a PTP no hardware, mas você pode verificar esses recursos com o seguinte 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
Substitua p1p1
pelo nome da interface usada para PTP.
As seções a seguir orientam como instalar e configurar o PTP especificamente no SUSE Edge, mas deve haver uma familiaridade com os conceitos básicos do PTP. Para uma breve visão geral do PTP e a implementação incluída no SUSE Edge for Telco, acesse https://documentation.suse.com/sles/html/SLES-all/cha-tuning-ptp.html.
41.13.1 Instalar os componentes de software PTP #
No SUSE Edge for Telco, a implementação do PTP é fornecida pelo pacote
linuxptp
, que inclui dois componentes:
ptp4l
: um daemon que controla o PHC na NIC e executa o protocolo PTPphc2sys
: um daemon que mantém a sincronização do relógio do sistema com o PHC sincronizado por PTP na NIC
Os dois daemons são necessários para que a sincronização do sistema funcione por completo e devem ser definidos de maneira correta com a sua configuração, o que foi abordado na Seção 41.13.2, “Configurar o PTP para implantações de telecomunicações”.
A maneira melhor e mais fácil de integrar o PTP ao cluster downstream é
adicionar o pacote linuxptp
em
packageList
ao arquivo de definição do Edge Image Builder
(EIB). Desse modo, o software de plano de controle PTP será instalado
automaticamente durante o provisionamento do cluster. Consulte a
documentação do EIB (Seção 3.3.4, “Configurando pacotes RPM”) para
obter mais informações sobre como instalar os pacotes.
Veja a seguir um manifesto do EIB de amostra com
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}
O pacote linuxptp
incluído no SUSE Edge for Telco não
habilita o ptp4l
e o phc2sys
por
padrão. Se os arquivos de configuração específicos do sistema forem
implantados no momento do provisionamento (consulte a Seção 41.13.3, “Integração da Cluster API”), eles deverão ser habilitados. Para isso, adicione-os
à seção systemd
do manifesto, conforme o exemplo acima.
Siga o processo normal para criar a imagem conforme descrito na documentação do EIB (Seção 3.4, “Criando a imagem”) e use-a para implantar o cluster. Se você não tem experiência com o EIB, comece pelo Capítulo 11, Edge Image Builder.
41.13.2 Configurar o PTP para implantações de telecomunicações #
Muitos aplicativos de telecomunicações exigem uma sincronização rígida de
fase e de tempo com pouca variação, o que resultou na definição de dois
perfis orientados a telecomunicações: ITU-T G.8275.1 e ITU-T G.8275.2. Os
dois têm alta taxa de mensagens de sincronização e outros aspectos
diferenciados, como uso de um algoritmo BMCA (Best Master Clock Algorithm)
alternativo. Esse comportamento exige definições específicas no arquivo de
configuração consumido pelo ptp4l
, apresentadas nas
seções a seguir como referência.
As duas seções abordam apenas o caso de um relógio comum na configuração de receptor de tempo.
Esse tipo de perfil deve ser usado em uma infraestrutura PTP bem planejada.
Sua rede PTP específica pode exigir um ajuste de configuração adicional. Revise os exemplos apresentados e adapte-os se necessário.
41.13.2.1 Perfil de PTP ITU-T G.8275.1 #
O perfil G.8275.1 tem as seguintes especificações:
Executado diretamente em Ethernet e requer suporte completo à rede (nós/comutadores adjacentes devem dar suporte a PTP).
A configuração de domínio padrão é 24.
A comparação de conjunto de dados baseia-se no algoritmo G.8275.x e nos valores
localPriority
depois depriority2
.
Copie o seguinte conteúdo para um arquivo chamado
/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
Após a criação do arquivo, faça referência a ele em
/etc/sysconfig/ptp4l
para o daemon ser iniciado
corretamente. Para fazer isso, altere a linha OPTIONS=
:
OPTIONS="-f /etc/ptp4l-G.8275.1.conf -i $IFNAME --message_tag ptp-8275.1"
Mais precisamente:
-f
requer o nome do arquivo de configuração que será usado; neste caso,/etc/ptp4l-G.8275.1.conf
.-i
requer o nome da interface que será usada. Substitua$IFNAME
pelo nome da interface real.--message_tag
permite identificar melhor a saída de ptp4l nos registros do sistema e é opcional.
Após a conclusão das etapas acima, o daemon ptp4l
deverá
ser (re)iniciado:
# systemctl restart ptp4l
Verifique o status da sincronização observando os registros com:
# journalctl -e -u ptp4l
41.13.2.2 Perfil de PTP ITU-T G.8275.2 #
O perfil G.8275.2 tem as seguintes especificações:
Executado em IP e não requer suporte total à rede (nós/comutadores adjacentes podem não dar suporte a PTP).
A configuração de domínio padrão é 44.
A comparação de conjunto de dados baseia-se no algoritmo G.8275.x e nos valores
localPriority
depois depriority2
.
Copie o seguinte conteúdo para o arquivo chamado
/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
Substitua os seguintes espaços reservados:
$PEER_IP_ADDRESS
: o endereço IP do nó PTP seguinte com o qual se comunicar, como o relógio mestre ou de limite que fornecerá a sincronização.$IFNAME
: instrui optp4l
sobre qual interface usar para PTP.
Após a criação do arquivo, faça referência a ele, junto com o nome da
interface para PTP, em /etc/sysconfig/ptp4l
para que o
daemon seja iniciado corretamente. Para fazer isso, altere a linha
OPTIONS=
para:
OPTIONS="-f /etc/ptp4l-G.8275.2.conf --message_tag ptp-8275.2"
Mais precisamente:
-f
requer o nome do arquivo de configuração que será usado; neste caso,/etc/ptp4l-G.8275.2.conf
.--message_tag
permite identificar melhor a saída de ptp4l nos registros do sistema e é opcional.
Após a conclusão das etapas acima, o daemon ptp4l
deverá
ser (re)iniciado:
# systemctl restart ptp4l
Verifique o status da sincronização observando os registros com:
# journalctl -e -u ptp4l
41.13.2.3 Configuração do phc2sys #
Embora não seja obrigatório, é recomendado completar toda a configuração de
ptp4l
antes de passar para o
phc2sys
. O phc2sys
não requer um
arquivo de configuração, e seus parâmetros de execução podem ser controlados
unicamente pela variável OPTIONS=
presente em
/etc/sysconfig/ptp4l
, de maneira similar a
ptp4l
:
OPTIONS="-s $IFNAME -w"
Em que $IFNAME
é o nome da interface já configurada em
ptp4l, que será usada como fonte para o relógio do sistema. Isso é usado
para identificar o PHC de origem.
41.13.3 Integração da Cluster API #
Sempre que um cluster é implantado por cluster de gerenciamento e
provisionamento de rede direcionado, tanto o arquivo de configuração quanto
as duas variáveis de configuração em /etc/sysconfig
podem
ser implantados no host no momento do provisionamento. Veja abaixo o trecho
de uma definição de cluster, com foco no objeto
RKE2ControlPlane
modificado que implanta o mesmo arquivo
de configuração G.8275.1 em todos os 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"
Além de outras variáveis, é necessário preencher a definição acima com o nome da interface e os outros objetos da Cluster API, conforme descrito no Capítulo 42, Provisionamento de rede direcionado totalmente automatizado.
Essa é uma abordagem prática apenas quando o hardware no cluster é uniforme e a mesma configuração é necessária em todos os hosts, inclusive o nome da interface.
Há outras abordagens possíveis que serão explicadas em versões futuras.
Neste ponto, os hosts devem ter uma pilha PTP em funcionamento e começarão a negociar sua função de PTP.