Exemplos de UDNs de rede local para virtualização d Red Hat OpenShift

Conecte máquinas virtuais de virtualização do OpenShift às sub-redes do IBM Cloud VPC usando redes CUDN Localnet para tráfego baseado em VLAN e isolado por namespace.

Este tutorial mostra como criar um exemplo de aplicativo de três camadas usando sub-redes da Nuvem Privada Virtual (VPC), Redes Definidas pelo Usuário em Cluster (CUDNs), localnets e namespaces no Red Hat OpenShift on IBM Cloud em IBM Cloud. O exemplo demonstra como conectar servidores virtuais que rodam na virtualização d Red Hat OpenShift diretamente às sub-redes da VPC, utilizando redes localnet baseadas em redes de área local virtual (VLAN). Para obter mais informações sobre tipos de rede, consulte a seção “Redes Open Virtual Network(OVN)” em Red Hat OpenShift, destinada aos administradores do vSphere®.

Visão geral

O exemplo implementa uma aplicação de três camadas com segmentos de rede separados para as camadas web, banco de dados e aplicação. Cada camada utiliza uma sub-rede VPC dedicada e uma rede local CUDN com um ID de VLAN exclusivo. As camadas da web e do banco de dados estão localizadas em um único namespace (green), enquanto a camada de aplicação está localizada em um namespace separado (red) para demonstrar o isolamento baseado em namespace.

Detalhes da rede, do namespace e do servidor virtual

A tabela a seguir resume o exemplo de layout de rede.

Exemplo de configuração de CUDN, namespace e servidor virtual na rede local
Localnet CUDN Namespace: ID de VLAN Sub-rede de VPC Servidores virtuais
vlan20-prod green 20 198.18.0.0/24 plant-web00, plant-web01
vlan21-db green 21 198.18.1.0/24 plant-db00, plant-db01
vlan22-app red 22 198.18.2.0/24 plant-app00, plant-app01

Diagrama da configuração final

Configuração de aplicativo de três camadas no Localnet
Configuração de aplicativo de três camadas no Localnet

Cada bloco de código do guia pode ser copiado para um arquivo e aplicado com o comando oc apply -f .yml``. Alguns blocos de código podem ultrapassar os limites das páginas nos formatos PDF e Word, e algumas linhas longas podem quebrar nesses formatos.

O guia utiliza “ ic ” como abreviação de “ ibmcloud ” nos comandos da CLI do IBM Cloud. Defina alias ic=ibmcloud no seu shell ou substitua ibmcloud por ic nos comandos a seguir.

Antes de Iniciar

Certifique-se de que os seguintes itens estejam disponíveis:

  • Uma conta do IBM Cloud com permissão para gerenciar recursos do VPC e do Red Hat OpenShift.
  • A CLI do IBM Cloud está instalada.
  • Os plug-ins container-service e vpc-infrastructure estão instalados.

O plug-in “ container-service ” fornece os comandos “ ic ks ” que o guia utiliza para conectar interfaces de rede virtuais (VNIs) de VLAN ao cluster. O plug-in “ vpc-infrastructure ” fornece os comandos “ ic is ” que o guia utiliza para criar sub-redes VPC, interfaces de rede virtual (VNIs) e outros componentes de infraestrutura.

Se você precisar instalar os plug-ins necessários para a CLI, use os comandos a seguir.

ibmcloud plugin install container-service
ibmcloud plugin install vpc-infrastructure

Verificar os pré-requisitos de rede

Se você estiver usando o Red Hat OpenShift on IBM Cloud, verifique os pré-requisitos de rede do OVN UDN/CUDN em Red Hat OpenShift on IBM Cloud antes de começar. O Serviço de Virtualização Red Hat OpenShift inclui esses pré-requisitos por padrão.

Criação de um namespace e de uma rede secundária CUDN Localnet para o nível verde

As redes Localnet podem coexistir com redes primárias Layer 2, redes secundárias Layer 2 e outras redes Localnet em um namespace. Cada rede local requer um VLAN ID. Atualmente, é possível usar apenas uma sub-rede por VLAN.

A VLAN não cria um domínio de “ Layer 2 ” entre os trabalhadores. A VLAN é utilizada dentro de cada nó de trabalho, e não dentro da VPC.

Crie o namespace green e as redes vlan20-prod e vlan21-db. Aplique o manifesto com o comando oc apply -f step1.yml``.

