Introdução à parte de rede da infraestrutura em nuvem

Introdução à parte de rede da infraestrutura em nuvem

A computação em nuvem está cada vez mais presente em nossas vidas e provavelmente não há uma única pessoa que nunca tenha usado algum serviço em nuvem. Mas o que realmente é a nuvem e como ela funciona, na maioria das vezes, poucas pessoas sabem, mesmo que apenas em termos gerais. O 5G já se tornou uma realidade e a infraestrutura de telecomunicações começa a migrar de soluções tradicionais para soluções em nuvem, assim como ocorreu anteriormente com a transição de soluções totalmente físicas para colunas virtualizadas.

Hoje vamos falar sobre o mundo interno da infraestrutura em nuvem, especificamente sobre os fundamentos da parte de rede.

O que é a nuvem? Seria a mesma coisa que virtualização - uma visão lateral?

Essa é uma pergunta bastante lógica. Não, não é virtualização, embora essa também seja uma parte do processo. Vamos considerar duas definições:

Computação em nuvem (daqui em diante, Nuvem) é um modelo que fornece ao usuário acesso conveniente a recursos computacionais distribuídos, que devem ser implantados e ativos sob demanda, com a menor latência e custo possível para o provedor de serviços.

Virtualização é a possibilidade de dividir uma única entidade física (por exemplo, um servidor) em várias entidades virtuais, aumentando assim a utilização de recursos (por exemplo, você tinha 3 servidores ocupados de 25 a 30 por cento, após a virtualização você obtém 1 servidor utilizado de 80 a 90 por cento). Naturalmente, a virtualização consome parte dos recursos - você precisa alimentar o hipervisor, no entanto, como a prática mostrou, vale a pena. Um exemplo ideal de virtualização é o VMWare, que prepara máquinas virtuais muito bem, ou o KVM, que eu prefiro, mas isso já é uma questão de gosto.

Usamos virtualização sem nem perceber; até mesmo roteadores físicos já utilizam virtualização - por exemplo, nas últimas versões do JunOS, o sistema operacional é executado como uma máquina virtual sobre um sistema Linux em tempo real (Wind River 9). Mas virtualização não é nuvem, no entanto, a nuvem não pode existir sem virtualização.

A virtualização é um dos blocos sobre os quais a nuvem é construída.

Criar uma nuvem simplesmente juntando vários hipervisores em um único domínio L2, acrescentando alguns playbooks YAML para a configuração automática de VLANs através de algum ansible e adicionando a isso algo como um sistema de orquestração para a criação automática de máquinas virtuais — não vai funcionar. Na verdade, até pode funcionar, mas o resultado será um Frankenstein — não é a nuvem que precisamos, embora possa ser o que alguns sonham. Além disso, se pegarmos o OpenStack — que, na essência, também é um Frankenstein, mas deixemos isso de lado por enquanto.

Mas eu entendo que da definição apresentada acima, não está muito claro o que realmente se pode chamar de nuvem.

Portanto, no documento do NIST (Instituto Nacional de Padrões e Tecnologia) estão descritas 5 características principais que uma infraestrutura de nuvem deve possuir:

Prestação de serviço sob demanda. O usuário deve ter acesso livre aos recursos computacionais alocados (como redes, discos virtuais, memória, núcleos de processadores, etc.), e esses recursos devem ser fornecidos automaticamente — ou seja, sem a intervenção do provedor de serviços.

Acessibilidade ampla do serviço. O acesso aos recursos deve ser garantido por mecanismos padrão, permitindo a utilização tanto de PCs convencionais quanto de clientes leves e dispositivos móveis.

Agrupamento de recursos em pools. Os pools de recursos devem garantir a alocação simultânea de recursos a vários clientes, garantindo a isolamento entre eles e a ausência de interferência ou competição pelos recursos. Os pools incluem redes, o que implica a possibilidade de endereçamento sobreposto. Os pools devem suportar escalabilidade sob demanda. O uso de pools permite garantir o nível necessário de resiliência dos recursos e a abstração dos recursos físicos e virtuais — ao cliente é simplesmente oferecido o conjunto de recursos solicitado (onde esses recursos estão fisicamente localizados, em quantos servidores e switches — isso não é da conta do cliente). No entanto, deve-se considerar que o provedor deve assegurar o armazenamento transparente desses recursos.

Adaptação rápida a diferentes condições. Os serviços devem ser flexíveis — fornecimento rápido de recursos, redistribuição, adição ou redução de recursos conforme a solicitação do cliente, de modo que o cliente tenha a impressão de que os recursos da nuvem são infinitos. Para simplificar, por exemplo, você não vê um aviso de que uma parte do espaço em disco no Apple iCloud desapareceu porque o disco rígido no servidor falhou, e os discos realmente falham. Além disso, da sua parte, as capacidades desse serviço são praticamente ilimitadas — se você precisa de 2 TB — sem problemas, pagou e recebeu. Um exemplo semelhante pode ser dado com Google Drive ou Yandex.Disk.

A capacidade de medir o serviço fornecido. Os sistemas em nuvem devem controlar e otimizar automaticamente os recursos consumidos, e esses mecanismos devem ser transparentes tanto para o usuário quanto para o provedor de serviços. Ou seja, você sempre pode verificar quanto recurso você e seus clientes estão consumindo.

É importante considerar o fato de que esses requisitos, na maioria das vezes, são exigências para a nuvem pública, portanto, para a nuvem privada (ou seja, a nuvem executada para as necessidades internas da empresa), esses requisitos podem ser ligeiramente ajustados. No entanto, eles ainda devem ser cumpridos, caso contrário, não obteremos todas as vantagens da computação em nuvem.

Por que precisamos de nuvem?

No entanto, qualquer nova ou já existente tecnologia, qualquer novo protocolo, é criado para um propósito (exceto o RIP-ng, naturalmente). Um protocolo apenas por ser um protocolo — ninguém precisa (exceto o RIP-ng, naturalmente). É lógico que a Nuvem é criada para fornecer algum serviço ao usuário/cliente. Todos nós conhecemos pelo menos alguns serviços em nuvem, como Dropbox ou Google Docs, e suponho que a maioria os utiliza com sucesso — por exemplo, este artigo foi escrito usando o serviço em nuvem Google Docs. Mas os serviços em nuvem que conhecemos são apenas uma parte das possibilidades da nuvem — mais precisamente, são apenas serviços do tipo SaaS. Fornecer um serviço em nuvem pode ser feito de três maneiras: como SaaS, PaaS ou IaaS. Qual serviço você precisa depende dos seus desejos e capacidades.

Vamos analisar cada um na ordem:

Software as a Service (SaaS) — é um modelo de fornecimento de serviços completos ao cliente, como um serviço de e-mail, por exemplo, Yandex.Mail ou Gmail. Nesse modelo de fornecimento, você, como cliente, basicamente não faz nada além de usar o serviço — ou seja, não precisa se preocupar com a configuração, a resiliência ou o backup do serviço. O principal é não comprometer sua senha, tudo o mais será gerenciado pelo provedor do serviço. Do ponto de vista do provedor, ele é totalmente responsável por todo o serviço — desde o hardware do servidor e os sistemas operacionais de hospedagem, até as configurações de banco de dados e software.

Platform as a Service (PaaS) — ao utilizar este modelo, o fornecedor de serviços fornece ao cliente uma base para o serviço, por exemplo, vamos considerar um servidor Web. O fornecedor ofereceu ao cliente um servidor virtual (na verdade um conjunto de recursos, como RAM/CPU/Armazenamento/Redes, etc.), e até mesmo instalou o sistema operacional e software necessários no servidor, no entanto, a configuração de tudo isso é feita pelo próprio cliente e a responsabilidade pela funcionalidade do serviço recai sobre o cliente. O fornecedor, como no caso anterior, é responsável pela operação do hardware físico, hipervisores, da própria máquina virtual, sua acessibilidade na rede, etc., mas o serviço já está fora de sua responsabilidade.

Infrastructure as a Service (IaaS) — essa abordagem é ainda mais interessante, pois o fornecedor fornece ao cliente uma infraestrutura virtualizada completa — ou seja, um conjunto (pool) de recursos, como Núcleos de CPU, RAM, Redes, etc. Todo o restante é responsabilidade do cliente — o que o cliente deseja fazer com esses recursos dentro do pool (quota) que lhe foi atribuído não importa muito para o fornecedor. Se o cliente quiser criar seu próprio vEPC ou até mesmo se tornar um mini operador e oferecer serviços de telecomunicações — sem problemas — vá em frente. Nesse cenário, o fornecedor é responsável por fornecer recursos, sua resiliência e disponibilidade, bem como pelo sistema operacional que permite combinar esses recursos em pools e oferecê-los ao cliente com a possibilidade de aumentar ou diminuir recursos a pedido. Todas as máquinas virtuais e outras configurações são feitas pelo próprio cliente através do portal de autoatendimento e da console, incluindo a configuração de redes (exceto redes externas).

O que é OpenStack?

Em todas as três opções, o provedor de serviços precisa de um sistema operacional que permita criar uma infraestrutura em nuvem. Na prática, no entanto, com SaaS, esse conjunto de tecnologias é gerido por mais de um departamento — há um departamento responsável pela infraestrutura — ou seja, que fornece IaaS a outro departamento, que por sua vez fornece SaaS ao cliente. O OpenStack é um dos sistemas operacionais em nuvem que permite reunir vários comutadores, servidores e sistemas de armazenamento em um único pool de recursos, subdividir esse pool em subpools (tenants) e fornecer esses recursos aos clientes via rede.

OpenStack — é um sistema operacional em nuvem que permite controlar grandes pools de recursos computacionais, armazenamentos de dados e recursos de rede, cujo provisionamento e gerenciamento são realizados via API utilizando mecanismos padrão de autenticação.

Em outras palavras, trata-se de um conjunto de projetos de software livre destinado à criação de serviços em nuvem (tanto públicos quanto privados) — ou seja, um conjunto de ferramentas que permite integrar equipamentos de servidores e comutação em um único pool de recursos, gerenciar esses recursos, garantindo o nível necessário de resiliência.

No momento em que este material foi escrito, a estrutura do OpenStack é a seguinte:
Introdução à parte de rede da infraestrutura em nuvem
A imagem foi retirada de openstack.org

Cada um dos componentes que fazem parte do OpenStack desempenha uma função específica. Essa arquitetura distribuída permite incluir no conjunto as funcionalidades necessárias. No entanto, alguns componentes são considerados fundamentais e sua remoção levará à completa ou parcial inoperabilidade da solução como um todo. Esses componentes incluem:

  • Painel — Interface gráfica baseada em web para gerenciar os serviços do OpenStack
  • Keystone — serviço de identidade centralizado que fornece funcionalidade de autenticação e autorização para outros serviços, além de gerenciar as credenciais dos usuários e seus papéis.
  • Neutron — serviço de rede que fornece conectividade entre as interfaces de vários serviços do OpenStack (incluindo a conectividade entre VMs e o acesso ao mundo exterior)
  • Cinder — fornece acesso ao armazenamento em bloco para máquinas virtuais
  • Nova — gerenciamento do ciclo de vida das máquinas virtuais
  • Glance — repositório de imagens de máquinas virtuais e snapshots
  • Swift — fornece acesso ao armazenamento de objetos
  • Ceilometer — serviço que permite a coleta de telemetria e medição dos recursos existentes e consumidos
  • Heat — orquestração baseada em templates para criação e provisionamento automático de recursos

Você pode visualizar a lista completa de todos os projetos e suas finalidades aqui.

Cada componente do OpenStack é um serviço responsável por uma função específica e fornece uma API para gerenciar essa função e interagir com outros serviços do sistema operacional de nuvem, a fim de criar uma infraestrutura unificada. Por exemplo, Nova gerencia recursos computacionais e fornece uma API para acessar a configuração desses recursos, Glance – para gerenciamento de imagens e API para gerenciá-las, Cinder – armazenamento em bloco e API para gerenciá-lo, etc. Todas as funções estão interligadas de forma muito estreita.

No entanto, se você pensar bem, todos os serviços executados no OpenStack representam, em última instância, alguma máquina virtual (ou contêiner) conectada à rede. Surge a pergunta — por que precisamos de tantos elementos?

Vamos percorrer o algoritmo de criação de uma máquina virtual e conexão dela à rede e ao armazenamento persistente no OpenStack.

  1. Quando você faz um pedido para criar uma máquina, seja por meio do Horizon (Painel de Controle) ou por meio da CLI, a primeira coisa que acontece é a autenticação do seu pedido no Keystone — se você pode criar a máquina, se tem permissão para usar a rede, se o seu projeto tem quota, etc.
  2. Keystone autentica seu pedido e gera um token de autenticação na resposta, que será usado posteriormente. Ao obter a resposta do Keystone, o pedido é enviado para o Nova (nova api).
  3. Nova-api verifica a validade do seu pedido, consultando o Keystone, usando o token de autenticação gerado anteriormente.
  4. Keystone realiza a autenticação e fornece, com base no token de autenticação, informações sobre permissões e restrições.
  5. Nova-api cria um registro da nova VM no banco de dados nova e encaminha o pedido de criação da máquina para o nova-scheduler.
  6. O nova-scheduler seleciona um host (nodo de computação) onde a VM será implantada com base em parâmetros definidos, pesos e zonas. Um registro disso e o identificador da VM são gravados no banco de dados nova.
  7. Em seguida, o nova-scheduler faz uma solicitação ao nova-compute para implantar a instância. O nova-compute se comunica com o nova-conductor para obter informações sobre os parâmetros da máquina (o nova-conductor é um componente do nova que atua como um servidor proxy entre o banco de dados nova e o nova-compute, limitando o número de solicitações ao banco de dados nova para evitar problemas de consistência e reduzir a carga).
  8. O nova-conductor obtém as informações solicitadas do banco de dados nova e as repassa para o nova-compute.
  9. Em seguida, o nova-compute se comunica com o glance para obter o ID da imagem. O glance valida a solicitação no Keystone e retorna as informações solicitadas.
  10. O nova-compute se comunica com o neutron para obter informações sobre os parâmetros da rede. Da mesma forma que o glance, o neutron valida a solicitação no Keystone, após o que cria um registro no banco de dados (identificador da porta etc.), faz uma solicitação para criar a porta e retorna as informações solicitadas ao nova-compute.
  11. O nova-compute se comunica com o cinder para solicitar a alocação de um volume para a máquina virtual. Da mesma forma que o glance, o cinder valida a solicitação no Keystone, cria uma solicitação para criar o volume e retorna as informações solicitadas.
  12. O nova-compute se comunica com o libvirt para solicitar a implantação da máquina virtual com os parâmetros especificados.

Na verdade, parece que uma operação simples de criar uma máquina virtual se transforma em um turbilhão de chamadas de API entre os elementos da plataforma de nuvem. E como você pode ver, mesmo os serviços mencionados anteriormente são compostos por componentes menores, entre os quais ocorre a interação. Criar uma máquina é apenas uma pequena parte do que a plataforma de nuvem permite – há um serviço responsável pelo balanceamento de tráfego, um serviço responsável pelo armazenamento em bloco, um serviço responsável pelo DNS, um serviço responsável pela provisão de servidores bare metal, e assim por diante. A nuvem permite que você trate suas máquinas virtuais como um rebanho de ovelhas (diferente da virtualização). Se algo acontecer com a máquina em um ambiente virtual, você a restaura a partir de backups, etc., já os aplicativos em nuvem são construídos de maneira que a máquina virtual não desempenhe um papel tão importante – a máquina virtual

Naturalmente, deve-se sempre ter em mente que não existe infraestrutura de nuvem sem rede – cada elemento interage com outros elementos de alguma forma através da rede. Além disso, a nuvem possui uma rede absolutamente não estática. É claro que a rede subjacente é mais ou menos estática – não se adicionam novos nós e switches todos os dias; no entanto, a parte overlay pode e inevitavelmente mudará constantemente – novas redes serão adicionadas ou removidas, novas máquinas virtuais surgirão e máquinas antigas desaparecerão. E como você se lembra da definição de nuvem dada no início do artigo – os recursos devem ser alocados ao usuário automaticamente e com o mínimo (ou melhor, sem) intervenção do provedor de serviços. Ou seja, o tipo de fornecimento de recursos de rede que existe agora, na forma de um frontend no seu painel pessoal acessível via http/https e do engenheiro de rede de plantão Vasily como backend – isso não é nuvem, mesmo com Vasily tendo oito braços.

O Neutron, sendo um serviço de rede, fornece uma API para gerenciar a parte de rede da infraestrutura em nuvem. O serviço garante a operação e gestão da parte de rede do OpenStack, oferecendo um nível de abstração chamado Network-as-a-Service (NaaS). Ou seja, a rede é uma unidade virtual mensurável, assim como núcleos virtuais de CPU ou a quantidade de RAM.

Mas antes de avançarmos para a arquitetura da parte de rede do OpenStack, vamos examinar como a rede funciona no OpenStack e por que a rede é uma parte importante e inseparável da nuvem.

Então, temos duas máquinas virtuais do cliente RED e duas máquinas virtuais do cliente GREEN. Suponhamos que essas máquinas estão localizadas em dois hipervisores da seguinte forma:

Introdução à parte de rede da infraestrutura em nuvem