---
apiVersion: v1
kind: Namespace
metadata:
  name: green
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
  name: "vlan20-prod"
spec:
  namespaceSelector:
    matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: In
      values:
      - "green"
  network:
    topology: Localnet
    localnet:
      role: "Secondary"
      physicalNetworkName: "vpc-vlans"
      ipam:
        mode: Disabled
      vlan:
        mode: Access
        access:
          id: 20
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
  name: "vlan21-db"
spec:
  namespaceSelector:
    matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: In
      values:
      - "green"
  network:
    topology: Localnet
    localnet:
      role: "Secondary"
      physicalNetworkName: "vpc-vlans"
      ipam:
        mode: Disabled
      vlan:
        mode: Access
        access:
          id: 21

Tenha em mente as seguintes considerações:

  • A sub-rede não está definida na configuração do Localnet.
  • Não utilize VLAN 1.
  • Utilize VLANs no intervalo de 2 a 500. As VLANs 501 a 4094 estão restritas no momento.

Criação de outro namespace e de uma rede secundária CUDN Localnet para o nível vermelho

Crie o namespace red e a rede vlan22-app. Aplique o manifesto com o comando oc apply -f step2.yml``.

---
apiVersion: v1
kind: Namespace
metadata:
  name: red
---
apiVersion: k8s.ovn.org/v1
kind: ClusterUserDefinedNetwork
metadata:
  name: "vlan22-app"
spec:
  namespaceSelector:
    matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: In
      values:
      - "red"
  network:
    topology: Localnet
    localnet:
      role: "Secondary"
      physicalNetworkName: "vpc-vlans"
      ipam:
        mode: Disabled
      vlan:
        mode: Access
        access:
          id: 22

Criação de IPs reservados e VNIs na sua conta VPC

Esta etapa cria um endereço IP reservado em cada sub-rede; em seguida, cria o VNI usando esse endereço IP reservado e atribui um endereço de interface de rede virtual ( MAC address ) a cada interface de rede virtual (VNI).

Tenha em mente as seguintes considerações:

  • O “ VLAN ID ” não é anexado nesta etapa.
  • Você deve verificar qual grupo de segurança deve ser usado nesta etapa. Execute o comando ic is sgs para listar os grupos de segurança disponíveis.
  • É possível executar essa etapa em lote.
  • O limite é de 256 VNIs por host. Mantenha a utilização abaixo de 85% para permitir o failover e as migrações de outros hosts.

Criação de endereços IP reservados em cada sub-rede

Primeiro, crie um endereço IP reservado em cada sub-rede para seus servidores virtuais:

ic is subnet-reserved-ip-create zone1-vm-prod --address 198.18.0.20 --name zone1-web00 --auto-delete false
ic is subnet-reserved-ip-create zone1-vm-db --address 198.18.1.20 --name zone1-db00 --auto-delete false
ic is subnet-reserved-ip-create zone1-vm-app --address 198.18.2.20 --name zone1-app00 --auto-delete false

Criação de VNIs usando os endereços IP reservados

Agora, crie as VNIs usando os nomes de IP reservados na etapa anterior:

ic is virtual-network-interface-create --name zone1-web00 --allow-ip-spoofing false --auto-delete false --protocol-state-filtering-mode disabled --enable-infrastructure-nat true --subnet zone1-vm-prod --vpc my-vpc --rip zone1-web00 --sgs handclap-roundworm-clique-eccentric --resource-group-name Default
ic is virtual-network-interface-create --name zone1-db00 --allow-ip-spoofing false --auto-delete false --protocol-state-filtering-mode disabled --enable-infrastructure-nat true --subnet zone1-vm-db --vpc my-vpc --rip zone1-db00 --sgs handclap-roundworm-clique-eccentric --resource-group-name Default
ic is virtual-network-interface-create --name zone1-app00 --allow-ip-spoofing false --auto-delete false --protocol-state-filtering-mode disabled --enable-infrastructure-nat true --subnet zone1-vm-app --vpc my-vpc --rip zone1-app00 --sgs handclap-roundworm-clique-eccentric --resource-group-name Default

Anexando o VNI da VLAN ao cluster

Obtenha o ID de cada VNI que você criou na etapa anterior e, em seguida, use o plug-in “ IBM Cloud ” container-service para associar o VNI ao cluster. Você precisa do ID do cluster, que pode ser obtido executando o comando ic ks cluster ls``.