Neste momento, isso é apenas a virtualização de 4 servidores e nada mais, pois até agora tudo que fizemos foi virtualizar 4 servidores, alocando-os em dois servidores físicos. E até agora, eles nem estão conectados à rede.

Para que isso se torne uma nuvem, precisamos adicionar alguns componentes. Primeiro, precisamos virtualizar a parte de rede — precisamos conectar essas 4 máquinas em pares, sendo que os clientes desejam uma conexão L2. Podemos usar um switch e configurar uma trunk para gerenciar tudo através de um linux bridge, ou para usuários mais avançados, openvswitch (que voltaremos a discutir). Mas as redes podem ser muitas, e propagar L2 constantemente através do switch não é a melhor ideia — assim diferentes departamentos, service desk, meses de espera para a execução do pedido, semanas de troubleshooting — no mundo moderno essa abordagem já não funciona. E quanto antes a empresa entender isso, mais fácil será avançar. Portanto, entre os hipervisores, vamos definir uma rede L3 pela qual nossas máquinas virtuais se comunicarão, e sobre essa rede L3 construiremos redes L2 sobrepostas (overlay), onde trafegarão os dados das nossas máquinas virtuais. Podemos usar GRE, Geneve ou VxLAN para encapsulamento. Por enquanto, vamos nos concentrar no último, mesmo que isso não seja tão importante.

Precisamos localizar o VTEP em algum lugar (espero que todos estejam familiarizados com a terminologia VxLAN). Como nossa rede L3 sai imediatamente dos servidores, nada nos impede de situar o VTEP nos próprios servidores, e OVS (OpenvSwitch) faz isso muito bem. No final, obtivemos a seguinte configuração:

Introdução à parte de rede da infraestrutura em nuvem

Como o tráfego entre VMs deve ser dividido, as portas em direção às máquinas virtuais terão diferentes números de VLAN. O número da tag só importa dentro de um switch virtual, uma vez que, ao encapsular em VxLAN, podemos removê-lo sem problemas, pois teremos o VNI.

Introdução à parte de rede da infraestrutura em nuvem

Agora podemos criar nossas máquinas e redes virtuais para elas sem quaisquer problemas.

Mas e se o cliente tiver outra máquina, mas estiver em outra rede? Precisamos de roteamento entre redes. Vamos analisar uma variante simples, quando é utilizado roteamento centralizado — ou seja, o tráfego é roteado através de nós de rede dedicados (normalmente, eles são combinados com nós de controle, então teremos o mesmo).

Parece simples — criamos uma interface bridge no nó de controle, redirecionamos o tráfego para lá e, a partir daí, o roteamos para onde precisamos. Mas o problema é que o cliente RED quer usar a rede 10.0.0.0/24, e o cliente GREEN quer usar a rede 10.0.0.0/24. Ou seja, estamos começando a ter uma sobreposição de endereços. Além disso, os clientes não querem que outros clientes possam ser roteados para suas redes internas, o que faz sentido. Para separar as redes e o tráfego dos clientes, destinaremos um namespace separado para cada um deles. Um namespace é, na verdade, uma cópia da pilha de rede do Linux, ou seja, os clientes no namespace RED estão completamente isolados dos clientes no namespace GREEN (ou o roteamento entre essas redes de clientes é permitido através do namespace default ou já em equipamento de transporte superior).

Portanto, obtemos o seguinte esquema:

Introdução à parte de rede da infraestrutura em nuvem

Túneis L2 convergem de todos os nós computacionais para o nó de controle, onde está localizada a interface L3 para essas redes, cada uma em um namespace dedicado para isolamento.

No entanto, esquecemos o mais importante. A máquina virtual deve fornecer serviço ao cliente, ou seja, ela deve ter pelo menos uma interface externa pela qual possa ser acessada. Precisamos então conectar ao mundo externo. Existem diferentes opções. Vamos fazer a opção mais simples. Vamos adicionar uma rede para cada cliente, que será válida na rede do provedor e não se sobreporá a outras redes. As redes também podem se sobrepor e se conectar a diferentes VRFs do lado da rede do provedor. Essas redes também existirão no namespace de cada cliente. No entanto, elas ainda se conectarão ao mundo externo por meio de uma única interface física (ou um bond, que é mais lógico). Para separar o tráfego dos clientes, o tráfego que sai será identificado por uma etiqueta VLAN específica para o cliente.

No final, obtivemos o seguinte diagrama:

Introdução à parte de rede da infraestrutura em nuvem

Uma pergunta pertinente — por que não criar gateways nas próprias nodes compute? Não há grande problema nisso, além do mais, ao ativar o roteador distribuído (DVR), isso funcionará dessa forma. Neste cenário, consideramos a opção mais simples com um gateway centralizado, que é usado por padrão no OpenStack. Para funções de alta carga, serão utilizados tanto o roteador distribuído quanto tecnologias de aceleração como SR-IOV e Passthrough, mas como dizem, isso já é outra história. Para começar, vamos entender a parte básica e depois nos aprofundaremos nos detalhes.

A nossa configuração já está funcionando, porém há alguns detalhes a considerar:

  • Precisamos proteger nossas máquinas de alguma forma, ou seja, devemos aplicar um filtro na interface do switch voltada para o cliente.
  • Implementar a possibilidade de a máquina virtual obter um endereço IP automaticamente, para não precisarmos acessar a máquina via console e atribuir um endereço manualmente toda vez.

Vamos começar pela proteção das máquinas. Para isso, podemos usar iptables comuns, por que não?

Ou seja, agora nossa topologia já está um pouco mais complexa:

Introdução à parte de rede da infraestrutura em nuvem

Vamos em frente. Precisamos adicionar um servidor DHCP. O lugar mais ideal para posicionar os servidores DHCP para cada cliente será a já mencionada control node, onde os namespaces estão localizados:

Introdução à parte de rede da infraestrutura em nuvem

No entanto, há um pequeno problema. E se tudo reiniciar e todas as informações sobre a locação de endereços no DHCP desaparecerem? É lógico que novos endereços serão atribuídos às máquinas, o que não é muito conveniente. Existem duas opções: usar nomes de domínio e adicionar um servidor DNS para cada cliente, então o endereço não será muito importante para nós (semelhante à parte de rede no k8s) — mas aqui surge uma questão com redes externas, pois nelas os endereços também podem ser atribuídos por DHCP — haverá necessidade de sincronização entre os servidores DNS na plataforma em nuvem e um servidor DNS externo, o que, na minha opinião, não é muito flexível, mas é perfeitamente possível. Ou a segunda opção — usar metadados — ou seja, manter informações sobre o endereço atribuído à máquina para que o servidor DHCP saiba qual endereço atribuir à máquina, caso ela já tenha recebido um. A segunda opção é mais simples e flexível, pois permite armazenar informações adicionais sobre a máquina. Agora, adicionamos à esquema o agente de metadados:

Introdução à parte de rede da infraestrutura em nuvem

Outra questão que também merece ser abordada é a possibilidade de usar uma única rede externa por todos os clientes, já que, se as redes externas precisam ser válidas em toda a rede, haverá uma complexidade — será necessário continuamente alocar e controlar a alocação dessas redes. A possibilidade de utilização de uma única rede externa pré-configurada para todos os clientes será muito útil na criação de uma nuvem pública. Isso simplificará a implantação das máquinas, pois não precisamos consultar um banco de dados de endereços e escolher um espaço de endereços exclusivo para a rede externa de cada cliente. Além disso, podemos definir a rede externa com antecedência e, no momento da implantação, basta associar os endereços externos às máquinas dos clientes.

E aqui o NAT entra em cena — simplesmente permitiremos que os clientes se conectem ao mundo exterior através do namespace padrão usando tradução NAT. Contudo, há um pequeno problema. Isso funciona bem se o servidor do cliente atua como cliente e não como servidor — ou seja, iniciando, e não aceitando conexões. Mas no nosso caso, será o contrário. Nesse caso, precisamos implementar o NAT de destino para que, ao receber o tráfego, o nó de controle entenda que esse tráfego é destinado à máquina virtual A do cliente A, e portanto deve fazer a tradução NAT do endereço externo, por exemplo, 100.1.1.1, para o endereço interno 10.0.0.1. Assim, embora todos os clientes usem a mesma rede, o isolamento interno se mantém completamente. Isso significa que precisamos implementar dNAT e sNAT no nó de controle. A utilização de uma única rede com endereços flutuantes ou redes externas, ou ambos ao mesmo tempo, dependerá do que você deseja levar para a nuvem. Não iremos adicionar endereços flutuantes ao diagrama e manteremos as redes externas já adicionadas anteriormente — cada cliente tem sua própria rede externa (no diagrama, designadas como VLAN 100 e 200 na interface externa).

No final, conseguimos uma solução interessante e ao mesmo tempo bem elaborada, que possui certa flexibilidade, mas ainda não conta com mecanismos de tolerância a falhas.

Primeiramente, temos apenas um nó de controle — a sua falha resultará na derrubada de todos os sistemas. Para resolver esse problema, é necessário ter pelo menos um quórum de 3 nós. Vamos adicionar isso ao diagrama:

Introdução à parte de rede da infraestrutura em nuvem

Naturalmente, todos os nós se sincronizam e, caso um nó ativo falhe, suas funções serão assumidas por outro nó.

O próximo problema são os discos das máquinas virtuais. No momento, eles estão armazenados nos próprios hipervisores e, em caso de problemas com o hipervisor, perdemos todos os dados — e ter RAID aqui não ajuda em nada se perdermos não apenas o disco, mas todo o servidor. Para isso, precisamos criar um serviço que atuará como frontend para algum tipo de armazenamento. Não nos importa muito qual será esse armazenamento, mas ele deve proteger nossos dados contra falhas tanto de disco quanto de nó, e possivelmente até de todo o armário. Existem várias opções — existem redes SAN com Fiber Channel, mas vamos ser honestos — FC é um vestígio do passado — análogo ao E1 no transporte — sim, concordo, ainda é utilizado, mas apenas onde é absolutamente necessário. Portanto, não me voluntariaria para implementar uma rede FC em 2020, ciente da existência de outras alternativas mais interessantes. Embora cada um tenha sua preferência, e podem existir aqueles que acreditam que FC, com todas as suas limitações, é tudo que precisamos — não vou discutir, cada um tem sua opinião. No entanto, a solução que considero mais interessante é o uso de SDS, por exemplo, o Ceph.

O Ceph permite construir uma solução de alta disponibilidade para armazenamento de dados com uma infinidade de opções de redundância, desde códigos com verificação de paridade (análogos ao RAID 5 ou 6) até a replicação total de dados em diferentes discos, levando em consideração a localização dos discos nos servidores e dos servidores nos armários, etc.

Para montar o Ceph, precisamos de mais 3 nós. A interação com o armazenamento será feita também pela rede, utilizando serviços de armazenamento em bloco, objeto e arquivos. Vamos adicionar ao esquema o armazenamento:

Introdução à parte de rede da infraestrutura em nuvem

Nota: também é possível criar nós de computação hiperconvergentes — essa é a ideia de combinar várias funções em um único nó — por exemplo, armazenamento + computação — sem dedicar nós especiais para armazenamento Ceph. Conseguimos um esquema de alta disponibilidade, pois o SDS reservará os dados com o nível de redundância que especificamos. No entanto, nós hiperconvergentes sempre implicam em um compromisso, pois o nó de armazenamento não fica apenas "esquentando o ar", como pode parecer à primeira vista (já que não há máquinas virtuais nele) — ele utiliza recursos de CPU para gerenciar o SDS (na prática, ele está realizando em segundo plano todas as replicações, recuperações de falhas de nós, discos, etc.). Ou seja, você perderá parte da potência do nó de computação se o combinar com armazenamento.

Todo esse conjunto deve ser gerenciado de alguma forma — precisamos de algo que nos permita criar máquinas, redes, roteadores virtuais, etc. Para isso, adicionaremos um serviço ao nó de controle que atuará como um painel — o cliente poderá se conectar a esse portal via http/https e fazer tudo o que precisar (quase tudo).

Como resultado, agora temos um sistema de alta disponibilidade. Todos os elementos dessa infraestrutura precisam ser gerenciados. Foi descrito anteriormente que o OpenStack é um conjunto de projetos, cada um dos quais fornece uma função específica. Como podemos ver, há mais do que elementos suficientes para configurar e controlar. Hoje, falaremos sobre a parte de rede.

Arquitetura Neutron

No OpenStack, o Neutron é responsável por conectar portas de máquinas virtuais à rede L2 comum, garantindo o roteamento de tráfego entre VMs em diferentes redes L2 e também roteamento externo, fornecendo serviços como NAT, IP flutuante, DHCP, etc.

O funcionamento do serviço de rede em um nível alto (parte básica) pode ser descrito assim.

Ao iniciar uma VM, o serviço de rede:

  1. Cria uma porta para essa VM (ou portas) e notifica o serviço DHCP;
  2. Um novo dispositivo de rede virtual é criado (por meio do libvirt);
  3. A VM conecta-se à porta criada na etapa 1 (ou portas);

Curiosamente, a base do funcionamento do Neutron se baseia em mecanismos padrão, conhecidos por todos que já se imergiram no Linux — são namespaces, iptables, bridges do Linux, openvswitch, conntrack, etc.

É importante esclarecer imediatamente que o Neutron não é um controlador SDN.

O Neutron consiste em vários componentes interconectados:

Introdução à parte de rede da infraestrutura em nuvem

Openstack-neutron-server — é um daemon que opera com solicitações de usuários através da API. Este daemon não estabelece conexões de rede, mas fornece as informações necessárias para seus plugins, que em seguida configuram o elemento de rede desejado. Os agentes Neutron nos nós do OpenStack se registram no servidor Neutron.

O Neutron-server é, na verdade, um aplicativo escrito em Python, composto por duas partes:

  • Serviço REST
  • Plugin Neutron (núcleo/serviço)

O serviço REST é destinado a receber chamadas da API de outros componentes (por exemplo, solicitações para fornecer alguma informação, etc.)

Os plugins são componentes/modulos de software que são chamados durante solicitações da API — ou seja, a atribuição de algum serviço acontece através deles. Os plugins se dividem em dois tipos — plugin de serviço e plugin núcleo. Em geral, o plugin núcleo é responsável principalmente pela gestão do espaço de endereçamento e das conexões L2 entre VM, enquanto os plugins de serviço oferecem funcionalidades adicionais como VPN ou FW.

A lista de plugins disponíveis hoje pode ser vista, por exemplo, aqui

Pode haver vários plugins de serviço, no entanto, pode haver apenas um plugin núcleo.

Openstack-neutron-ml2 — é o plugin núcleo padrão do OpenStack. Este plugin possui uma arquitetura modular (diferente de seu predecessor) e através de drivers conectáveis realiza a configuração do serviço de rede. O próprio plugin será discutido um pouco mais tarde, pois, na verdade, ele oferece a flexibilidade que o OpenStack possui na parte de rede. O plugin núcleo pode ser substituído (por exemplo, a Contrail Networking faz essa substituição).

Serviço RPC (rabbitmq-server) — serviço que fornece gerenciamento de filas e interação com outros serviços do OpenStack, bem como a interação entre agentes do serviço de rede.

Agentes de rede — agentes que estão localizados em cada nó, através dos quais a configuração dos serviços de rede é realizada.

Os agentes vêm em vários tipos.

O agente principal é o Agente L2. Esses agentes são iniciados em cada um dos hypervisores, incluindo os nós de controle (mais especificamente, em todos os nós que oferecem algum serviço para os inquilinos) e sua função principal é conectar máquinas virtuais à rede L2 comum, além de gerar alertas ao ocorrer qualquer evento (por exemplo, desligamento/licenciamento de porta).

O próximo agente, não menos importante, é Agente L3. Por padrão, este agente é executado exclusivamente no nó de rede (muitas vezes o nó de rede é combinado com o nó de controle) e garante a roteamento entre as redes dos inquilinos (tanto entre suas próprias redes e redes de outros inquilinos, quanto disponível para o mundo exterior, oferecendo NAT e também o serviço DHCP). No entanto, ao utilizar DVR (roteador distribuído), a necessidade de um plug-in L3 surge também nos nós de computação.

O agente L3 utiliza namespaces do Linux para fornecer a cada inquilino um conjunto de redes isoladas próprias e a funcionalidade de roteadores virtuais, que roteiam o tráfego e oferecem serviços de gateway para redes de Camada 2.

Banco de dados — um banco de dados de identificadores de redes, sub-redes, portas, pools, etc.

Na verdade, o Neutron aceita solicitações de API para a criação de qualquer entidade de rede, autentica a solicitação e, através de RPC (se contatando com algum plug-in ou agente) ou REST API (se comunicando no SDN), transmite aos agentes (via plug-ins) as instruções necessárias para organizar o serviço solicitado.

Agora, vamos nos voltar para a instalação de teste (como ela foi implantada e o que a compõe veremos mais tarde na parte prática) e verificar onde cada componente está localizado:

(overcloud) [stack@undercloud ~]$ openstack network agent list  
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| ID                                   | Tipo de Agente     | Host                                | Zona de Disponibilidade | Vivo  | Estado | Binário                  |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| 10495de9-ba4b-41fe-b30a-b90ec3f8728b | Agente Open vSwitch | overcloud-novacompute-1.localdomain | Nenhum            | :-)   | ATIVO | neutron-openvswitch-agent |
| 1515ad4a-5972-46c3-af5f-e5446dff7ac7 | Agente L3           | overcloud-controller-0.localdomain  | nova              | :-)   | ATIVO | neutron-l3-agent          |
| 322e62ca-1e5a-479e-9a96-4f26d09abdd7 | Agente DHCP         | overcloud-controller-0.localdomain  | nova              | :-)   | ATIVO | neutron-dhcp-agent        |
| 9c1de2f9-bac5-400e-998d-4360f04fc533 | Agente Open vSwitch | overcloud-novacompute-0.localdomain | Nenhum            | :-)   | ATIVO | neutron-openvswitch-agent |
| d99c5657-851e-4d3c-bef6-f1e3bb1acfb0 | Agente Open vSwitch | overcloud-controller-0.localdomain  | Nenhum            | :-)   | ATIVO | neutron-openvswitch-agent |
| ff85fae6-5543-45fb-a301-19c57b62d836 | Agente de Metadados | overcloud-controller-0.localdomain  | Nenhum            | :-)   | ATIVO | neutron-metadata-agent    |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
(overcloud) [stack@undercloud ~]$ 

Introdução à parte de rede da infraestrutura em nuvem

Aqui está toda a estrutura do Neutron. Agora vale a pena dedicar um tempo ao plugin ML2.

Modular Layer 2

Como já mencionado, o plugin é o plugin raiz padrão do OpenStack e possui uma arquitetura modular.

O precursor do plugin ML2 tinha uma estrutura monolítica, o que não permitia, por exemplo, usar uma mistura de várias tecnologias em uma única instalação. Por exemplo, você não podia usar openvswitch e linuxbridge ao mesmo tempo — ou um, ou o outro. Por essa razão, o plugin ML2 foi criado com a sua arquitetura.

O ML2 possui duas componentes — dois tipos de drivers: Type drivers e Mechanism drivers.

Type drivers definem as tecnologias que serão usadas para organizar as conexões de rede, como VxLAN, VLAN, GRE. Ao mesmo tempo, o driver permite o uso de diferentes tecnologias. A tecnologia padrão é a encapsulação VxLAN para redes overlay e vlan para redes externas.

Os seguintes tipos de redes são classificados como Type drivers:

Flat — rede sem etiquetagem
VLAN — rede etiquetada
Local — tipo especial de rede para instalações do tipo all-in-one (esse tipo de instalação é necessário para desenvolvedores ou para treinamento)
GRE — rede overlay que utiliza túneis GRE
VxLAN — rede overlay que utiliza túneis VxLAN

Mechanism drivers definem os meios que garantem a organização das tecnologias especificadas no tipo de driver — por exemplo, openvswitch, sr-iov, opendaylight, OVN, etc.

Dependendo da implementação deste driver, serão utilizados agentes que são gerenciados pelo Neutron ou serão utilizadas conexões com um controlador SDN externo, que assume todas as questões relacionadas à organização das redes L2, roteamento, etc.

Por exemplo, se utilizamos ML2 junto com OVS, então em cada nó de computação um agente L2 é instalado, que gerencia o OVS. No entanto, se utilizarmos, por exemplo, OVN ou OpenDayLight, o gerenciamento do OVS passa para a jurisdição deles — o Neutron através do plugin raiz envia comandos ao controlador, que executa o que foi solicitado.

Vamos relembrar o Open vSwitch

Atualmente, um dos componentes-chave do OpenStack é o Open vSwitch.
Ao instalar o OpenStack sem qualquer tipo de SDN de fornecedor adicional, como Juniper Contrail ou Nokia Nuage, o OVS é o principal componente de rede da rede em nuvem e, em conjunto com iptables, conntrack, namespaces, permite a organização de redes overlays completas com multi-tenancy. Naturalmente, esse componente pode ser substituído, por exemplo, ao utilizar soluções SDN proprietárias de terceiros.

OVS é um switch de software de código aberto, projetado para uso em ambientes virtualizados como um encaminhador de tráfego virtual.

Atualmente, o OVS possui um funcionalidade bastante robusta, que inclui tecnologias como QoS, LACP, VLAN, VxLAN, GENEVE, OpenFlow, DPDK etc.

Nota: originalmente, o OVS não foi concebido como um switch de software para funções de telecomunicações de alta carga e era mais voltado para funções de TI que exigem menos largura de banda, como servidores WEB ou servidores de email. No entanto, o OVS está sendo aprimorado e as implementações atuais do OVS melhoraram significativamente seu desempenho e capacidades, permitindo seu uso por operadores de telecomunicações em funções de alta carga, por exemplo, existe uma implementação do OVS com suporte para aceleração DPDK.

Existem três componentes importantes do OVS que você precisa conhecer:

  • Módulo do kernel — um componente localizado no espaço do kernel, que processa o tráfego com base nas regras recebidas do elemento de controle;
  • vSwitch O daemon (ovs-vswitchd) é um processo executado no espaço do usuário, responsável pela programação do módulo do kernel, ou seja, representa diretamente a lógica de operação do switch.
  • Servidor de banco de dados — um banco de dados local, localizado em cada host onde o OVS está em execução, que armazena a configuração. Por meio deste módulo, controladores SDN podem se comunicar usando o protocolo OVSDB.

Além disso, vem acompanhado de um conjunto de utilitários de diagnóstico e gerenciamento, como ovs-vsctl, ovs-appctl, ovs-ofctl, etc.

Atualmente, o OpenStack é amplamente utilizado por operadores de telecomunicações para migrar suas funções de rede, como EPC, SBC, HLR, etc. Algumas funções podem operar sem problemas com o OVS da forma como está, mas o EPC, por exemplo, processa o tráfego dos assinantes — ou seja, transmite uma quantidade enorme de tráfego (atualmente, volumes de tráfego atingem centenas de gigabits por segundo). Naturalmente, enviar esse tráfego pelo espaço do kernel (já que por padrão o encaminhador está localizado lá) não é a melhor ideia. Portanto, muitas vezes o OVS é inteiramente implementado no espaço do usuário com o uso da tecnologia de aceleração DPDK para redirecionar o tráfego da NIC para o espaço do usuário, evitando o kernel.

Nota: para a nuvem implantada para funções de telecomunicações, há a possibilidade de direcionar o tráfego da unidade de computação diretamente para o equipamento de comutação, evitando o OVS. Para isso, são utilizados mecanismos SR-IOV e Passthrough.

Como isso funciona em um modelo real?

Agora vamos para a parte prática e ver como tudo isso funciona na prática.

Para começar, vamos implantar uma simples instalação do OpenStack. Como não tenho um conjunto de servidores para experimentos à mão, vamos construir o modelo em um único servidor físico usando máquinas virtuais. Sim, é claro que essa solução não é adequada para fins comerciais, mas para ver, através de um exemplo, como a rede funciona no OpenStack, essa instalação é mais do que suficiente. Além disso, essa instalação é até mais interessante para fins de aprendizado — já que podemos capturar o tráfego, etc.

Como precisamos ver apenas a parte básica, podemos usar apenas duas redes, onde a segunda rede neste modelo será usada exclusivamente para acesso ao undercloud e ao servidor DNS. Redes externas não serão abordadas por enquanto — esse será o tema de um grande artigo separado.

Então, vamos começar pela ordem. Primeiro, um pouco de teoria. Vamos instalar o Openstack com o auxílio do TripleO (Openstack sobre Openstack). O conceito por trás do TripleO é que instalamos o Openstack all-in-one (ou seja, em um único nó), chamado de undercloud, e então utilizamos as capacidades do Openstack implantado para instalar o Openstack destinado à produção, chamado de overcloud. O undercloud utilizará a capacidade embutida de gerenciar servidores físicos (bare metal) — o projeto Ironic — para provisionar hipervisores que desempenharão os papéis de nodos compute, control e storage. Ou seja, não utilizamos nenhuma ferramenta externa para implantar o Openstack — estamos implantando o Openstack com os próprios recursos do Openstack. Ao longo da instalação, isso ficará muito mais claro, então não vamos nos deter nisso e seguir em frente.

Nota: Neste artigo, para simplificar, eu não usei isolamento de rede para as redes internas do Openstack, e tudo foi implantado utilizando apenas uma rede. No entanto, a presença ou ausência de isolamento de redes não afeta a funcionalidade básica da solução — tudo funcionará exatamente da mesma forma que com o isolamento, mas o tráfego estará em uma única rede. Para uma instalação comercial, é claro que é necessário usar isolamento com diferentes VLANs e interfaces. Por exemplo, o tráfego de gerenciamento do armazenamento Ceph e o tráfego diretamente dados (acessos das máquinas aos discos, etc.) ao usar isolamento utilizam subredes diferentes (Storage management e Storage), o que torna a solução mais resistente a falhas, dividindo esse tráfego, por exemplo, em diferentes portas, ou utilizando diferentes perfis de QoS para diferentes tipos de tráfego, a fim de garantir que o tráfego de dados não sobrecarregue o tráfego de sinalização. No nosso caso, eles estarão na mesma rede e, na prática, isso não nos limita.

Nota: Como estamos prestes a executar máquinas virtuais em um ambiente virtual baseado em máquinas virtuais, primeiro precisamos ativar a virtualização aninhada.

Você pode verificar se a virtualização aninhada está ativada ou não assim:


[root@hp-gen9 bormoglotx]# cat /sys/module/kvm_intel/parameters/nested
N
[root@hp-gen9 bormoglotx]# 

Se você vê a letra N, ative o suporte à virtualização aninhada de qualquer guia que encontrar na rede, por exemplo, uma .

Precisamos montar um esquema como o seguinte a partir das máquinas virtuais:

Introdução à parte de rede da infraestrutura em nuvem

No meu caso, para a conectividade das máquinas virtuais que fazem parte da futura instalação (e eu tenho 7, mas você pode se sair com 4 se não tiver muitos recursos), eu usei o OpenvSwitch. Criei um brinde ovs e conectei as máquinas virtuais a ele através de port-groups. Para isso, criei um arquivo XML do seguinte formato:


[root@hp-gen9 ~]# virsh net-dumpxml ovs-network-1        

  ovs-network-1
  7a2e7de7-fc16-4e00-b1ed-4d190133af67

Aqui estão declarados três grupos de portas — duas access e uma trunk (a última era necessária para o servidor DNS, mas você pode ficar sem, ou configurá-lo na máquina host — depende do que for mais conveniente para você). Em seguida, usando este modelo, definimos nossa rede através do virsh net-define:


virsh net-define ovs-network-1.xml 
virsh net-start ovs-network-1 
virsh net-autostart ovs-network-1 

Agora vamos ajustar as configurações das portas do hipervisor:


[root@hp-gen9 ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens1f0   
TYPE=Ethernet
NAME=ens1f0
DEVICE=ens1f0
TYPE=OVSPort
DEVICETYPE=ovs
OVS_BRIDGE=ovs-br1
ONBOOT=yes
OVS_OPTIONS="trunk=100,101,102"
[root@hp-gen9 ~]
[root@hp-gen9 ~]# cat /etc/sysconfig/network-scripts/ifcfg-ovs-br1 
DEVICE=ovs-br1
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
ONBOOT=yes
IPADDR=192.168.255.200
PREFIX=24
[root@hp-gen9 ~]# 

Nota: neste cenário, o endereço na porta ovs-br1 não estará acessível, pois não possui uma tag VLAN. Para corrigir isso, execute o comando sudo ovs-vsctl set port ovs-br1 tag=100. No entanto, após a reinicialização, essa tag desaparecerá (se alguém souber como fazer para que ela permaneça — ficarei muito agradecido). Mas isso não é tão importante, pois esse endereço será necessário apenas durante a instalação e não será preciso quando o Openstack estiver totalmente deployado.

Em seguida, criamos a máquina undercloud:


virt-install  -n undercloud --description "undercloud"  --os-type=Linux  --os-variant=centos7.0  --ram=8192  --vcpus=8  --disk path=/var/lib/libvirt/images/undercloud.qcow2,bus=virtio,size=40,format=qcow2 --network network:ovs-network-1,model=virtio,portgroup=access-100 --network network:ovs-network-1,model=virtio,portgroup=access-101 --graphics none  --location /var/lib/libvirt/boot/CentOS-7-x86_64-Minimal-2003.iso --extra-args console=ttyS0

Durante a instalação, você define todos os parâmetros necessários, como o nome da máquina, senhas, usuários, servidores NTP, etc. É possível configurar as portas imediatamente, mas pessoalmente, acho mais fácil entrar na máquina via console e ajustar os arquivos necessários depois da instalação. Se você já tiver uma imagem pronta, pode usá-la ou seguir meu exemplo: baixar uma imagem mínima do CentOS 7 e usá-la para a instalação da VM.

Após uma instalação bem-sucedida, você deve ter uma máquina virtual na qual pode instalar o undercloud.


[root@hp-gen9 bormoglotx]# virsh list
 Id    Name                           State
----------------------------------------------------
 6     dns-server                     running
 62    undercloud                     running

Primeiro, instalamos as ferramentas necessárias para o processo de instalação:

sudo yum update -y
sudo yum install -y net-tools
sudo yum install -y wget
sudo yum install -y ipmitool

Instalação do Undercloud

Criamos o usuário stack, definimos uma senha, adicionamos ao sudoer e damos a ele a possibilidade de executar comandos como root via sudo sem a necessidade de inserir a senha:


useradd stack
passwd stack

echo "stack ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/stack
chmod 0440 /etc/sudoers.d/stack

Agora, especificamos no arquivo hosts o nome completo do undercloud:


vi /etc/hosts

127.0.0.1   undercloud.openstack.rnd localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

Em seguida, adicionamos os repositórios e instalamos o software necessário:


sudo yum install -y https://trunk.rdoproject.org/centos7/current/python2-tripleo-repos-0.0.1-0.20200409224957.8bac392.el7.noarch.rpm
sudo -E tripleo-repos -b queens current
sudo -E tripleo-repos -b queens current ceph
sudo yum install -y python-tripleoclient
sudo yum install -y ceph-ansible

Nota: se você não planeja instalar o ceph, não é necessário inserir os comandos relacionados ao ceph. Usei a versão Queens, mas você pode usar qualquer outra que preferir.

Em seguida, copiamos o arquivo de configuração do undercloud para o diretório home do usuário stack:


cp /usr/share/instack-undercloud/undercloud.conf.sample ~/undercloud.conf

Agora é necessário ajustar este arquivo, adaptando-o à nossa instalação.

No início do arquivo, adicione as seguintes linhas:

vi undercloud.conf
[DEFAULT]
undercloud_hostname = undercloud.openstack.rnd
local_ip = 192.168.255.1/24
network_gateway = 192.168.255.1
undercloud_public_host = 192.168.255.2
undercloud_admin_host = 192.168.255.3
undercloud_nameservers = 192.168.255.253
generate_service_certificate = false
local_interface = eth0
local_mtu = 1450
network_cidr = 192.168.255.0/24
masquerade = true
masquerade_network = 192.168.255.0/24
dhcp_start = 192.168.255.11
dhcp_end = 192.168.255.50
inspection_iprange = 192.168.255.51,192.168.255.100
scheduler_max_attempts = 10

Agora, vamos passar pelas configurações:

undercloud_hostname — nome completo do servidor undercloud, deve coincidir com o registro no servidor DNS

local_ip — endereço local do undercloud para a rede de provisionamento

network_gateway — este é o mesmo endereço local que atuará como gateway para acesso ao mundo exterior durante a instalação dos nós overcloud, também coincide com o IP local

undercloud_public_host — endereço da API externa, pode ser qualquer endereço livre da rede de provisionamento

undercloud_admin_host endereço da API interna, pode ser qualquer endereço livre da rede de provisionamento

undercloud_nameservers — servidor DNS

generate_service_certificate — esta linha é muito importante no exemplo atual, pois se não for definida como false você receberá um erro durante a instalação, o problema é descrito no bug tracker da Red Hat

local_interface interface na rede de provisionamento. Esta interface será reconfigurada durante a instalação do undercloud, portanto, o undercloud deve ter duas interfaces — uma para acesso a ele, a outra para provisionamento

local_mtu — MTU. Como temos um laboratório de testes e o MTU é 1500 nas portas do switch OVS, é necessário definir como 1450 para que pacotes encapsulados em VxLAN possam passar

network_cidr — rede de provisionamento

masquerade — uso de NAT para acesso à rede externa

masquerade_network — rede que será NAT-ed

dhcp_start — endereço inicial do pool de endereços, a partir do qual os endereços serão atribuídos aos nós durante o deploy do overcloud

dhcp_end — endereço final do pool de endereços, a partir do qual os endereços serão atribuídos aos nós durante o deploy do overcloud

inspection_iprange — pool de endereços necessários para realizar a inspeção (não deve sobrepor-se ao pool mencionado acima)

scheduler_max_attempts — número máximo de tentativas de instalação do overcloud (deve ser maior ou igual ao número de nós)

Depois que o arquivo está descrito, você pode dar o comando para implantar o undercloud:


openstack undercloud install

O procedimento leva de 10 a 30 minutos, dependendo do seu hardware. No final, você deve ver a seguinte saída:

vi undercloud.conf
2020-08-13 23:13:12,668 INFO: 
#############################################################################
Instalação do Undercloud completa.

O arquivo contendo as senhas desta instalação está em
/home/stack/undercloud-passwords.conf.

Há também um arquivo stackrc em /home/stack/stackrc.

Esses arquivos são necessários para interagir com os serviços do OpenStack e devem ser
protegidos.

#############################################################################

Esta saída indica que você instalou o undercloud com sucesso e agora pode verificar o estado do undercloud e prosseguir com a instalação do overcloud.

Se você olhar a saída do ifconfig, verá que uma nova interface de bridge apareceu

[stack@undercloud ~]$ ifconfig
br-ctlplane: flags=4163  mtu 1450
        inet 192.168.255.1  netmask 255.255.255.0  broadcast 192.168.255.255
        inet6 fe80::5054:ff:fe2c:89e  prefixlen 64  scopeid 0x20
        ether 52:54:00:2c:08:9e  txqueuelen 1000  (Ethernet)
        RX packets 14  bytes 1095 (1.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 20  bytes 1292 (1.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Agora, este interface será usado para o deployment do overcloud.

A partir da saída abaixo, podemos ver que todos os serviços estão em um único nó:

(undercloud) [stack@undercloud ~]$ openstack host list
+--------------------------+-----------+----------+
| Host Name                | Service   | Zone     |
+--------------------------+-----------+----------+
| undercloud.openstack.rnd | conductor | internal |
| undercloud.openstack.rnd | scheduler | internal |
| undercloud.openstack.rnd | compute   | nova     |
+--------------------------+-----------+----------+

Abaixo está a configuração da parte de rede do undercloud:


(undercloud) [stack@undercloud ~]$ python -m json.tool /etc/os-net-config/config.json 
{
    "network_config": [
        {
            "addresses": [
                {
                    "ip_netmask": "192.168.255.1/24"
                }
            ],
            "members": [
                {
                    "dns_servers": [
                        "192.168.255.253"
                    ],
                    "mtu": 1450,
                    "name": "eth0",
                    "primary": "true",
                    "type": "interface"
                }
            ],
            "mtu": 1450,
            "name": "br-ctlplane",
            "ovs_extra": [
                "br-set-external-id br-ctlplane bridge-id br-ctlplane"
            ],
            "routes": [],
            "type": "ovs_bridge"
        }
    ]
}
(undercloud) [stack@undercloud ~]$

Instalação do overcloud

Neste momento, temos apenas o undercloud e precisamos de nós que formarão o overcloud. Portanto, primeiro, vamos implantar as máquinas virtuais necessárias. Durante o deployment, o undercloud instalará o sistema operacional e o software necessário nas máquinas do overcloud — ou seja, não precisamos implantar a máquina completamente, apenas criar um disco (ou discos) e definir seus parâmetros — recebendo, de fato, um servidor em branco sem sistema operacional instalado.

Vamos para a pasta com os discos das nossas máquinas virtuais e criaremos os discos do tamanho necessário:


cd /var/lib/libvirt/images/
qemu-img create -f qcow2 -o preallocation=metadata control-1.qcow2 60G
qemu-img create -f qcow2 -o preallocation=metadata compute-1.qcow2 60G
qemu-img create -f qcow2 -o preallocation=metadata compute-2.qcow2 60G
qemu-img create -f qcow2 -o preallocation=metadata storage-1.qcow2 160G
qemu-img create -f qcow2 -o preallocation=metadata storage-2.qcow2 160G

Como estamos agindo como root, precisamos alterar a propriedade desses discos para evitar problemas de permissão:


[root@hp-gen9 images]# ls -lh
total 5.8G
drwxr-xr-x. 2 qemu qemu 4.0K Aug 13 16:15 backups
-rw-r--r--. 1 root root  61G Aug 14 03:07 compute-1.qcow2
-rw-r--r--. 1 root root  61G Aug 14 03:07 compute-2.qcow2
-rw-r--r--. 1 root root  61G Aug 14 03:07 control-1.qcow2
-rw-------. 1 qemu qemu  41G Aug 14 03:03 dns-server.qcow2
-rw-r--r--. 1 root root 161G Aug 14 03:07 storage-1.qcow2
-rw-r--r--. 1 root root 161G Aug 14 03:07 storage-2.qcow2
-rw-------. 1 qemu qemu  41G Aug 14 03:07 undercloud.qcow2
[root@hp-gen9 images]# 
[root@hp-gen9 images]# 
[root@hp-gen9 images]# chown qemu:qemu /var/lib/libvirt/images/*qcow2
[root@hp-gen9 images]# ls -lh
total 5.8G
drwxr-xr-x. 2 qemu qemu 4.0K Aug 13 16:15 backups
-rw-r--r--. 1 qemu qemu  61G Aug 14 03:07 compute-1.qcow2
-rw-r--r--. 1 qemu qemu  61G Aug 14 03:07 compute-2.qcow2
-rw-r--r--. 1 qemu qemu  61G Aug 14 03:07 control-1.qcow2
-rw-------. 1 qemu qemu  41G Aug 14 03:03 dns-server.qcow2
-rw-r--r--. 1 qemu qemu 161G Aug 14 03:07 storage-1.qcow2
-rw-r--r--. 1 qemu qemu 161G Aug 14 03:07 storage-2.qcow2
-rw-------. 1 qemu qemu  41G Aug 14 03:08 undercloud.qcow2
[root@hp-gen9 images]# 

Nota: se você não planeja instalar o ceph para fins de estudo, não crie comandos com pelo menos 3 nós com pelo menos dois discos, e no template indique que serão utilizados discos virtuais vda, vdb, etc.

Ótimo, agora precisamos definir todas essas máquinas:


virt-install --name control-1 --ram 32768 --vcpus 8 --os-variant centos7.0 --disk path=/var/lib/libvirt/images/control-1.qcow2,device=disk,bus=virtio,format=qcow2 --noautoconsole --vnc  --network network:ovs-network-1,model=virtio,portgroup=access-100 --network network:ovs-network-1,model=virtio,portgroup=trunk-1 --dry-run --print-xml > /tmp/control-1.xml  

virt-install --name storage-1 --ram 16384 --vcpus 4 --os-variant centos7.0 --disk path=/var/lib/libvirt/images/storage-1.qcow2,device=disk,bus=virtio,format=qcow2 --noautoconsole --vnc  --network network:ovs-network-1,model=virtio,portgroup=access-100 --dry-run --print-xml > /tmp/storage-1.xml  

virt-install --name storage-2 --ram 16384 --vcpus 4 --os-variant centos7.0 --disk path=/var/lib/libvirt/images/storage-2.qcow2,device=disk,bus=virtio,format=qcow2 --noautoconsole --vnc  --network network:ovs-network-1,model=virtio,portgroup=access-100 --dry-run --print-xml > /tmp/storage-2.xml  

virt-install --name compute-1 --ram 32768 --vcpus 12 --os-variant centos7.0 --disk path=/var/lib/libvirt/images/compute-1.qcow2,device=disk,bus=virtio,format=qcow2 --noautoconsole --vnc  --network network:ovs-network-1,model=virtio,portgroup=access-100 --dry-run --print-xml > /tmp/compute-1.xml  

virt-install --name compute-2 --ram 32768 --vcpus 12 --os-variant centos7.0 --disk path=/var/lib/libvirt/images/compute-2.qcow2,device=disk,bus=virtio,format=qcow2 --noautoconsole --vnc  --network network:ovs-network-1,model=virtio,portgroup=access-100 --dry-run --print-xml > /tmp/compute-2.xml 

No final, há comandos —print-xml > /tmp/storage-1.xml, que criam um arquivo xml com a descrição de cada máquina na pasta /tmp/, se não adicionar, não conseguirá identificar as máquinas virtuais.

Agora precisamos definir todas essas máquinas no virsh:


virsh define --file /tmp/control-1.xml
virsh define --file /tmp/compute-1.xml
virsh define --file /tmp/compute-2.xml
virsh define --file /tmp/storage-1.xml
virsh define --file /tmp/storage-2.xml

[root@hp-gen9 ~]# virsh list --all
 Id    Name                           State
----------------------------------------------------
 6     dns-server                     em funcionamento
 64    undercloud                     em funcionamento
 -     compute-1                      desligado
 -     compute-2                      desligado
 -     control-1                      desligado
 -     storage-1                      desligado
 -     storage-2                      desligado

[root@hp-gen9 ~]#

Agora, um pequeno detalhe — o tripleO utiliza IPMI para gerenciar servidores durante a instalação e introspecção.

A introspecção é o processo de inspeção do hardware para obter seus parâmetros necessários para o provisionamento futuro dos nós. A introspecção é realizada com o Ironic — um serviço destinado a trabalhar com servidores bare metal.

Mas aqui está o problema — se para servidores físicos o IPMI é uma porta separada (ou uma porta compartilhada, mas isso não é o principal), as máquinas virtuais não têm essas portas. Aqui, um paliativo chamado vbmc nos ajuda — uma ferramenta que permite emular uma porta IPMI. Este detalhe deve ser especialmente considerado por aqueles que desejam montar um laboratório em um hipervisor ESXI — não sei se há um análogo ao vbmc, portanto, é melhor preocupar-se com essa questão antes de implementar tudo.

Instalando o vbmc:


yum install python2-virtualbmc

Se o seu sistema operacional não conseguir encontrar o pacote, adicione o repositório:

yum install -y https://www.rdoproject.org/repos/rdo-release.rpm

Agora, vamos configurar a ferramenta. Aqui é tudo muito simples. Neste momento, é lógico que na lista do vbmc não há servidores.


[root@hp-gen9 ~]# vbmc list

[root@hp-gen9 ~]# 

Para que eles apareçam, é necessário declarar manualmente dessa forma:


[root@hp-gen9 ~]# vbmc add control-1 --port 7001 --username admin --password admin
[root@hp-gen9 ~]# vbmc add storage-1 --port 7002 --username admin --password admin
[root@hp-gen9 ~]# vbmc add storage-2 --port 7003 --username admin --password admin
[root@hp-gen9 ~]# vbmc add compute-1 --port 7004 --username admin --password admin
[root@hp-gen9 ~]# vbmc add compute-2 --port 7005 --username admin --password admin
[root@hp-gen9 ~]#
[root@hp-gen9 ~]# vbmc list
+-------------+--------+---------+------+
| Nome do domínio | Status | Endereço | Porta |
+-------------+--------+---------+------+
| compute-1   | desligado   | ::      | 7004 |
| compute-2   | desligado   | ::      | 7005 |
| control-1   | desligado   | ::      | 7001 |
| storage-1   | desligado   | ::      | 7002 |
| storage-2   | desligado   | ::      | 7003 |
+-------------+--------+---------+------+
[root@hp-gen9 ~]#

Acredito que a sintaxe do comando é clara e não precisa de explicações. No entanto, por enquanto, todas as nossas sessões estão com status DOWN. Para que elas mudem para STATUS UP, é necessário ligá-las:


[root@hp-gen9 ~]# vbmc start control-1
2020-08-14 03:15:57,826.826 13149 INFO VirtualBMC [-] Instância do vBMC iniciada para o domínio control-1
[root@hp-gen9 ~]# vbmc start storage-1 
2020-08-14 03:15:58,316.316 13149 INFO VirtualBMC [-] Instância do vBMC iniciada para o domínio storage-1
[root@hp-gen9 ~]# vbmc start storage-2
2020-08-14 03:15:58,851.851 13149 INFO VirtualBMC [-] Instância do vBMC iniciada para o domínio storage-2
[root@hp-gen9 ~]# vbmc start compute-1
2020-08-14 03:15:59,307.307 13149 INFO VirtualBMC [-] Instância do vBMC iniciada para o domínio compute-1
[root@hp-gen9 ~]# vbmc start compute-2
2020-08-14 03:15:59,712.712 13149 INFO VirtualBMC [-] Instância do vBMC iniciada para o domínio compute-2
[root@hp-gen9 ~]# 
[root@hp-gen9 ~]# 
[root@hp-gen9 ~]# vbmc list
+-------------+---------+---------+------+
| Nome do domínio | Status  | Endereço | Porta |
+-------------+---------+---------+------+
| compute-1   | em execução | ::      | 7004 |
| compute-2   | em execução | ::      | 7005 |
| control-1   | em execução | ::      | 7001 |
| storage-1   | em execução | ::      | 7002 |
| storage-2   | em execução | ::      | 7003 |
+-------------+---------+---------+------+
[root@hp-gen9 ~]#

E a última etapa — é necessário ajustar as regras do firewall (ou desligá-lo completamente):


firewall-cmd --zone=public --add-port=7001/udp --permanent
firewall-cmd --zone=public --add-port=7002/udp --permanent
firewall-cmd --zone=public --add-port=7003/udp --permanent
firewall-cmd --zone=public --add-port=7004/udp --permanent
firewall-cmd --zone=public --add-port=7005/udp --permanent
firewall-cmd --reload

Agora vamos acessar o undercloud e verificar se tudo está funcionando. O endereço da máquina host é 192.168.255.200, e no undercloud adicionamos o pacote necessário ipmitool durante a preparação para o deployment:


[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power status          
A alimentação do chassi está desligada
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power on
Controle de Energia do Chassi: Ligado
[stack@undercloud ~]$ 

[root@hp-gen9 ~]# virsh list 
 Id    Nome                           Estado
----------------------------------------------------
 6     dns-server                     em execução
 64    undercloud                     em execução
 65    control-1                      em execução

Como podem ver, conseguimos iniciar com sucesso o nó de controle através do vbmc. Agora vamos desligá-lo e seguir em frente:


[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power off
Controle de Energia do Chassi: Desligado
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power status
A alimentação do chassi está desligada
[stack@undercloud ~]$ 

[root@hp-gen9 ~]# virsh list --all
 Id    Nome                           Estado
----------------------------------------------------
 6     dns-server                     em execução
 64    undercloud                     em execução
 -     compute-1                      desligado
 -     compute-2                      desligado
 -     control-1                      desligado
 -     storage-1                      desligado
 -     storage-2                      desligado

[root@hp-gen9 ~]#

O próximo passo é a introspecção dos nós, nos quais será instalado o overcloud. Para isso, precisamos preparar um arquivo json que descreva nossos nós. Observe que, ao contrário da instalação em servidores físicos, o arquivo menciona a porta em que o vbmc está rodando para cada uma das máquinas.


[root@hp-gen9 ~]# virsh domiflist --domain control-1 
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
-          rede      ovs-network-1 virtio      52:54:00:20:a2:2f
-          rede      ovs-network-1 virtio      52:54:00:3f:87:9f

[root@hp-gen9 ~]# virsh domiflist --domain compute-1
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
-          rede      ovs-network-1 virtio      52:54:00:98:e9:d6

[root@hp-gen9 ~]# virsh domiflist --domain compute-2
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
-          rede      ovs-network-1 virtio      52:54:00:6a:ea:be

[root@hp-gen9 ~]# virsh domiflist --domain storage-1
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
-          rede      ovs-network-1 virtio      52:54:00:79:0b:cb

[root@hp-gen9 ~]# virsh domiflist --domain storage-2
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
-          rede      ovs-network-1 virtio      52:54:00:a7:fe:27

Nota: no nó de controle há duas interfaces, mas neste caso isso não é importante, nesta instalação apenas uma é suficiente.

Agora vamos preparar o arquivo json. Precisamos indicar o endereço MAC da porta pela qual será feito o provisionamento, parâmetros dos nós, atribuir nomes a eles e indicar como acessar o ipmi:


{
    "nodes":[
        {
            "mac":[
                "52:54:00:20:a2:2f"
            ],
            "cpu":"8",
            "memory":"32768",
            "disk":"60",
            "arch":"x86_64",
            "name":"control-1",
            "pm_type":"pxe_ipmitool",
            "pm_user":"admin",
            "pm_password":"admin",
            "pm_addr":"192.168.255.200",
            "pm_port":"7001"
        },
        {
            "mac":[
                "52:54:00:79:0b:cb"
            ],
            "cpu":"4",
            "memory":"16384",
            "disk":"160",
            "arch":"x86_64",
            "name":"storage-1",
            "pm_type":"pxe_ipmitool",
            "pm_user":"admin",
            "pm_password":"admin",
            "pm_addr":"192.168.255.200",
            "pm_port":"7002"
        },
        {
            "mac":[
                "52:54:00:a7:fe:27"
            ],
            "cpu":"4",
            "memory":"16384",
            "disk":"160",
            "arch":"x86_64",
            "name":"storage-2",
            "pm_type":"pxe_ipmitool",
            "pm_user":"admin",
            "pm_password":"admin",
            "pm_addr":"192.168.255.200",
            "pm_port":"7003"
        },
        {
            "mac":[
                "52:54:00:98:e9:d6"
            ],
            "cpu":"12",
            "memory":"32768",
            "disk":"60",
            "arch":"x86_64",
            "name":"compute-1",
            "pm_type":"pxe_ipmitool",
            "pm_user":"admin",
            "pm_password":"admin",
            "pm_addr":"192.168.255.200",
            "pm_port":"7004"
        },
        {
            "mac":[
                "52:54:00:6a:ea:be"
            ],
            "cpu":"12",
            "memory":"32768",
            "disk":"60",
            "arch":"x86_64",
            "name":"compute-2",
            "pm_type":"pxe_ipmitool",
            "pm_user":"admin",
            "pm_password":"admin",
            "pm_addr":"192.168.255.200",
            "pm_port":"7005"
        }
    ]
}

Agora precisamos preparar as imagens para o ironic. Para isso, fazemos o download delas usando wget e instalamos:

(undercloud) [stack@undercloud ~]$ sudo wget https://images.rdoproject.org/queens/delorean/current-tripleo-rdo/overcloud-full.tar --no-check-certificate
(undercloud) [stack@undercloud ~]$ sudo wget https://images.rdoproject.org/queens/delorean/current-tripleo-rdo/ironic-python-agent.tar --no-check-certificate
(undercloud) [stack@undercloud ~]$ ls -lh
total 1.9G
-rw-r--r--. 1 stack stack 447M Aug 14 10:26 ironic-python-agent.tar
-rw-r--r--. 1 stack stack 1.5G Aug 14 10:26 overcloud-full.tar
-rw-------. 1 stack stack  916 Aug 13 23:10 stackrc
-rw-r--r--. 1 stack stack  15K Aug 13 22:50 undercloud.conf
-rw-------. 1 stack stack 2.0K Aug 13 22:50 undercloud-passwords.conf
(undercloud) [stack@undercloud ~]$ mkdir images/
(undercloud) [stack@undercloud ~]$ tar -xpvf ironic-python-agent.tar -C ~/images/
ironic-python-agent.initramfs
ironic-python-agent.kernel
(undercloud) [stack@undercloud ~]$ tar -xpvf overcloud-full.tar -C ~/images/
overcloud-full.qcow2
overcloud-full.initrd
overcloud-full.vmlinuz
(undercloud) [stack@undercloud ~]$
(undercloud) [stack@undercloud ~]$ ls -lh images/
total 1.9G
-rw-rw-r--. 1 stack stack 441M Aug 12 17:24 ironic-python-agent.initramfs
-rwxr-xr-x. 1 stack stack 6.5M Aug 12 17:24 ironic-python-agent.kernel
-rw-r--r--. 1 stack stack  53M Aug 12 17:14 overcloud-full.initrd
-rw-r--r--. 1 stack stack 1.4G Aug 12 17:18 overcloud-full.qcow2
-rwxr-xr-x. 1 stack stack 6.5M Aug 12 17:14 overcloud-full.vmlinuz
(undercloud) [stack@undercloud ~]$

Carregando imagens no undercloud:

(undercloud) [stack@undercloud ~]$ openstack overcloud image upload --image-path ~/images/
Imagem "overcloud-full-vmlinuz" foi carregada.
+--------------------------------------+------------------------+-------------+---------+--------+
|                  ID                  |          Nome          | Formato do Disco |   Tamanho  | Status |
+--------------------------------------+------------------------+-------------+---------+--------+
| c2553770-3e0f-4750-b46b-138855b5c385 | overcloud-full-vmlinuz |     aki     | 6761064 | ativo |
+--------------------------------------+------------------------+-------------+---------+--------+
Imagem "overcloud-full-initrd" foi carregada.
+--------------------------------------+-----------------------+-------------+----------+--------+
|                  ID                  |          Nome         | Formato do Disco |   Tamanho   | Status |
+--------------------------------------+-----------------------+-------------+----------+--------+
| 949984e0-4932-4e71-af43-d67a38c3dc89 | overcloud-full-initrd |     ari     | 55183045 | ativo |
+--------------------------------------+-----------------------+-------------+----------+--------+
Imagem "overcloud-full" foi carregada.
+--------------------------------------+----------------+-------------+------------+--------+
|                  ID                  |      Nome      | Formato do Disco |    Tamanho   | Status |
+--------------------------------------+----------------+-------------+------------+--------+
| a2f2096d-c9d7-429a-b866-c7543c02a380 | overcloud-full |    qcow2    | 1487475712 | ativo |
+--------------------------------------+----------------+-------------+------------+--------+
Imagem "bm-deploy-kernel" foi carregada.
+--------------------------------------+------------------+-------------+---------+--------+
|                  ID                  |       Nome       | Formato do Disco |   Tamanho  | Status |
+--------------------------------------+------------------+-------------+---------+--------+
| e413aa78-e38f-404c-bbaf-93e582a8e67f | bm-deploy-kernel |     aki     | 6761064 | ativo |
+--------------------------------------+------------------+-------------+---------+--------+
Imagem "bm-deploy-ramdisk" foi carregada.
+--------------------------------------+-------------------+-------------+-----------+--------+
|                  ID                  |        Nome       | Formato do Disco |    Tamanho   | Status |
+--------------------------------------+-------------------+-------------+-----------+--------+
| 5cf3aba4-0e50-45d3-929f-27f025dd6ce3 | bm-deploy-ramdisk |     ari     | 461759376 | ativo |
+--------------------------------------+-------------------+-------------+-----------+--------+
(undercloud) [stack@undercloud ~]$

Verificando se todas as imagens foram carregadas


(undercloud) [stack@undercloud ~]$ openstack image list
+--------------------------------------+------------------------+--------+
| ID                                   | Nome                   | Status |
+--------------------------------------+------------------------+--------+
| e413aa78-e38f-404c-bbaf-93e582a8e67f | bm-deploy-kernel       | ativo |
| 5cf3aba4-0e50-45d3-929f-27f025dd6ce3 | bm-deploy-ramdisk      | ativo |
| a2f2096d-c9d7-429a-b866-c7543c02a380 | overcloud-full         | ativo |
| 949984e0-4932-4e71-af43-d67a38c3dc89 | overcloud-full-initrd  | ativo |
| c2553770-3e0f-4750-b46b-138855b5c385 | overcloud-full-vmlinuz | ativo |
+--------------------------------------+------------------------+--------+
(undercloud) [stack@undercloud ~]$

Mais um detalhe — é necessário adicionar um servidor DNS:


(undercloud) [stack@undercloud ~]$ openstack subnet list
+--------------------------------------+-----------------+--------------------------------------+------------------+
| ID                                   | Nome            | Rede                                | Sub-rede        |
+--------------------------------------+-----------------+--------------------------------------+------------------+
| f45dea46-4066-42aa-a3c4-6f84b8120cab | ctlplane-subnet | 6ca013dc-41c2-42d8-9d69-542afad53392 | 192.168.255.0/24 |
+--------------------------------------+-----------------+--------------------------------------+------------------+
(undercloud) [stack@undercloud ~]$ openstack subnet show f45dea46-4066-42aa-a3c4-6f84b8120cab
+-------------------+-----------------------------------------------------------+
| Campo             | Valor                                                     |
+-------------------+-----------------------------------------------------------+
| allocation_pools  | 192.168.255.11-192.168.255.50                             |
| cidr              | 192.168.255.0/24                                          |
| created_at        | 2020-08-13T20:10:37Z                                      |
| descrição         |                                                           |
| dns_nameservers   |                                                           |
| enable_dhcp       | Verdadeiro                                                |
| gateway_ip        | 192.168.255.1                                             |
| host_routes       | destination='169.254.169.254/32', gateway='192.168.255.1' |
| id                | f45dea46-4066-42aa-a3c4-6f84b8120cab                      |
| ip_version        | 4                                                         |
| ipv6_address_mode | Nenhum                                                    |
| ipv6_ra_mode      | Nenhum                                                    |
| nome              | ctlplane-subnet                                           |
| network_id        | 6ca013dc-41c2-42d8-9d69-542afad53392                      |
| prefix_length     | Nenhum                                                    |
| project_id        | a844ccfcdb2745b198dde3e1b28c40a3                          |
| revision_number   | 0                                                         |
| segment_id        | Nenhum                                                    |
| service_types     |                                                           |
| subnetpool_id     | Nenhum                                                    |
| tags              |                                                           |
| updated_at        | 2020-08-13T20:10:37Z                                      |
+-------------------+-----------------------------------------------------------+
(undercloud) [stack@undercloud ~]$ 
(undercloud) [stack@undercloud ~]$ neutron subnet-update f45dea46-4066-42aa-a3c4-6f84b8120cab --dns-nameserver 192.168.255.253                                    
neutron CLI está obsoleto e será removido no futuro. Use openstack CLI em vez disso.
Sub-rede atualizada: f45dea46-4066-42aa-a3c4-6f84b8120cab
(undercloud) [stack@undercloud ~]$

Agora podemos emitir um comando para a introspecção:

(undercloud) [stack@undercloud ~]$ openstack overcloud node import --introspect --provide inspection.json 
Iniciado o fluxo de trabalho do Mistral tripleo.baremetal.v1.register_or_update. ID da execução: d57456a3-d8ed-479c-9a90-dff7c752d0ec
Aguardando mensagens na fila 'tripleo' sem tempo limite.


5 nó(s) movido(s) com sucesso para o estado "gerenciável".
Nó UUID b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 registrado com sucesso
Nó UUID b89a72a3-6bb7-429a-93bc-48393d225838 registrado com sucesso
Nó UUID 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e registrado com sucesso
Nó UUID bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 registrado com sucesso
Nó UUID 766ab623-464c-423d-a529-d9afb69d1167 registrado com sucesso
Aguardando a finalização da introspecção...
Iniciado o fluxo de trabalho do Mistral tripleo.baremetal.v1.introspect. ID da execução: 6b4d08ae-94c3-4a10-ab63-7634ec198a79
Aguardando mensagens na fila 'tripleo' sem tempo limite.
Introspecção do nó b89a72a3-6bb7-429a-93bc-48393d225838 concluída. Status:SUCESSO. Erros:Nenhum
Introspecção do nó 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e concluída. Status:SUCESSO. Erros:Nenhum
Introspecção do nó bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 concluída. Status:SUCESSO. Erros:Nenhum
Introspecção do nó 766ab623-464c-423d-a529-d9afb69d1167 concluída. Status:SUCESSO. Erros:Nenhum
Introspecção do nó b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 concluída. Status:SUCESSO. Erros:Nenhum
5 nó(s) introspectados com sucesso.
Iniciado o fluxo de trabalho do Mistral tripleo.baremetal.v1.provide. ID da execução: f5594736-edcf-4927-a8a0-2a7bf806a59a
Aguardando mensagens na fila 'tripleo' sem tempo limite.
5 nó(s) movido(s) com sucesso para o estado "disponível".
(undercloud) [stack@undercloud ~]$

Como pode ser visto na saída, tudo foi concluído sem erros. Vamos verificar se todos os nós estão no estado disponível:


(undercloud) [stack@undercloud ~]$ openstack baremetal node list
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
| UUID                                 | Nome      | UUID da Instância | Estado de Energia | Estado de Provisionamento | Manutenção |
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | controle-1 | Nenhum        | desligado   | disponível          | Falso       |
| b89a72a3-6bb7-429a-93bc-48393d225838 | armazenamento-1 | Nenhum   | desligado   | disponível          | Falso       |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | armazenamento-2 | Nenhum   | desligado   | disponível          | Falso       |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | computação-1 | Nenhum      | desligado   | disponível          | Falso       |
| 766ab623-464c-423d-a529-d9afb69d1167 | computação-2 | Nenhum      | desligado   | disponível          | Falso       |
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
(undercloud) [stack@undercloud ~]$ 

Se os nós estiverem em outro estado, geralmente gerenciável, algo deu errado e é preciso verificar os logs para entender o que aconteceu. Tenha em mente que, neste cenário, estamos usando virtualização e pode haver bugs relacionados ao uso de máquinas virtuais ou vbmc.

Em seguida, precisamos especificar qual nó realizará qual função — ou seja, definir o perfil com o qual o nó será implantado:


(undercloud) [stack@undercloud ~]$ openstack overcloud profiles list
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| Node UUID                            | Node Name | Provision State | Current Profile | Possible Profiles |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | control-1 | disponível      | Nenhum          |                   |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | disponível      | Nenhum          |                   |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | disponível      | Nenhum          |                   |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | disponível      | Nenhum          |                   |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | disponível      | Nenhum          |                   |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
(undercloud) [stack@undercloud ~]$ openstack flavor list
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
| ID                                   | Nome         |  RAM | Disco | Efêmero  | VCPUs | É Público? |
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
| 168af640-7f40-42c7-91b2-989abc5c5d8f | swift-storage | 4096 |   40 |         0 |     1 | Verdadeiro  |
| 52148d1b-492e-48b4-b5fc-772849dd1b78 | baremetal     | 4096 |   40 |         0 |     1 | Verdadeiro  |
| 56e66542-ae60-416d-863e-0cb192d01b09 | control       | 4096 |   40 |         0 |     1 | Verdadeiro  |
| af6796e1-d0c4-4bfe-898c-532be194f7ac | block-storage | 4096 |   40 |         0 |     1 | Verdadeiro  |
| e4d50fdd-0034-446b-b72c-9da19b16c2df | compute       | 4096 |   40 |         0 |     1 | Verdadeiro  |
| fc2e3acf-7fca-4901-9eee-4a4d6ef0265d | ceph-storage  | 4096 |   40 |         0 |     1 | Verdadeiro  |
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
(undercloud) [stack@undercloud ~]$

Especificamos o perfil para cada nó:


openstack baremetal node set --property capabilities='profile:control,boot_option:local' b4b2cf4a-b7ca-4095-af13-cc83be21c4f5
openstack baremetal node set --property capabilities='profile:ceph-storage,boot_option:local' b89a72a3-6bb7-429a-93bc-48393d225838
openstack baremetal node set --property capabilities='profile:ceph-storage,boot_option:local' 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e
openstack baremetal node set --property capabilities='profile:compute,boot_option:local' bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8
openstack baremetal node set --property capabilities='profile:compute,boot_option:local' 766ab623-464c-423d-a529-d9afb69d1167

Verificamos se fizemos tudo corretamente:


(undercloud) [stack@undercloud ~]$ openstack overcloud profiles list
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| Node UUID                            | Node Name | Provision State | Current Profile | Possible Profiles |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | control-1 | disponível      | controle        |                   |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | disponível      | ceph-storage    |                   |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | disponível      | ceph-storage    |                   |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | disponível      | computação      |                   |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | disponível      | computação      |                   |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
(undercloud) [stack@undercloud ~]$

Se tudo estiver correto, executamos o comando para implantar o overcloud:

openstack overcloud deploy --templates --control-scale 1 --compute-scale 2  --ceph-storage-scale 2 --control-flavor control --compute-flavor compute  --ceph-storage-flavor ceph-storage --libvirt-type qemu

Em uma instalação real, templates personalizados serão utilizados, mas no nosso caso isso complicará bastante o processo, pois será necessário explicar cada alteração no template. Como mencionado anteriormente — mesmo uma instalação simples será suficiente para ver como isso funciona.

Nota: a variável --libvirt-type qemu é necessária neste caso, pois usaremos virtualização aninhada. Caso contrário, suas máquinas virtuais não iniciarão.

Agora você tem cerca de uma hora, ou talvez mais (dependendo das capacidades do hardware), e deve torcer para que ao final desse tempo você veja a seguinte mensagem:


2020-08-14 08:39:21Z [overcloud]: CREATE_COMPLETE  Stack CREATE completed successfully

 Stack overcloud CREATE_COMPLETE 

Host 192.168.255.21 não encontrado em /home/stack/.ssh/known_hosts
Iniciado o Workflow Mistral tripleo.deployment.v1.get_horizon_url. ID de Execução: fcb996cd-6a19-482b-b755-2ca0c08069a9
Endpoint do Overcloud: http://192.168.255.21:5000/
URL do Painel do Overcloud: http://192.168.255.21:80/dashboard
Arquivo rc do Overcloud: /home/stack/overcloudrc
Overcloud Implantado
(undercloud) [stack@undercloud ~]$

Agora você tem uma versão quase completa do OpenStack, na qual pode aprender, testar, etc.

Vamos verificar se está tudo funcionando corretamente. No diretório inicial do usuário stack, há dois arquivos — um stackrc (para gerenciar o undercloud) e outro overcloudrc (para gerenciar o overcloud). Esses arquivos devem ser indicados como source, pois contêm as informações necessárias para autenticação.


(undercloud) [stack@undercloud ~]$ openstack server list
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
| ID                                   | Nome                    | Status | Redes                   | Imagem         | Sabor        |
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
| fd7d36f4-ce87-4b9a-93b0-add2957792de | overcloud-controller-0  | ATIVO  | ctlplane=192.168.255.15 | overcloud-full | controle      |
| edc77778-8972-475e-a541-ff40eb944197 | overcloud-novacompute-1 | ATIVO  | ctlplane=192.168.255.26 | overcloud-full | computação    |
| 5448ce01-f05f-47ca-950a-ced14892c0d4 | overcloud-cephstorage-1 | ATIVO  | ctlplane=192.168.255.34 | overcloud-full | ceph-storage  |
| ce6d862f-4bdf-4ba3-b711-7217915364d7 | overcloud-novacompute-0 | ATIVO  | ctlplane=192.168.255.19 | overcloud-full | computação    |
| e4507bd5-6f96-4b12-9cc0-6924709da59e | overcloud-cephstorage-0 | ATIVO  | ctlplane=192.168.255.44 | overcloud-full | ceph-storage  |
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
(undercloud) [stack@undercloud ~]$ 


(undercloud) [stack@undercloud ~]$ source overcloudrc 
(overcloud) [stack@undercloud ~]$ 
(overcloud) [stack@undercloud ~]$ openstack project list
+----------------------------------+---------+
| ID                               | Nome    |
+----------------------------------+---------+
| 4eed7d0f06544625857d51cd77c5bd4c | admin   |
| ee1c68758bde41eaa9912c81dc67dad8 | serviço |
+----------------------------------+---------+
(overcloud) [stack@undercloud ~]$ 
(overcloud) [stack@undercloud ~]$ 
(overcloud) [stack@undercloud ~]$ openstack network agent list  
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| ID                                   | Tipo de Agente     | Host                                | Zona de Disponibilidade | Vivo  | Estado | Binário                   |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| 10495de9-ba4b-41fe-b30a-b90ec3f8728b | agente Open vSwitch | overcloud-novacompute-1.localdomain | Nenhum            | :-)   | ATIVO | neutron-openvswitch-agent |
| 1515ad4a-5972-46c3-af5f-e5446dff7ac7 | agente L3           | overcloud-controller-0.localdomain  | nova              | :-)   | ATIVO | neutron-l3-agent          |
| 322e62ca-1e5a-479e-9a96-4f26d09abdd7 | agente DHCP         | overcloud-controller-0.localdomain  | nova              | :-)   | ATIVO | neutron-dhcp-agent        |
| 9c1de2f9-bac5-400e-998d-4360f04fc533 | agente Open vSwitch | overcloud-novacompute-0.localdomain | Nenhum            | :-)   | ATIVO | neutron-openvswitch-agent |
| d99c5657-851e-4d3c-bef6-f1e3bb1acfb0 | agente Open vSwitch | overcloud-controller-0.localdomain  | Nenhum            | :-)   | ATIVO | neutron-openvswitch-agent |
| ff85fae6-5543-45fb-a301-19c57b62d836 | agente de Metadados | overcloud-controller-0.localdomain  | Nenhum            | :-)   | ATIVO | neutron-metadata-agent    |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
(overcloud) [stack@undercloud ~]$