Tenha em mente as seguintes considerações:

  • Se um trabalhador ultrapassar sua cota de VNI, a operação associada falhará.
  • As VNIs podem ser conectadas ao cluster (também conhecido como “ floating ”) ou a um worker específico.

Procure os IDs do VNI.

ic is vni zone1-web00 | awk '$1 ~ /^ID/ {print $NF}'
ic is vni zone1-db00 | awk '$1 ~ /^ID/ {print $NF}'
ic is vni zone1-app00 | awk '$1 ~ /^ID/ {print $NF}'

Conecte cada VNI ao cluster com o ID de VLAN correspondente. Substitua o ID do cluster e os IDs de VNI pelos valores do seu ambiente.

ic ks vni attach baremetal -c <CLUSTER_ID> --vni <VNI_ID_web00> --vlan 20
ic ks vni attach baremetal -c <CLUSTER_ID> --vni <VNI_ID_db00>  --vlan 21
ic ks vni attach baremetal -c <CLUSTER_ID> --vni <VNI_ID_app00> --vlan 22

Adicionando servidores virtuais aos namespaces

O manifesto a seguir é um exemplo básico de YAML para criar um servidor virtual. Você pode atualizar esse manifesto para cada namespace e rede. Você precisa do arquivo MAC address para cada VNI que criou. Execute o comando ic is vnis para listá-los e atualize o campo macAddress no modelo para que DHCP funcione corretamente.

Use os seguintes comandos para localizar o arquivo MAC address para cada VNI``.

ic is vni zone1-web00 | awk '/^Mac Address/ {print $NF}'
ic is vni zone1-db00  | awk '/^Mac Address/ {print $NF}'
ic is vni zone1-app00 | awk '/^Mac Address/ {print $NF}'

Exemplo de saída para cada VNI. Seus valores são diferentes:

02:00:01:00:98:A0
02:00:02:00:98:A5
02:00:02:00:98:AA

Tenha em mente as seguintes considerações antes de aplicar os manifestos:

  • Atualize a senha em cada manifesto.
  • Você precisa inserir uma chave pública SSH válida no campo “ ssh_authorized_keys ” para fazer o login.
  • Não é possível usar o SSH com senha.
  • Substitua todos os valores “ macAddress ” pelo endereço MAC do VNI correspondente que você consultou nos comandos anteriores. O endereço de interface de rede ( macAddress ) deve corresponder ao VNI para que o servidor de nomes de rede ( DHCP ) atribua o endereço IP esperado.

Aplique cada um dos seguintes manifestos com o comando oc apply -f .yml``. Use os links a seguir para acessar diretamente cada manifesto.

Servidor virtual plant-web00 no namespace green em vlan20-prod

# Bare YAML to stand up a Red Hat OpenShift on IBM Cloud virtual machine
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: "plant-web00"
  namespace: "green"
  annotations:
    description: "example vm plant-web00"
  labels:
    app: "plant-web00-green-server"
    kubevirt.io/dynamic-credentials-support: 'true'
    vm.kubevirt.io/template: "centos-stream9-server-small"
    vm.kubevirt.io/template.namespace: openshift
    vm.kubevirt.io/template.revision: '1'
    vm.kubevirt.io/template.version: v0.34.0
spec:
  dataVolumeTemplates:
    - apiVersion: cdi.kubevirt.io/v1beta1
      kind: DataVolume
      metadata:
        creationTimestamp: null
        name: "plant-web00-green-server"
      spec:
        sourceRef:
          kind: DataSource
          name: "centos-stream9"
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  runStrategy: RerunOnFailure
  template:
    metadata:
      annotations:
        vm.kubevirt.io/flavor: "small"
        vm.kubevirt.io/os: "centos-stream9"
        vm.kubevirt.io/workload: "server"
      labels:
        kubevirt.io/domain: example
        kubevirt.io/size: "small"
    spec:
      domain:
        cpu:
          cores: 1
          sockets: 1
          threads: 1
        devices:
          disks:
            - disk:
                bus: virtio
              name: rootdisk
            - disk:
                bus: virtio
              name: cloudinitdisk
          interfaces:
            - model: virtio
              name: default
              state: up
              bridge: {}
              macAddress: 02:00:01:00:98:A0 # <- replace with the MAC of VNI zone1-web00
          networkInterfaceMultiqueue: true
          rng: {}
        memory:
          guest: "2Gi"
      hostname: "plant-web00"
      networks:
        - name: default
          multus:
            networkName: vlan20-prod
      terminationGracePeriodSeconds: 180
      volumes:
        - dataVolume:
            name: "plant-web00-green-server"
          name: rootdisk
        - cloudInitNoCloud:
            userData: |-
              #cloud-config
              user: admin
              password: "aRandomPassword9292"
              ssh_authorized_keys:
                 - "ssh-ed25519 AAAA....BBBB....CCCCC.....DDDD put-your-key-here@example.local"
              chpasswd: { expire: False }
              runcmd:
                - [ dnf, install, -y, epel-release ]
                - [ dnf, install, -y, iperf3, nmap-ncat, darkhttpd ]
          name: cloudinitdisk

Servidor virtual plant-db00 no namespace green em vlan21-db

---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: "plant-db00"
  namespace: "green"
  annotations:
    description: "example vm plant-db00"
  labels:
    app: "plant-db00-green-server"
    kubevirt.io/dynamic-credentials-support: 'true'
    vm.kubevirt.io/template: "centos-stream9-server-small"
    vm.kubevirt.io/template.namespace: openshift
    vm.kubevirt.io/template.revision: '1'
    vm.kubevirt.io/template.version: v0.34.0
spec:
  dataVolumeTemplates:
    - apiVersion: cdi.kubevirt.io/v1beta1
      kind: DataVolume
      metadata:
        creationTimestamp: null
        name: "plant-db00-green-server"
      spec:
        sourceRef:
          kind: DataSource
          name: "centos-stream9"
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  runStrategy: RerunOnFailure
  template:
    metadata:
      annotations:
        vm.kubevirt.io/flavor: "small"
        vm.kubevirt.io/os: "centos-stream9"
        vm.kubevirt.io/workload: "server"
      labels:
        kubevirt.io/domain: example
        kubevirt.io/size: "small"
    spec:
      domain:
        cpu:
          cores: 1
          sockets: 1
          threads: 1
        devices:
          disks:
            - disk:
                bus: virtio
              name: rootdisk
            - disk:
                bus: virtio
              name: cloudinitdisk
          interfaces:
            - model: virtio
              name: default
              state: up
              bridge: {}
              macAddress: 02:00:01:00:98:A5 # <- replace with the MAC of VNI zone1-db00
          networkInterfaceMultiqueue: true
          rng: {}
        memory:
          guest: "2Gi"
      hostname: "plant-db00"
      networks:
        - name: default
          multus:
            networkName: vlan21-db
      terminationGracePeriodSeconds: 180
      volumes:
        - dataVolume:
            name: "plant-db00-green-server"
          name: rootdisk
        - cloudInitNoCloud:
            userData: |-
              #cloud-config
              user: admin
              password: "aRandomPassword9292"
              ssh_authorized_keys:
                 - "ssh-ed25519 AAAA....BBBB....CCCCC.....DDDD put-your-key-here@example.local"
              chpasswd: { expire: False }
              runcmd:
                - [ dnf, install, -y, epel-release ]
                - [ dnf, install, -y, iperf3, nmap-ncat, darkhttpd ]
          name: cloudinitdisk

Servidor virtual plant-app00 no namespace red em vlan22-app

---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: "plant-app00"
  namespace: "red"
  annotations:
    description: "example vm plant-app00"
  labels:
    app: "plant-app00-red-server"
    kubevirt.io/dynamic-credentials-support: 'true'
    vm.kubevirt.io/template: "centos-stream9-server-small"
    vm.kubevirt.io/template.namespace: openshift
    vm.kubevirt.io/template.revision: '1'
    vm.kubevirt.io/template.version: v0.34.0