Em minha instalação, ainda falta um pequeno detalhe — adicionar uma rota no controlador, já que a máquina com a qual estou trabalhando está em outra rede. Para isso, vamos acessar o control-1 com a conta heat-admin e definir a rota.


(undercloud) [stack@undercloud ~]$ ssh heat-admin@192.168.255.15         
Último login: sex 14 ago 09:47:40 2020 de 192.168.255.1
[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ sudo ip route add 10.169.0.0/16 via 192.168.255.254

Agora você pode acessar o horizonte. Todas as informações — endereços, login e senha — estão no arquivo /home/stack/overcloudrc. O esquema final fica assim:

Introdução à parte de rede da infraestrutura em nuvem

Por sinal, na nossa instalação, os endereços das máquinas foram atribuídos via DHCP e, como você pode ver, eles são atribuídos "aleatoriamente". Você pode definir rigidamente, no template, qual endereço deve ser anexado a qual máquina durante o deployment, se necessário.

Como o tráfego circula entre as máquinas virtuais?

Neste artigo, vamos considerar três opções para a passagem de tráfego.

  • Duas máquinas em um hypervisor na mesma rede L2.
  • Duas máquinas em hypervisores diferentes na mesma rede L2.
  • Duas máquinas em redes diferentes (roteamento entre redes).

Casos com acesso ao mundo exterior através de uma rede externa, com uso de endereços flutuantes, bem como roteamento distribuído, serão abordados na próxima vez; por enquanto, vamos nos concentrar no tráfego interno.

Para verificação, vamos montar o seguinte esquema:

Introdução à parte de rede da infraestrutura em nuvem

Criamos 4 máquinas virtuais — 3 em uma rede L2 — net-1, e mais 1 na rede net-2.

(overcloud) [stack@undercloud ~]$ nova list --tenant 5e18ce8ec9594e00b155485f19895e6c             
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
| ID                                   | Nome | ID do Inquilino                  | Status | Estado da Tarefa | Estado de Energia | Redes           |
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
| f53b37b5-2204-46cc-aef0-dba84bf970c0 | vm-1 | 5e18ce8ec9594e00b155485f19895e6c | ATIVO  | -          | Em Execução | net-1=10.0.1.85 |
| fc8b6722-0231-49b0-b2fa-041115bef34a | vm-2 | 5e18ce8ec9594e00b155485f19895e6c | ATIVO  | -          | Em Execução | net-1=10.0.1.88 |
| 3cd74455-b9b7-467a-abe3-bd6ff765c83c | vm-3 | 5e18ce8ec9594e00b155485f19895e6c | ATIVO  | -          | Em Execução | net-1=10.0.1.90 |
| 7e836338-6772-46b0-9950-f7f06dbe91a8 | vm-4 | 5e18ce8ec9594e00b155485f19895e6c | ATIVO  | -          | Em Execução | net-2=10.0.2.8  |
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
(overcloud) [stack@undercloud ~]$ 

Vamos ver em quais hypervisores as máquinas foram criadas:

(overcloud) [stack@undercloud ~]$ nova show f53b37b5-2204-46cc-aef0-dba84bf970c0 | egrep "hypervisor_hostname|instance_name|hostname"
| OS-EXT-SRV-ATTR:hostname             | vm-1                                                     |
| OS-EXT-SRV-ATTR:hypervisor_hostname  | overcloud-novacompute-0.localdomain                      |
| OS-EXT-SRV-ATTR:instance_name        | instance-00000001                                        |
(overcloud) [stack@undercloud ~]$ nova show fc8b6722-0231-49b0-b2fa-041115bef34a | egrep "hypervisor_hostname|instance_name|hostname"
| OS-EXT-SRV-ATTR:hostname             | vm-2                                                     |
| OS-EXT-SRV-ATTR:hypervisor_hostname  | overcloud-novacompute-1.localdomain                      |
| OS-EXT-SRV-ATTR:instance_name        | instance-00000002                                        |
(overcloud) [stack@undercloud ~]$ nova show 3cd74455-b9b7-467a-abe3-bd6ff765c83c | egrep "hypervisor_hostname|instance_name|hostname"
| OS-EXT-SRV-ATTR:hostname             | vm-3                                                     |
| OS-EXT-SRV-ATTR:hypervisor_hostname  | overcloud-novacompute-0.localdomain                      |
| OS-EXT-SRV-ATTR:instance_name        | instance-00000003                                        |
(overcloud) [stack@undercloud ~]$ nova show 7e836338-6772-46b0-9950-f7f06dbe91a8 | egrep "hypervisor_hostname|instance_name|hostname"
| OS-EXT-SRV-ATTR:hostname             | vm-4                                                     |
| OS-EXT-SRV-ATTR:hypervisor_hostname  | overcloud-novacompute-1.localdomain                      |
| OS-EXT-SRV-ATTR:instance_name        | instance-00000004                                        |

(overcloud) [stack@undercloud ~]$
As máquinas vm-1 e vm-3 estão localizadas no compute-0, enquanto as máquinas vm-2 e vm-4 estão no nó compute-1.

Além disso, um roteador virtual foi criado para permitir a roteação entre as redes especificadas:

(overcloud) [stack@undercloud ~]$ openstack router list  --project 5e18ce8ec9594e00b155485f19895e6c
+--------------------------------------+----------+--------+-------+-------------+-------+----------------------------------+
| ID                                   | Name     | Status | State | Distributed | HA    | Project                          |
+--------------------------------------+----------+--------+-------+-------------+-------+----------------------------------+
| 0a4d2420-4b9c-46bd-aec1-86a1ef299abe | router-1 | ACTIVE | UP    | False       | False | 5e18ce8ec9594e00b155485f19895e6c |
+--------------------------------------+----------+--------+-------+-------------+-------+----------------------------------+
(overcloud) [stack@undercloud ~]$ 

O roteador possui duas portas virtuais que atuam como gateways para as redes:

(overcloud) [stack@undercloud ~]$ openstack router show 0a4d2420-4b9c-46bd-aec1-86a1ef299abe | grep interface
| interfaces_info         | [{"subnet_id": "2529ad1a-6b97-49cd-8515-cbdcbe5e3daa", "ip_address": "10.0.1.254", "port_id": "0c52b15f-8fcc-4801-bf52-7dacc72a5201"}, {"subnet_id": "335552dd-b35b-456b-9df0-5aac36a3ca13", "ip_address": "10.0.2.254", "port_id": "92fa49b5-5406-499f-ab8d-ddf28cc1a76c"}] |
(overcloud) [stack@undercloud ~]$ 

Mas antes de examinarmos como o tráfego flui, vamos dar uma olhada no que temos atualmente no nó de controle (que também é o nó de rede) e no nó de computação. Comecemos pelo nó de computação.


[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-vsctl show
[heat-admin@overcloud-novacompute-0 ~]$ sudo sudo ovs-appctl dpif/show
system@ovs-system: hit:3 missed:3
  br-ex:
    br-ex 65534/1: (internal)
    phy-br-ex 1/none: (patch: peer=int-br-ex)
  br-int:
    br-int 65534/2: (internal)
    int-br-ex 1/none: (patch: peer=phy-br-ex)
    patch-tun 2/none: (patch: peer=patch-int)
  br-tun:
    br-tun 65534/3: (internal)
    patch-int 1/none: (patch: peer=patch-tun)
    vxlan-c0a8ff0f 3/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.15)
    vxlan-c0a8ff1a 2/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.26)
[heat-admin@overcloud-novacompute-0 ~]$

Atualmente, existem três bridges OVS no nó — br-int, br-tun, br-ex. Entre eles, como podemos ver, há um conjunto de interfaces. Para facilitar a compreensão, vamos representar todas essas interfaces em um diagrama e ver o que resulta.

Introdução à parte de rede da infraestrutura em nuvem

Nos endereços onde os túneis VxLAN estão configurados, pode-se ver que um túnel está levantado no compute-1 (192.168.255.26) e o segundo está apontando para o control-1 (192.168.255.15). Mas o mais interessante é que o br-ex não tem interfaces físicas, e se olharmos quais fluxos estão configurados, veremos que essa bridge atualmente só pode descartar tráfego.


[heat-admin@overcloud-novacompute-0 ~]$ ifconfig eth0
eth0: flags=4163  mtu 1450
        inet 192.168.255.19  netmask 255.255.255.0  broadcast 192.168.255.255
        inet6 fe80::5054:ff:fe6a:eabe  prefixlen 64  scopeid 0x20
        ether 52:54:00:6a:ea:be  txqueuelen 1000  (Ethernet)
        RX packets 2909669  bytes 4608201000 (4.2 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1821057  bytes 349198520 (333.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[heat-admin@overcloud-novacompute-0 ~]$ 

Como pode ser visto na saída, o endereço está vinculado diretamente à porta física, e não à interface bridge virtual.


[heat-admin@overcloud-novacompute-0 ~]$  sudo ovs-appctl fdb/show br-ex
 port  VLAN  MAC                Age
[heat-admin@overcloud-novacompute-0 ~]$  sudo ovs-ofctl dump-flows br-ex
 cookie=0x9169eae8f7fe5bb2, duration=216686.864s, table=0, n_packets=303, n_bytes=26035, priority=2,in_port="phy-br-ex" actions=drop
 cookie=0x9169eae8f7fe5bb2, duration=216686.887s, table=0, n_packets=0, n_bytes=0, priority=0 actions=NORMAL
[heat-admin@overcloud-novacompute-0 ~]$ 

De acordo com a primeira regra, tudo o que vem da porta phy-br-ex deve ser descartado.
Então, neste bridge, atualmente não deve haver tráfego de onde mais, exceto desse interface (conexão com br-int), e, com base nos drops, parece que já chegou tráfego BUM a essa bridge.

Ou seja, o tráfego pode sair deste nó apenas através de um túnel VxLAN e não de outra forma. No entanto, se ativarmos o DVR, a situação mudará, mas vamos abordar isso em outra ocasião. Ao utilizar a segmentação de redes, por exemplo, com VLANs, você terá mais de uma interface L3 na VLAN 0, em vez de apenas uma. No entanto, o tráfego VxLAN sairá do nó da mesma forma, mas encapsulado em alguma VLAN dedicada.

Já que entendemos como funciona o nó de computação, vamos para o nó de controle.


[heat-admin@overcloud-controller-0 ~]$ sudo ovs-appctl dpif/show
system@ovs-system: hit:930491 missed:825
  br-ex:
    br-ex 65534/1: (interno)
    eth0 1/2: (sistema)
    phy-br-ex 2/nem: (patch: peer=int-br-ex)
  br-int:
    br-int 65534/3: (interno)
    int-br-ex 1/nem: (patch: peer=phy-br-ex)
    patch-tun 2/nem: (patch: peer=patch-int)
  br-tun:
    br-tun 65534/4: (interno)
    patch-int 1/nem: (patch: peer=patch-tun)
    vxlan-c0a8ff13 3/5: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.15, remote_ip=192.168.255.19)
    vxlan-c0a8ff1a 2/5: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.15, remote_ip=192.168.255.26)
[heat-admin@overcloud-controller-0 ~]$

De fato, pode-se dizer que é tudo a mesma coisa, no entanto, o endereço IP já não está na interface física, mas sim na ponte virtual. Isso ocorreu porque esta porta é a porta pela qual o tráfego irá sair para o mundo exterior.