spec:
  dataVolumeTemplates:
    - apiVersion: cdi.kubevirt.io/v1beta1
      kind: DataVolume
      metadata:
        creationTimestamp: null
        name: "plant-app00-red-server"
      spec:
        sourceRef:
          kind: DataSource
          name: "centos-stream9"
          namespace: openshift-virtualization-os-images
        storage:
          resources:
            requests:
              storage: 30Gi
  runStrategy: RerunOnFailure
  template:
    metadata:
      annotations:
        vm.kubevirt.io/flavor: "small"
        vm.kubevirt.io/os: "centos-stream9"
        vm.kubevirt.io/workload: "server"
      labels:
        kubevirt.io/domain: example
        kubevirt.io/size: "small"
    spec:
      domain:
        cpu:
          cores: 1
          sockets: 1
          threads: 1
        devices:
          disks:
            - disk:
                bus: virtio
              name: rootdisk
            - disk:
                bus: virtio
              name: cloudinitdisk
          interfaces:
            - model: virtio
              name: default
              state: up
              bridge: {}
              macAddress: 02:00:01:00:98:AA # <- replace with the MAC of VNI zone1-app00
          networkInterfaceMultiqueue: true
          rng: {}
        memory:
          guest: "2Gi"
      hostname: "plant-app00"
      networks:
        - name: default
          multus:
            networkName: vlan22-app
      terminationGracePeriodSeconds: 180
      volumes:
        - dataVolume:
            name: "plant-app00-red-server"
          name: rootdisk
        - cloudInitNoCloud:
            userData: |-
              #cloud-config
              user: admin
              password: "aRandomPassword9292"
              ssh_authorized_keys:
                 - "ssh-ed25519 AAAA....BBBB....CCCCC.....DDDD put-your-key-here@example.local"
              chpasswd: { expire: False }
              runcmd:
                - [ dnf, install, -y, epel-release ]
                - [ dnf, install, -y, iperf3, nmap-ncat, darkhttpd ]
          name: cloudinitdisk

Testando a configuração da rede

IBM recomenda que você utilize um host de salto do Linux® na mesma VPC que o cluster para esses testes. No servidor host, use o SSH para se conectar a cada servidor virtual com a chave pública que você especificou na configuração do servidor virtual.

Configure o encaminhamento do agente SSH ou use uma nova chave hospedada no host de trânsito. Não copie sua chave privada entre sistemas.

Em uma sessão de terminal, use o SSH para se conectar ao servidor virtual da camada web:

ssh admin@198.18.0.20

Em outra sessão de terminal, use o SSH para se conectar ao servidor virtual da camada de banco de dados:

ssh admin@198.18.1.20

Em outra sessão de terminal, use o SSH para se conectar ao servidor virtual da camada de aplicativos:

ssh admin@198.18.2.20

Testes

Execute os testes a seguir para verificar a configuração da rede.

  1. Inicie um servidor simples do tipo “ HTTP ” em cada servidor virtual.

    • No site 198.18.0.20, acesse darkhttpd /usr/share/doc/bash --daemon.
    • No site 198.18.1.20, acesse darkhttpd /usr/share/doc/bash --daemon.
    • No site 198.18.2.20, acesse darkhttpd /usr/share/doc/bash --daemon.
  2. No site 198.18.0.20, acesse curl -v http://198.18.1.20:8080.

  3. No site 198.18.1.20, acesse curl -v http://198.18.0.20:8080.

  4. No servidor virtual “jump”, execute curl -v http://198.18.2.20:8080.

  5. No site 198.18.1.20, inicie um servidor iperf3: iperf3 -s -p 9090.

  6. No 198.18.0.20, conecte-se ao servidor iperf3 no namespace green: iperf3 -c 198.18.1.20 -p 9090.

  7. Faça um ping de 198.18.1.20 para 198.18.0.20 e vice-versa.

  8. Execute novamente as tarefas anteriores usando 198.18.2.20 e o endereço IP do servidor virtual jump.

Aplicação de uma política de múltiplas redes e repetição dos testes

Aplique uma política de múltiplas redes que permita apenas o acesso TCP na porta 8080 para a rede vlan20-prod. Salve o manifesto a seguir em um arquivo chamado my-policy.yml. Em seguida, execute o comando oc apply -f my-policy.yml para aplicá-lo.

---
apiVersion: k8s.ovn.org/v1alpha1
kind: MultiNetworkPolicy
metadata:
  name: allow-8080-tcp
  namespace: green
  annotations:
    k8s.v1.cni.cncf.io/policy-for: vlan20-prod
spec:
  podSelector: {}
  ingress:
    - ports:
        - protocol: TCP
          port: 8080
  egress:
    - ports:
        - protocol: TCP
          port: 8080
  policyTypes:
    - Ingress
    - Egress

Execute novamente os testes no endereço plant-web00, disponível em vlan20-prod. TCP A porta 8080 ainda funciona, mas outros tipos de tráfego, como ping e o teste iperf3 na porta 9090, não funcionam mais nessa conexão de rede.

Execute o comando oc delete -f my-policy.yml para remover a política e restaurar a conectividade. Os testes foram aprovados novamente.