[heat-admin@overcloud-controller-0 ~]$ ifconfig br-ex
br-ex: flags=4163  mtu 1450
        inet 192.168.255.15  netmask 255.255.255.0  broadcast 192.168.255.255
        inet6 fe80::5054:ff:fe20:a22f  prefixlen 64  scopeid 0x20
        ether 52:54:00:20:a2:2f  txqueuelen 1000  (Ethernet)
        RX packets 803859  bytes 1732616116 (1.6 GiB)
        RX errors 0  dropped 63  overruns 0  frame 0
        TX packets 808475  bytes 121652156 (116.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ sudo ovs-appctl fdb/show br-ex
 port  VLAN  MAC                Age
    3   100  28:c0:da:00:4d:d3   35
    1     0  28:c0:da:00:4d:d3   35
    1     0  52:54:00:98:e9:d6    0
LOCAL     0  52:54:00:20:a2:2f    0
    1     0  52:54:00:2c:08:9e    0
    3   100  52:54:00:20:a2:2f    0
    1     0  52:54:00:6a:ea:be    0
[heat-admin@overcloud-controller-0 ~]$ 

Esta porta está vinculada à ponte br-ex e, como não possui nenhuma tag de VLAN, é uma porta trunk onde todas as VLANs são permitidas. Atualmente, o tráfego sai para fora sem tag, como indicado pelo vlan-id 0 na saída acima.

Introdução à parte de rede da infraestrutura em nuvem

Todo o restante, neste momento, é semelhante ao nó de computação — as mesmas pontes, os mesmos túneis que vão para os dois nós de computação.

Neste artigo, não iremos abordar as nódulos de armazenamento, mas para a compreensão, é importante mencionar que a parte de rede dessas nódulos é extremamente simples. No nosso caso, há apenas uma porta física (eth0) com um endereço IP configurado e ponto final. Não há VxLANs, túneis ou pontes de túnel — não há OVS, pois isso não faz sentido. Ao usar isolamento de redes, esta nódulo terá duas interfaces (portas físicas, bonds, ou simplesmente duas VLANs — isso não importa — depende do que você deseja) — uma para gerenciamento e a outra para tráfego (gravação em disco VM, leitura a partir do disco, etc.).

Agora que entendemos o que temos nas nódulos na ausência de quaisquer serviços, vamos iniciar 4 máquinas virtuais e ver como a configuração descrita acima mudará — devemos ver aparecer portas, roteadores virtuais, etc.

Até agora, nossa rede se parece com isto:

Introdução à parte de rede da infraestrutura em nuvem

Temos duas máquinas virtuais em cada nódulo de computação. Vamos observar como está tudo conectado, usando o exemplo do compute-0.


[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh list 
 Id    Nome                           Estado
----------------------------------------------------
 1     instance-00000001              em execução
 3     instance-00000003              em execução

[heat-admin@overcloud-novacompute-0 ~]$ 

A máquina possui apenas uma interface virtual — tap95d96a75-a0:

[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000001
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
tap95d96a75-a0 bridge     qbr95d96a75-a0 virtio      fa:16:3e:44:98:20

[heat-admin@overcloud-novacompute-0 ~]$ 

Esta interface se conecta a um bridge Linux:

[heat-admin@overcloud-novacompute-0 ~]$ sudo brctl show
nome da ponte     ID da ponte               STP habilitado     interfaces
docker0         8000.0242904c92a8       não
qbr5bd37136-47          8000.5e4e05841423       não              qvb5bd37136-47
                                                        tap5bd37136-47
qbr95d96a75-a0          8000.de076cb850f6       não              qvb95d96a75-a0
                                                        tap95d96a75-a0
[heat-admin@overcloud-novacompute-0 ~]$ 

Como pode ser visto na saída, há apenas duas interfaces no bridge — tap95d96a75-a0 e qvb95d96a75-a0.

Aqui, vale a pena parar um pouco sobre os tipos de dispositivos de rede virtuais no OpenStack:
vtap — interface virtual conectada a uma instância (VM)
qbr — bridge Linux
qvb e qvo — par de vEth conectado ao bridge Linux e ao bridge Open vSwitch
br-int, br-tun, br-vlan — bridges Open vSwitch
patch-, int-br-, phy-br- — interfaces de patch Open vSwitch que conectam bridges
qg, qr, ha, fg, sg — portas Open vSwitch usadas por dispositivos virtuais para conectar-se ao OVS

Como você entende, se temos no bridge uma porta qvb95d96a75-a0, que é um par vEth, então deve haver do outro lado uma contrapartida, que logicamente deve ser chamada de qvo95d96a75-a0. Vamos ver quais portas existem no OVS.


[heat-admin@overcloud-novacompute-0 ~]$ sudo sudo ovs-appctl dpif/show
system@ovs-system: hit:526 missed:91
  br-ex:
    br-ex 65534/1: (internal)
    phy-br-ex 1/none: (patch: peer=int-br-ex)
  br-int:
    br-int 65534/2: (internal)
    int-br-ex 1/none: (patch: peer=phy-br-ex)
    patch-tun 2/none: (patch: peer=patch-int)
    qvo5bd37136-47 6/6: (system)
    qvo95d96a75-a0 3/5: (system)
  br-tun:
    br-tun 65534/3: (internal)
    patch-int 1/none: (patch: peer=patch-tun)
    vxlan-c0a8ff0f 3/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.15)
    vxlan-c0a8ff1a 2/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.26)
[heat-admin@overcloud-novacompute-0 ~]$ 

Como podemos ver, a porta está localizada em br-int. O br-int atua como um switch, terminando as portas das máquinas virtuais. Além de qvo95d96a75-a0, a saída também mostra a porta qvo5bd37136-47. Esta é a porta para a segunda máquina virtual. No final, nosso esquema agora se parece com isto:

Introdução à parte de rede da infraestrutura em nuvem

A pergunta que deve imediatamente interessar o leitor atento é: qual é o propósito do linux bridge entre a porta da máquina virtual e a porta OVS? O fato é que, para proteger a máquina, são utilizadas security groups, que nada mais são do que iptables. O OVS não funciona com iptables, por isso foi inventado esse 'gambiarra'. No entanto, isso já está ultrapassado — está sendo substituído pelo conntrack em novas versões.

Portanto, no final das contas, o esquema se parece com isto:

Introdução à parte de rede da infraestrutura em nuvem

Duas máquinas em um hypervisor na mesma rede L2.

Uma vez que as duas máquinas virtuais estão na mesma rede L2 e no mesmo hypervisor, o tráfego entre elas deverá passar localmente através do br-int, visto que ambas estarão na mesma VLAN:


[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000001
Interface  Type       Source     Model       MAC
-------------------------------------------------------
tap95d96a75-a0 bridge     qbr95d96a75-a0 virtio      fa:16:3e:44:98:20

[heat-admin@overcloud-novacompute-0 ~]$ 
[heat-admin@overcloud-novacompute-0 ~]$ 
[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000003
Interface  Type       Source     Model       MAC
-------------------------------------------------------
tap5bd37136-47 bridge     qbr5bd37136-47 virtio      fa:16:3e:83:ad:a4

[heat-admin@overcloud-novacompute-0 ~]$ 
[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-appctl fdb/show br-int 
 port  VLAN  MAC                Age
    6     1  fa:16:3e:83:ad:a4    0
    3     1  fa:16:3e:44:98:20    0
[heat-admin@overcloud-novacompute-0 ~]$ 

Duas máquinas em hypervisores diferentes na mesma rede L2.

Agora vamos ver como o tráfego entre duas máquinas na mesma rede L2, mas localizadas em hypervisores diferentes, será tratado. Para ser honesto, não mudará muito, apenas o tráfego entre os hypervisores passará através do túnel vxlan. Vamos ver um exemplo.

Endereços das máquinas virtuais entre as quais vamos monitorar o tráfego:

[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000001
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
tap95d96a75-a0 bridge     qbr95d96a75-a0 virtio      fa:16:3e:44:98:20

[heat-admin@overcloud-novacompute-0 ~]$ 


[heat-admin@overcloud-novacompute-1 ~]$ sudo virsh domiflist instance-00000002
Interface  Tipo       Fonte     Modelo       MAC
-------------------------------------------------------
tape7e23f1b-07 bridge     qbre7e23f1b-07 virtio      fa:16:3e:72:ad:53

[heat-admin@overcloud-novacompute-1 ~]$ 

Verificando a tabela de encaminhamento em br-int no compute-0:

[heat-admin@overcloud-novacompute-0 ~]$  sudo ovs-appctl fdb/show br-int | grep fa:16:3e:72:ad:53
    2     1  fa:16:3e:72:ad:53    1
[heat-admin@overcloud-novacompute-0 ~]$

O tráfego deve ir para a porta 2 — vamos ver qual é essa porta:

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-ofctl show br-int | grep addr
 1(int-br-ex): addr:7e:7f:28:1f:bd:54
 2(patch-tun): addr:0a:bd:07:69:58:d9
 3(qvo95d96a75-a0): addr:ea:50:9a:3d:69:58
 6(qvo5bd37136-47): addr:9a:d1:03:50:3d:96
 LOCAL(br-int): addr:1a:0f:53:97:b1:49
[heat-admin@overcloud-novacompute-0 ~]$

Esta é a patch-tun — ou seja, interface em br-tun. Vamos ver o que acontece com o pacote em br-tun:

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-ofctl dump-flows br-tun | grep fa:16:3e:72:ad:53
 cookie=0x8759a56536b67a8e, duration=1387.959s, table=20, n_packets=1460, n_bytes=138880, hard_timeout=300, idle_age=0, hard_age=0, priority=1,vlan_tci=0x0001/0x0fff,dl_dst=fa:16:3e:72:ad:53 actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:2
[heat-admin@overcloud-novacompute-0 ~]$ 

O pacote é encapsulado em VxLAN e enviado para a porta 2. Vamos ver para onde leva a porta 2:

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-ofctl show br-tun | grep addr   
 1(patch-int): addr:b2:d1:f8:21:96:66
 2(vxlan-c0a8ff1a): addr:be:64:1f:75:78:a7
 3(vxlan-c0a8ff0f): addr:76:6f:b9:3c:3f:1c
 LOCAL(br-tun): addr:a2:5b:6d:4f:94:47
[heat-admin@overcloud-novacompute-0 ~]$

Este é o túnel vxlan no compute-1:

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-appctl dpif/show | egrep vxlan-c0a8ff1a
    vxlan-c0a8ff1a 2/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.26)
[heat-admin@overcloud-novacompute-0 ~]$

Vamos para o compute-1 e ver o que acontece com o pacote:

[heat-admin@overcloud-novacompute-1 ~]$ sudo ovs-appctl fdb/show br-int | egrep fa:16:3e:44:98:20
    2     1  fa:16:3e:44:98:20    1
[heat-admin@overcloud-novacompute-1 ~]$ 

O MAC está na tabela de encaminhamento br-int no compute-1, e como pode ser visto na saída acima, ele é visível através da porta 2, que é a porta voltada para br-tun:

[heat-admin@overcloud-novacompute-1 ~]$ sudo ovs-ofctl show br-int | grep addr   
 1(int-br-ex): addr:8a:d7:f9:ad:8c:1d
 2(patch-tun): addr:46:cc:40:bd:20:da
 3(qvoe7e23f1b-07): addr:12:78:2e:34:6a:c7
 4(qvo3210e8ec-c0): addr:7a:5f:59:75:40:85
 LOCAL(br-int): addr:e2:27:b2:ed:14:46

E então, vamos verificar o que tem no br-int no compute-1 que contém o MAC de destino:

[heat-admin@overcloud-novacompute-1 ~]$ sudo ovs-appctl fdb/show br-int | egrep fa:16:3e:72:ad:53
    3     1  fa:16:3e:72:ad:53    0
[heat-admin@overcloud-novacompute-1 ~]$ 

Ou seja, o pacote recebido irá para a porta 3, onde já está a máquina virtual instance-00000003.

Todo o encanto da implantação do Openstack para estudo em infraestrutura virtual está no fato de que podemos capturar facilmente o tráfego entre os hypervisores e observar o que está acontecendo com ele. É isso que faremos agora, vamos executar o tcpdump na porta vnet em direção ao compute-0:


[root@hp-gen9 bormoglotx]# tcpdump -vvv -i vnet3
tcpdump: ouvindo em vnet3, tipo de link EN10MB (Ethernet), tamanho de captura 262144 bytes

*****************omitido*******************

04:39:04.583459 IP (tos 0x0, ttl 64, id 16868, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.19.39096 > 192.168.255.26.4789: [no cksum] VXLAN, flags [I] (0x08), vni 22
IP (tos 0x0, ttl 64, id 8012, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.1.85 > 10.0.1.88: solicitação de eco ICMP, id 5634, seq 16, length 64
04:39:04.584449 IP (tos 0x0, ttl 64, id 35181, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.26.speedtrace-disc > 192.168.255.19.4789: [no cksum] VXLAN, flags [I] (0x08), vni 22
IP (tos 0x0, ttl 64, id 59124, offset 0, flags [none], proto ICMP (1), length 84)
    10.0.1.88 > 10.0.1.85: resposta de eco ICMP, id 5634, seq 16, length 64
	
*****************omitido*******************

A primeira linha mostra que o pacote com o endereço 10.0.1.85 está indo para o endereço 10.0.1.88 (tráfego ICMP), e está encapsulado em um pacote VxLAN com vni 22, indo do host 192.168.255.19 (compute-0) para o host 192.168.255.26 (compute-1). Podemos verificar que o VNI corresponde ao especificado no ovs.

Vamos voltar a esta linha actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:2. 0x16 é o vni em base hexadecimal. Vamos converter esse número para a base decimal:


16 = 6*16^0+1*16^1 = 6+16 = 22

Ou seja, o vni está de acordo com a realidade.

A segunda linha mostra o tráfego inverso, mas não há necessidade de explicar, está tudo claro lá.

Duas máquinas em redes diferentes (roteamento entre redes)

O último caso de hoje é o roteamento entre redes dentro de um único projeto utilizando um roteador virtual. Estamos considerando o caso sem DVR (isso será abordado em outro artigo), portanto, o roteamento ocorre no nó de rede. No nosso caso, o nó de rede não está isolado como uma entidade separada e está localizado no nó de controle.

Para começar, vamos verificar se o roteamento está funcionando:

$ ping 10.0.2.8
PING 10.0.2.8 (10.0.2.8): 56 bytes de dados
64 bytes de 10.0.2.8: seq=0 ttl=63 time=7.727 ms
64 bytes de 10.0.2.8: seq=1 ttl=63 time=3.832 ms
^C
--- estatísticas do ping para 10.0.2.8 ---
2 pacotes transmitidos, 2 pacotes recebidos, 0% perda de pacotes
round-trip min/avg/max = 3.832/5.779/7.727 ms

Como neste caso o pacote deve ir para o gateway e ser roteado lá, precisamos descobrir o endereço MAC do gateway, para isso, vamos olhar a tabela ARP na instância:

$ arp
host-10-0-1-254.openstacklocal (10.0.1.254) at fa:16:3e:c4:64:70 [ether]  on eth0
host-10-0-1-1.openstacklocal (10.0.1.1) at fa:16:3e:e6:2c:5c [ether]  on eth0
host-10-0-1-90.openstacklocal (10.0.1.90) at fa:16:3e:83:ad:a4 [ether]  on eth0
host-10-0-1-88.openstacklocal (10.0.1.88) at fa:16:3e:72:ad:53 [ether]  on eth0

Agora vamos ver para onde o tráfego com o destino (10.0.1.254) fa:16:3e:c4:64:70 deve ser enviado.

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-appctl fdb/show br-int | egrep fa:16:3e:c4:64:70
    2     1  fa:16:3e:c4:64:70    0
[heat-admin@overcloud-novacompute-0 ~]$ 

Verificamos para onde o porta 2 leva:

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-ofctl show br-int | grep addr
 1(int-br-ex): addr:7e:7f:28:1f:bd:54
 2(patch-tun): addr:0a:bd:07:69:58:d9
 3(qvo95d96a75-a0): addr:ea:50:9a:3d:69:58
 6(qvo5bd37136-47): addr:9a:d1:03:50:3d:96
 LOCAL(br-int): addr:1a:0f:53:97:b1:49
[heat-admin@overcloud-novacompute-0 ~]$ 

Tudo faz sentido, o tráfego vai para br-tun. Vamos ver em qual túnel vxlan ele será encapsulado:

[heat-admin@overcloud-novacompute-0 ~]$ sudo ovs-ofctl dump-flows br-tun | grep fa:16:3e:c4:64:70
 cookie=0x8759a56536b67a8e, duration=3514.566s, table=20, n_packets=3368, n_bytes=317072, hard_timeout=300, idle_age=0, hard_age=0, priority=1,vlan_tci=0x0001/0x0fff,dl_dst=fa:16:3e:c4:64:70 actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:3
[heat-admin@overcloud-novacompute-0 ~]$ 

A terceira porta é o túnel vxlan:

[heat-admin@overcloud-controller-0 ~]$ sudo ovs-ofctl show br-tun | grep addr
 1(patch-int): addr:a2:69:00:c5:fa:ba
 2(vxlan-c0a8ff1a): addr:86:f0:ce:d0:e8:ea
 3(vxlan-c0a8ff13): addr:72:aa:73:2c:2e:5b
 LOCAL(br-tun): addr:a6:cb:cd:72:1c:45
[heat-admin@overcloud-controller-0 ~]$ 

Que se conecta ao nó de controle:

[heat-admin@overcloud-controller-0 ~]$ sudo sudo ovs-appctl dpif/show | grep vxlan-c0a8ff1a
    vxlan-c0a8ff1a 2/5: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.15, remote_ip=192.168.255.26)
[heat-admin@overcloud-controller-0 ~]$ 

O tráfego chegou ao nó de controle, então precisamos acessá-lo e ver como será o encaminhamento.

Como você se lembra, o nó de controle parecia exatamente igual ao nó de computação — os mesmos três bridges, exceto que o br-ex tinha uma porta física, pela qual o nó poderia enviar tráfego para fora. A criação de instâncias alterou a configuração nos nós de computação — foram adicionados bridges linux, iptables e interfaces nos nós. A criação de redes e de um roteador virtual também deixou sua marca na configuração do nó de controle.

Portanto, é evidente que o endereço MAC do gateway deve estar na tabela de encaminhamento do br-int no nó de controle. Vamos verificar se ele está lá e para onde ele está apontando:

[heat-admin@overcloud-controller-0 ~]$ sudo ovs-appctl fdb/show br-int | grep fa:16:3e:c4:64:70
    5     1  fa:16:3e:c4:64:70    1
[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ sudo ovs-ofctl show br-int | grep addr
 1(int-br-ex): addr:2e:58:b6:db:d5:de
 2(patch-tun): addr:06:41:90:f0:9e:56
 3(tapca25a97e-64): addr:fa:16:3e:e6:2c:5c
 4(tap22015e46-0b): addr:fa:16:3e:76:c2:11
 5(qr-0c52b15f-8f): addr:fa:16:3e:c4:64:70
 6(qr-92fa49b5-54): addr:fa:16:3e:80:13:72
 LOCAL(br-int): addr:06:de:5d:ed:44:44
[heat-admin@overcloud-controller-0 ~]$ 

O MAC é visível da porta qr-0c52b15f-8f. Se voltarmos à lista de portas virtuais no OpenStack, esse tipo de porta é utilizado para conectar diferentes dispositivos virtuais ao OVS. Para ser mais preciso, qr é a porta em direção ao roteador virtual, que é apresentada na forma de namespace.

Vamos ver quais namespaces existem no servidor:

[heat-admin@overcloud-controller-0 ~]$ sudo  ip netns
qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe (id: 2)
qdhcp-7d541e74-1c36-4e1d-a7c4-0968c8dbc638 (id: 1)
qdhcp-67a3798c-32c0-4c18-8502-2531247e3cc2 (id: 0)
[heat-admin@overcloud-controller-0 ~]$ 

Três instâncias inteiras. Mas, a julgar pelos nomes, podemos deduzir a finalidade de cada uma delas. Voltaremos às instâncias com ID 0 e 1 mais tarde, agora estamos interessados no namespace qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe:


[heat-admin@overcloud-controller-0 ~]$ sudo  ip netns exec qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe ip route
10.0.1.0/24 dev qr-0c52b15f-8f proto kernel scope link src 10.0.1.254 
10.0.2.0/24 dev qr-92fa49b5-54 proto kernel scope link src 10.0.2.254 
[heat-admin@overcloud-controller-0 ~]$ 

Neste namespace, existem duas interfaces internas que criamos anteriormente. Ambas as portas virtuais foram adicionadas ao br-int. Vamos verificar o endereço MAC da porta qr-0c52b15f-8f, já que o tráfego, pelo que parece devido ao endereço MAC de destino, foi para essa interface.

[heat-admin@overcloud-controller-0 ~]$ sudo  ip netns exec qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe ifconfig qr-0c52b15f-8f
qr-0c52b15f-8f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.0.1.254  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::f816:3eff:fec4:6470  prefixlen 64  scopeid 0x20<link>
        ether fa:16:3e:c4:64:70  txqueuelen 1000  (Ethernet)
        RX packets 5356  bytes 427305 (417.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 5195  bytes 490603 (479.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[heat-admin@overcloud-controller-0 ~]$ 

Então, neste caso, tudo funciona de acordo com as leis da roteação padrão. Como o tráfego é destinado ao host 10.0.2.8, ele deve sair pela segunda interface qr-92fa49b5-54 e seguir através do túnel vxlan para o nó de computação:


[heat-admin@overcloud-controller-0 ~]$ sudo  ip netns exec qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe arp
Address                  HWtype  HWaddress           Flags Mask            Iface
10.0.1.88                ether   fa:16:3e:72:ad:53   C                     qr-0c52b15f-8f
10.0.1.90                ether   fa:16:3e:83:ad:a4   C                     qr-0c52b15f-8f
10.0.2.8                 ether   fa:16:3e:6c:ad:9c   C                     qr-92fa49b5-54
10.0.2.42                ether   fa:16:3e:f5:0b:29   C                     qr-92fa49b5-54
10.0.1.85                ether   fa:16:3e:44:98:20   C                     qr-0c52b15f-8f
[heat-admin@overcloud-controller-0 ~]$ 

Tudo faz sentido, sem surpresas. Vamos ver de onde o endereço MAC do host 10.0.2.8 é visível em br-int:

[heat-admin@overcloud-controller-0 ~]$ sudo ovs-appctl fdb/show br-int | grep fa:16:3e:6c:ad:9c
    2     2  fa:16:3e:6c:ad:9c    1
[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ sudo ovs-ofctl show br-int | grep addr
 1(int-br-ex): addr:2e:58:b6:db:d5:de
 2(patch-tun): addr:06:41:90:f0:9e:56
 3(tapca25a97e-64): addr:fa:16:3e:e6:2c:5c
 4(tap22015e46-0b): addr:fa:16:3e:76:c2:11
 5(qr-0c52b15f-8f): addr:fa:16:3e:c4:64:70
 6(qr-92fa49b5-54): addr:fa:16:3e:80:13:72
 LOCAL(br-int): addr:06:de:5d:ed:44:44
[heat-admin@overcloud-controller-0 ~]$ 

Como esperado, o tráfego vai para br-tun, vamos ver em qual túnel o tráfego continuará:

[heat-admin@overcloud-controller-0 ~]$ sudo ovs-ofctl dump-flows br-tun | grep fa:16:3e:6c:ad:9c
 cookie=0x2ab04bf27114410e, duration=5346.829s, table=20, n_packets=5248, n_bytes=498512, hard_timeout=300, idle_age=0, hard_age=0, priority=1,vlan_tci=0x0002/0x0fff,dl_dst=fa:16:3e:6c:ad:9c actions=load:0->NXM_OF_VLAN_TCI[],load:0x63->NXM_NX_TUN_ID[],output:2
[heat-admin@overcloud-controller-0 ~]$
[heat-admin@overcloud-controller-0 ~]$ sudo ovs-ofctl show br-tun | grep addr
 1(patch-int): addr:a2:69:00:c5:fa:ba
 2(vxlan-c0a8ff1a): addr:86:f0:ce:d0:e8:ea
 3(vxlan-c0a8ff13): addr:72:aa:73:2c:2e:5b
 LOCAL(br-tun): addr:a6:cb:cd:72:1c:45
[heat-admin@overcloud-controller-0 ~]$
[heat-admin@overcloud-controller-0 ~]$ sudo sudo ovs-appctl dpif/show | grep vxlan-c0a8ff1a
    vxlan-c0a8ff1a 2/5: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.15, remote_ip=192.168.255.26)
[heat-admin@overcloud-controller-0 ~]$ 

O tráfego passa pelo túnel até o compute-1. E no compute-1 é simples — do br-tun o pacote vai para o br-int e de lá para a interface da máquina virtual:

[heat-admin@overcloud-controller-0 ~]$ sudo sudo ovs-appctl dpif/show | grep vxlan-c0a8ff1a
    vxlan-c0a8ff1a 2/5: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.15, remote_ip=192.168.255.26)
[heat-admin@overcloud-controller-0 ~]$
[heat-admin@overcloud-novacompute-1 ~]$ sudo ovs-appctl fdb/show br-int | grep fa:16:3e:6c:ad:9c
    4     2  fa:16:3e:6c:ad:9c    1
[heat-admin@overcloud-novacompute-1 ~]$ sudo ovs-ofctl show br-int | grep addr                  
 1(int-br-ex): addr:8a:d7:f9:ad:8c:1d
 2(patch-tun): addr:46:cc:40:bd:20:da
 3(qvoe7e23f1b-07): addr:12:78:2e:34:6a:c7
 4(qvo3210e8ec-c0): addr:7a:5f:59:75:40:85
 LOCAL(br-int): addr:e2:27:b2:ed:14:46
[heat-admin@overcloud-novacompute-1 ~]$ 

Vamos verificar se esta é realmente a interface correta:

[heat-admin@overcloud-novacompute-1 ~]$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02429c001e1c       no
qbr3210e8ec-c0          8000.ea27f45358be       no              qvb3210e8ec-c0
                                                        tap3210e8ec-c0
qbre7e23f1b-07          8000.b26ac0eded8a       no              qvbe7e23f1b-07
                                                        tape7e23f1b-07
[heat-admin@overcloud-novacompute-1 ~]$
[heat-admin@overcloud-novacompute-1 ~]$ sudo virsh domiflist instance-00000004
Interface  Type       Source     Model       MAC
-------------------------------------------------------
tap3210e8ec-c0 bridge     qbr3210e8ec-c0 virtio      fa:16:3e:6c:ad:9c

[heat-admin@overcloud-novacompute-1 ~]$

Efetivamente, seguimos todo o caminho do pacote. Acho que você notou que o tráfego percorreu diferentes túneis vxlan e saiu com diferentes VNIs. Vamos ver quais são esses VNIs e, em seguida, coletar um dump na porta do nó de controle para assegurar que o tráfego realmente anda como descrito acima.
Assim, o túnel até o compute-0 tem as seguintes actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:3. Vamos converter 0x16 para o sistema decimal:


0x16 = 6*16^0+1*16^1 = 6+16 = 22

O túnel até o compute-1 tem o seguinte VNI:actions=load:0->NXM_OF_VLAN_TCI[],load:0x63->NXM_NX_TUN_ID[],output:2. Vamos converter 0x63 para o sistema decimal:


0x63 = 3*16^0+6*16^1 = 3+96 = 99

Agora vamos olhar o dump:

[root@hp-gen9 bormoglotx]# tcpdump -vvv -i vnet4 
tcpdump: ouvindo em vnet4, tipo de link EN10MB (Ethernet), tamanho da captura 262144 bytes

*****************omitted*******************

04:35:18.709949 IP (tos 0x0, ttl 64, id 48650, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.19.41591 > 192.168.255.15.4789: [sem cksum] VXLAN, flags [I] (0x08), vni 22
IP (tos 0x0, ttl 64, id 49042, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.1.85 > 10.0.2.8: ICMP echo request, id 5378, seq 9, length 64
04:35:18.710159 IP (tos 0x0, ttl 64, id 23360, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.15.38983 > 192.168.255.26.4789: [sem cksum] VXLAN, flags [I] (0x08), vni 99
IP (tos 0x0, ttl 63, id 49042, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.1.85 > 10.0.2.8: ICMP echo request, id 5378, seq 9, length 64
04:35:18.711292 IP (tos 0x0, ttl 64, id 43596, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.26.42588 > 192.168.255.15.4789: [sem cksum] VXLAN, flags [I] (0x08), vni 99
IP (tos 0x0, ttl 64, id 55103, offset 0, flags [none], proto ICMP (1), length 84)
    10.0.2.8 > 10.0.1.85: ICMP echo reply, id 5378, seq 9, length 64
04:35:18.711531 IP (tos 0x0, ttl 64, id 8555, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.15.38983 > 192.168.255.19.4789: [sem cksum] VXLAN, flags [I] (0x08), vni 22
IP (tos 0x0, ttl 63, id 55103, offset 0, flags [none], proto ICMP (1), length 84)
    10.0.2.8 > 10.0.1.85: ICMP echo reply, id 5378, seq 9, length 64
	
*****************omitted*******************

O primeiro pacote é um pacote vxlan do host 192.168.255.19 (compute-0) para o host 192.168.255.15 (control-1) com vni 22, dentro do qual está empacotado um pacote ICMP do host 10.0.1.85 para o host 10.0.2.8. Como calculamos acima, o vni corresponde ao que vimos nas saídas.

O segundo pacote é um pacote vxlan do host 192.168.255.15 (control-1) para o host 192.168.255.26 (compute-1) com vni 99, dentro do qual está empacotado um pacote ICMP do host 10.0.1.85 para o host 10.0.2.8. Como calculamos acima, o vni corresponde ao que vimos nas saídas.

Os dois pacotes seguintes são o tráfego de retorno de 10.0.2.8 para 10.0.1.85.

Ou seja, no final, temos o seguinte esquema do nó de controle:

Introdução à parte de rede da infraestrutura em nuvem

Parece que é tudo? Esquecemos de dois namespaces:

[heat-admin@overcloud-controller-0 ~]$ sudo  ip netns
qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe (id: 2)
qdhcp-7d541e74-1c36-4e1d-a7c4-0968c8dbc638 (id: 1)
qdhcp-67a3798c-32c0-4c18-8502-2531247e3cc2 (id: 0)
[heat-admin@overcloud-controller-0 ~]$ 

Como falamos sobre a arquitetura da plataforma em nuvem — seria bom que as máquinas recebessem endereços automaticamente do servidor DHCP. Esses são os dois servidores DHCP para nossas duas redes 10.0.1.0/24 e 10.0.2.0/24.

Vamos verificar se é assim. Neste namespace, há apenas um endereço — 10.0.1.1 — o endereço do próprio servidor DHCP, e ele também está incluído em br-int:

[heat-admin@overcloud-controller-0 ~]$ sudo ip netns exec qdhcp-67a3798c-32c0-4c18-8502-2531247e3cc2 ifconfig
lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 1  bytes 28 (28.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 28 (28.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

tapca25a97e-64: flags=4163  mtu 1450
        inet 10.0.1.1  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 fe80::f816:3eff:fee6:2c5c  prefixlen 64  scopeid 0x20
        ether fa:16:3e:e6:2c:5c  txqueuelen 1000  (Ethernet)
        RX packets 129  bytes 9372 (9.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 49  bytes 6154 (6.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Vamos verificar se existem processos contendo em seu nome qdhcp-67a3798c-32c0-4c18-8502-2531247e3cc2 no nó de controle:


[heat-admin@overcloud-controller-0 ~]$ ps -aux | egrep qdhcp-7d541e74-1c36-4e1d-a7c4-0968c8dbc638 
root      640420  0.0  0.0   4220   348 ?        Ss   11:31   0:00 dumb-init --single-child -- ip netns exec qdhcp-7d541e74-1c36-4e1d-a7c4-0968c8dbc638 /usr/sbin/dnsmasq -k --no-hosts --no-resolv --pid-file=/var/lib/neutron/dhcp/7d541e74-1c36-4e1d-a7c4-0968c8dbc638/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/7d541e74-1c36-4e1d-a7c4-0968c8dbc638/host --addn-hosts=/var/lib/neutron/dhcp/7d541e74-1c36-4e1d-a7c4-0968c8dbc638/addn_hosts --dhcp-optsfile=/var/lib/neutron/dhcp/7d541e74-1c36-4e1d-a7c4-0968c8dbc638/opts --dhcp-leasefile=/var/lib/neutron/dhcp/7d541e74-1c36-4e1d-a7c4-0968c8dbc638/leases --dhcp-match=set:ipxe,175 --local-service --bind-dynamic --dhcp-range=set:subnet-335552dd-b35b-456b-9df0-5aac36a3ca13,10.0.2.0,static,255.255.255.0,86400s --dhcp-option-force=option:mtu,1450 --dhcp-lease-max=256 --conf-file= --domain=openstacklocal
heat-ad+  951620  0.0  0.0 112944   980 pts/0    S+   18:50   0:00 grep -E --color=auto qdhcp-7d541e74-1c36-4e1d-a7c4-0968c8dbc638
[heat-admin@overcloud-controller-0 ~]$ 

Existe tal processo e, com base nas informações apresentadas na saída acima, podemos, por exemplo, verificar o que temos alugado no momento:

[heat-admin@overcloud-controller-0 ~]$ cat /var/lib/neutron/dhcp/7d541e74-1c36-4e1d-a7c4-0968c8dbc638/leases
1597492111 fa:16:3e:6c:ad:9c 10.0.2.8 host-10-0-2-8 01:fa:16:3e:6c:ad:9c
1597491115 fa:16:3e:76:c2:11 10.0.2.1 host-10-0-2-1 *
[heat-admin@overcloud-controller-0 ~]$

Como resultado, obtemos esse conjunto de serviços no nó de controle:

Introdução à parte de rede da infraestrutura em nuvem

E tenha em mente que isso são apenas 4 máquinas, 2 redes internas e um roteador virtual... Aqui não temos redes externas, muitos projetos diferentes, cada um com suas redes (que se sobrepõem), e temos o roteador distribuído desligado. No final das contas, no ambiente de teste havia apenas uma node de controle (para resiliência, deve haver um quórum de três nodes). É lógico que no comércio tudo é um pouco mais complicado, mas neste exemplo simples entendemos como isso deve funcionar – você pode ter 3 ou 300 namespaces, é claro que isso é importante, mas do ponto de vista do funcionamento de toda a estrutura, não muda muito… a menos que você conecte algum SDN de fornecedor. Mas essa já é uma história bem diferente.

Espero que tenha sido interessante. Se houver comentários/adicionais ou se em algum lugar eu tiver mentido grosseiramente (eu sou humano e minha opinião sempre será subjetiva) – escreva o que precisa ser corrigido/adicionado – tudo ser corrigido/adicionado.

Para concluir, gostaria de dizer algumas palavras sobre a comparação do OpenStack (tanto a versão padrão quanto as versões de fornecedores) com a solução de nuvem da VMWare – muitas pessoas me fizeram essa pergunta nos últimos dois anos e, para ser sincero, já estou cansado dela, mas mesmo assim. Na minha opinião, é muito difícil comparar essas duas soluções, mas é seguro dizer que há desvantagens em ambas as soluções e, ao escolher uma delas, é preciso pesar todos os prós e contras.

Se o OpenStack é uma solução orientada pela comunidade, a VMWare pode fazer apenas o que deseja (leia-se – o que é lucrativo para ela), e isso é lógico – porque é uma empresa comercial, acostumada a ganhar dinheiro com seus clientes. Mas há um grande e importante PORÉM – você pode sair do OpenStack, por exemplo, da Nokia e com pouco esforço migrar para uma solução da Juniper (Contrail Cloud), mas provavelmente será difícil sair da VMWare. Para mim, essas duas soluções se parecem assim – OpenStack (de fornecedor) é uma gaiola simples, na qual você é colocado, mas você tem a chave e pode sair a qualquer momento. A VMWare é uma gaiola de ouro, a chave pertence ao dono e custará muito caro a você.

Não estou me pronunciando a favor do primeiro ou do segundo produto — você escolhe o que precisa. Mas se eu tivesse que escolher, optaria por ambas as soluções — VMWare para nuvem de TI (cargas leves, gestão conveniente), OpenStack de algum fornecedor (Nokia e Juniper oferecem soluções bastante boas prontas para uso) — para nuvem de Telecom. Eu não usaria OpenStack para TI puro — seria como usar um canhão para matar um pardal, mas não vejo contraindicações para usá-lo, além da redundância. No entanto, usar VMWare em telecomunicações é como transportar brita em uma Ford Raptor — é bonito do lado de fora, mas o motorista precisa fazer 10 viagens em vez de uma.

Na minha opinião, a maior desvantagem da VMWare é seu total fechamento — a empresa não fornece nenhuma informação sobre como funciona o vSAN, por exemplo, ou o que está no núcleo do hipervisor — isso simplesmente não a beneficia — ou seja, você nunca se tornará um especialista em VMWare — sem o suporte do fornecedor, você estará perdido (muito frequentemente encontro especialistas em VMWare que ficam confusos com perguntas banais). Para mim, VMWare é como comprar um carro com o capô trancado — sim, pode ser que você tenha especialistas que podem trocar a correia do motor, mas só quem vendeu a solução pode abrir o capô. Pessoalmente, não gosto de soluções nas quais não consigo mexer. Você pode dizer que talvez não precise olhar debaixo do capô. É possível, mas vou olhar para você quando precisar montar uma grande função na nuvem com 20-30 máquinas virtuais, 40-50 redes, metade das quais quer sair para fora, e a outra metade pede aceleração SR-IOV, ou você terá que adicionar mais algumas dezenas dessas máquinas — caso contrário, o desempenho não será suficiente.

Existem outras perspectivas, portanto, cabe a você decidir o que escolher, e o mais importante — você terá que responder por sua escolha depois. Esta é apenas a minha opinião — de alguém que viu e manipulou pelo menos 4 produtos — Nokia, Juniper, Red Hat e VMWare. Ou seja, eu tenho com o que comparar.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster