
L'informatica cloud penetra sempre di più nella nostra vita e ormai non c'è quasi nessuna persona che non abbia mai utilizzato qualche servizio cloud. Ma cos'è esattamente il cloud e come funziona, in gran parte, pochi lo sanno anche a livello teorico. Il 5G sta diventando una realtà e l'infrastruttura telecom inizia a passare da soluzioni hardware a soluzioni cloud, così come è avvenuto quando si è passati da soluzioni completamente fisiche a «pilastri» virtualizzati.
Oggi parleremo del mondo interiore dell'infrastruttura cloud e, in particolare, esamineremo le basi della parte di rete.
Cos'è il cloud? È forse la stessa virtualizzazione, vista da un'altra angolazione?
Una domanda più che legittima. No, non è virtualizzazione, anche se questa gioca un ruolo importante. Analizziamo due definizioni:
L'informatica cloud (di seguito Cloud) è un modello di fornitura di accesso utente a risorse di calcolo distribuite, che devono essere attivate e utilizzate su richiesta con la minima latenza possibile e a costi minimi per il fornitore di servizi.
Virtualizzazione è la possibilità di suddividere un'unica entità fisica (ad esempio un server) in più entità virtuali, aumentando così l'utilizzo delle risorse (ad esempio, se avevi 3 server utilizzati al 25-30%, dopo la virtualizzazione ottieni 1 server utilizzato all'80-90%). È evidente che la virtualizzazione consuma parte delle risorse — devi alimentare l'hypervisor, tuttavia, come ha dimostrato la pratica, ne vale la pena. Un esempio ideale di virtualizzazione è VMWare, che gestisce magnificamente le macchine virtuali, o ad esempio KVM, che preferisco, ma questo è già una questione di gusto.
Utilizziamo la virtualizzazione senza nemmeno rendercene conto, e anche i router fisici utilizzano già la virtualizzazione — per esempio, nelle ultime versioni di JunOS, il sistema operativo viene installato come macchina virtuale sopra una distribuzione di Linux in tempo reale (Wind River 9). Ma la virtualizzazione non è il cloud, tuttavia il cloud non può esistere senza la virtualizzazione.
La virtualizzazione è uno dei mattoni su cui si costruisce il cloud.
Creare un cloud semplicemente unendo più hypervisor in un unico dominio L2, aggiungendo un paio di playbook yaml per la configurazione automatica delle VLAN tramite qualche ansible e sovrapponendo a tutto ciò un sistema di orchestrazione per la creazione automatica di macchine virtuali non funziona. In realtà funziona, ma il Frankestein risultante non è quel cloud di cui abbiamo bisogno, anche se per alcuni potrebbe essere il massimo dei sogni. Inoltre, se prendiamo lo stesso Openstack, in effetti è anch'esso un grande Frankenstein, ma lasciamo perdere per ora.
Ma capisco che dalla definizione fornita sopra non è del tutto chiaro cosa si possa realmente definire cloud.
Pertanto, nel documento del NIST (National Institute of Standards and Technology) sono elencate 5 caratteristiche fondamentali che un'infrastruttura cloud deve avere:
Fornitura di servizi su richiesta. L'utente deve avere libero accesso alle risorse informatiche a lui dedicate (come reti, dischi virtuali, memoria, core di processore, ecc.) e queste risorse devono essere fornite automaticamente, cioè senza intervento da parte del fornitore di servizi.
Ampia disponibilità del servizio. L'accesso alle risorse deve essere garantito tramite meccanismi standard per poter utilizzare sia PC standard che client leggeri e dispositivi mobili.
Unione delle risorse in pool. I pool di risorse devono garantire la fornitura simultanea di risorse a più clienti, assicurando l'isolamento dei clienti e l'assenza di influenza reciproca tra di essi e competizione per le risorse. I pool includono anche reti, il che implica la possibilità di utilizzare indirizzamenti sovrapposti. I pool devono supportare la scalabilità su richiesta. L'uso di pool consente di garantire il livello necessario di resilienza delle risorse e l'astrazione delle risorse fisiche e virtuali: al destinatario del servizio viene semplicemente fornito il set di risorse richiesto (dove queste risorse sono fisicamente posizionate, su quanti server e switch, non importa al cliente). Tuttavia, è necessario considerare che il fornitore deve garantire un'adeguata riserva di queste risorse.
Rapida adattabilità a diverse condizioni. I servizi devono essere flessibili: fornire rapidamente risorse, ripartire, aggiungere o ridurre risorse su richiesta del cliente, e il cliente deve avere l'impressione che le risorse del cloud siano infinite. Per semplicità, ad esempio, non vedete un avviso che vi informa che nel vostro spazio su Apple iCloud è scomparsa una parte dello spazio su disco a causa di un guasto del disco rigido, e i dischi si guastano. Inoltre, da parte vostra, le possibilità di questo servizio sono praticamente illimitate: avete bisogno di 2 Tb? Nessun problema, pagate e ricevete. Un esempio simile può essere fatto con Google.Drive o Yandex.Disk.
La possibilità di misurare il servizio fornito. I sistemi cloud devono controllare e ottimizzare automaticamente le risorse consumate, e questi meccanismi devono essere trasparenti sia per l'utente che per il fornitore di servizi. Ciò significa che potete sempre controllare quante risorse voi e i vostri clienti consumate.
Si deve considerare il fatto che questi requisiti sono per lo più requisiti per il cloud pubblico, quindi per il cloud privato (cioè il cloud avviato per scopi interni dell'azienda) questi requisiti possono essere leggermente corretti. Tuttavia, devono comunque essere rispettati, altrimenti non otterremo tutti i vantaggi del cloud computing.
Perché ci serve il cloud?
Tuttavia, ogni nuova tecnologia o protocollo esistente, ogni nuovo protocollo, è creato per uno scopo (tranne che per il RIP-ng, ovviamente). Un protocollo creato per il solo fatto di essere un protocollo non ha senso (tranne che per il RIP-ng, ovviamente). È logico che il Cloud venga creato per fornire un servizio a un utente/cliente. Siamo tutti familiari con almeno un paio di servizi cloud, come Dropbox o Google.Docs, e presumo che la maggior parte delle persone li utilizzi con successo: ad esempio, questo articolo è stato scritto utilizzando il servizio cloud Google.Docs. Ma i servizi cloud che conosciamo sono solo una parte delle possibilità del cloud; in effetti, sono solo servizi di tipo SaaS. Possiamo fornire un servizio cloud in tre modalità: come SaaS, PaaS o IaaS. Quale servizio serva a voi dipende dai vostri desideri e possibilità.
Consideriamo ciascuno nel dettaglio:
Software as a Service (SaaS) — è un modello di fornitura di un servizio completo al cliente, come un servizio di posta elettronica tipo Yandex.Mail o Gmail. In questo modello di fornitura del servizio, lei, in quanto cliente, di fatto non fa nulla, se non utilizzare il servizio: cioè non deve pensare alla configurazione del servizio, alla sua tolleranza ai guasti o al ripristino. L'importante è non compromettere la propria password, tutto il resto sarà gestito dal fornitore di questo servizio. Dal punto di vista del fornitore del servizio, egli è completamente responsabile dell'intero servizio, a partire dall'hardware server e dai sistemi operativi host, fino alla configurazione dei database e del software.
Piattaforma come Servizio (PaaS) — utilizzando questo modello, il fornitore di servizi offre al cliente un'assegnazione per il servizio, come ad esempio un server Web. Il fornitore di servizi ha fornito al cliente un server virtuale (in effetti un insieme di risorse, come RAM / CPU / Storage / Nets, ecc.), e ha anche installato sul server il sistema operativo e il software necessario, ma la configurazione di tutto ciò è a carico del cliente e il cliente è già responsabile del funzionamento del servizio. Come nel caso precedente, il fornitore di servizi è responsabile del funzionamento dell'hardware fisico, degli hypervisor, della macchina virtuale stessa, della sua accessibilità di rete, ecc., ma il servizio stesso esula dalla sua responsabilità.
Infrastruttura come Servizio (IaaS) — questo approccio è già più interessante, poiché il fornitore di servizi offre al cliente un'infrastruttura completamente virtualizzata, cioè un certo insieme (pool) di risorse, come CPU Cores, RAM, Reti, ecc. Tutto il resto è compito del cliente: cosa vuole fare il cliente con queste risorse all'interno del pool (quota) assegnato, non è di particolare importanza per il fornitore. Se il cliente vuole creare il proprio vEPC o addirittura diventare un mini operatore e fornire servizi di telecomunicazione, non ci sono problemi: si faccia. In questo scenario, il fornitore di servizi è responsabile della fornitura delle risorse, della loro tolleranza ai guasti e disponibilità, e anche del sistema operativo che consente di aggregare queste risorse in pool e fornirle al cliente, con la possibilità di aumentare o diminuire le risorse a richiesta del cliente. Tutte le macchine virtuali e altre configurazioni il cliente le gestisce autonomamente attraverso il portale di self-service e la console, inclusa la configurazione delle reti (eccetto le reti esterne).
Che cos'è OpenStack?
In tutti e tre i casi, al fornitore di servizi è necessario un sistema operativo che consenta di creare un'infrastruttura cloud. In realtà, con il SaaS, non è un'unica divisione a rispondere per l'intero stack di tecnologie — c'è una divisione che si occupa dell'infrastruttura, ovvero offre IaaS ad un'altra divisione, mentre questa divisione fornisce SaaS ai clienti. OpenStack è uno dei sistemi operativi cloud che consente di aggregare vari switch, server e sistemi di storage in un unico pool di risorse, suddividere questo pool comune in sottopools (tenant) e fornire queste risorse ai clienti attraverso la rete.
OpenStack è un sistema operativo cloud che consente di controllare grandi pool di risorse computazionali, di archiviazione dei dati e di rete, il provisioning e la gestione avvengono attraverso API utilizzando meccanismi standard di autenticazione.
In altre parole, è un insieme di progetti di software libero destinato alla creazione di servizi cloud (sia pubblici che privati) — ovvero un insieme di strumenti che permette di unire l'hardware server e di rete in un unico pool di risorse, gestire queste risorse e garantire il livello necessario di resilienza.
Al momento della stesura di questo materiale, la struttura di OpenStack è la seguente:

L'immagine è tratta da
Ognuna delle componenti che compongono OpenStack svolge una funzione specifica. Questa architettura distribuita consente di includere nella soluzione un insieme di componenti funzionali necessari. Tuttavia, alcune componenti sono considerate componenti fondamentali e la loro rimozione porterà a un non funzionamento totale o parziale della soluzione nel suo complesso. A queste componenti vengono generalmente attribuite:
- Dashboard — GUI basata su web per la gestione dei servizi OpenStack
- Keystone — servizio di identità centralizzato, che fornisce funzionalità di autenticazione e autorizzazione per altri servizi, e gestisce le credenziali degli utenti e i loro ruoli.
- Neutron è il servizio di rete che garantisce la connettività tra le interfacce dei vari servizi OpenStack (inclusa la connettività tra VM e l'accesso al mondo esterno)
- Cinder fornisce accesso a storage a blocchi per le macchine virtuali
- Nova — gestione del ciclo di vita delle macchine virtuali
- Glance — repository di immagini di macchine virtuali e snapshot
- Swift — fornisce accesso allo storage degli oggetti
- Ceilometer — servizio che consente la raccolta di telemetria e la misura delle risorse disponibili e consumate
- Heat — orchestrazione basata su modelli per la creazione automatica e il provisioning delle risorse
L'elenco completo di tutti i progetti e i rispettivi scopi può essere visualizzato .
Ciascuna delle componenti di OpenStack è un servizio che gestisce una funzione specifica e fornisce API per la gestione di tale funzione e per l'interazione del servizio con altri servizi del sistema operativo cloud, al fine di creare un'infrastruttura unica. Ad esempio, Nova gestisce le risorse di calcolo e fornisce API per accedere alla configurazione di tali risorse, Glance – gestione delle immagini e API per la loro gestione, Cinder – storage a blocchi e API per la sua gestione, ecc. Tutte le funzioni sono strettamente interconnesse.
Tuttavia, se ci si pensa, tutti i servizi eseguiti in OpenStack rappresentano, in ultima analisi, una qualsiasi macchina virtuale (o contenitore) collegata alla rete. Si pone la domanda: perché abbiamo bisogno di così tanti elementi?
Facciamo una breve panoramica dell'algoritmo per creare una macchina virtuale e collegarla alla rete e a uno storage persistente in OpenStack.
- Quando richiedi la creazione di una macchina, sia essa una richiesta tramite Horizon (Dashboard) o una richiesta tramite CLI, la prima cosa che accade è l'autenticazione della tua richiesta a Keystone – puoi creare la macchina, hai il diritto di utilizzare questa rete, il tuo progetto ha sufficiente quota, ecc.
- Keystone autentica la tua richiesta e genera un auth-token nella risposta, che verrà utilizzato in seguito. Ricevuta la risposta da Keystone, la richiesta viene inviata a Nova (nova api).
- Nova-api verifica la validità della tua richiesta, collegandosi a Keystone, utilizzando l'auth-token generato in precedenza.
- Keystone effettua l'autenticazione e fornisce, sulla base di questo auth-token, informazioni sui permessi e sulle limitazioni.
- Nova-api crea un record di nuova VM nel nova-database e invia la richiesta per la creazione della macchina a nova-scheduler.
- Il nova-scheduler seleziona un host (nodo computer) su cui la VM sarà distribuita in base ai parametri specificati, pesi e zone. La registrazione di questo e l'identificativo della VM vengono memorizzati nel nova-database.
- Successivamente, il nova-scheduler si rivolge a nova-compute per richiedere il deployment di un'istanza. Nova-compute contatta nova-conductor per ottenere informazioni sui parametri della macchina (nova-conductor è un componente di nova che funge da proxy tra nova-database e nova-compute, limitando il numero di richieste verso nova-database per evitare problemi di coerenza del database e ridurre il carico).
- Nova-conductor riceve le informazioni richieste da nova-database e le invia a nova-compute.
- Successivamente, nova-compute si rivolge a glance per ottenere l'ID dell'immagine. Glance valida la richiesta in Keystone e restituisce le informazioni richieste.
- Nova-compute si rivolge a neutron per ottenere informazioni sui parametri di rete. Analogamente a glance, neutron convalida la richiesta in Keystone, poi crea una registrazione nel database (identificatore della porta, ecc.), genera una richiesta per la creazione della porta e restituisce le informazioni richieste a nova-compute.
- Nova-compute contatta cinder per richiedere l'assegnazione di un volume alla macchina virtuale. Analogamente a glance, cinder valida la richiesta in Keystone, crea una richiesta per la creazione del volume e restituisce le informazioni richieste.
- Nova-compute contatta libvirt per richiedere il deployment della macchina virtuale con i parametri specificati.
Di fatto, un'operazione apparentemente semplice come la creazione di una macchina virtuale diventa un turbinio di chiamate API tra gli elementi della piattaforma cloud. Inoltre, come potete vedere, anche i servizi precedentemente indicati sono composti da componenti più piccoli che interagiscono tra loro. La creazione di una macchina è solo una piccola parte di ciò che la piattaforma cloud permette di fare: esistono servizi dedicati al bilanciamento del traffico, allo storage a blocchi, al DNS, al provisioning dei server bare metal, e così via. Il cloud consente di trattare le macchine virtuali come un gregge di pecore (a differenza della virtualizzazione). Se in un ambiente virtuale qualcosa accade a una macchina, la si ripristina dai backup, ma le applicazioni cloud sono progettate in modo tale che la macchina virtuale non giochi un ruolo così importante: la macchina virtuale "è morta"? Nessun problema: si crea semplicemente una nuova macchina basata su un template e, come si suol dire, l'unità non si accorge della perdita del soldato. Naturalmente, ciò richiede meccanismi di orchestrazione: utilizzando i template Heat, è possibile implementare senza particolari problemi funzioni complesse composte da decine di reti e macchine virtuali.
È sempre importante tenere a mente che non esiste infrastruttura cloud senza rete: ogni elemento interagisce in un modo o nell'altro con altri elementi tramite la rete. Inoltre, la rete cloud non è affatto statica. Naturalmente, la rete di base è relativamente statica: non si aggiungono nuovi nodi e switch ogni giorno; tuttavia, la componente overlay può cambiare e cambierà inevitabilmente in modo costante: nuove reti verranno aggiunte o rimosse, verranno create nuove macchine virtuali e altre vecchie scompariranno. Come ricordate dalla definizione di cloud fornita all'inizio dell'articolo, le risorse devono essere assegnate all'utente automaticamente e con il minimo (se non nullo) intervento da parte del fornitore di servizi. Quindi, il tipo di fornitura delle risorse di rete che abbiamo attualmente sotto forma di interfaccia frontend nel vostro pannello personale accessibile via http/https con l'ingegnere di rete di guardia Vasily come backend non è un cloud, nemmeno con otto braccia.
Neutron, essendo un servizio di rete, fornisce un'API per la gestione della parte di rete dell'infrastruttura cloud. Il servizio garantisce il funzionamento e la gestione della parte di rete di OpenStack, offrendo un livello di astrazione noto come Network-as-a-Service (NaaS). Cioè, la rete è un'unità virtuale misurabile, proprio come i core virtuali della CPU o la quantità di RAM.
Ma prima di passare all'architettura della parte di rete di OpenStack, esaminiamo come questa rete funzioni in OpenStack e perché la rete sia una parte importante e imprescindibile del cloud.
Quindi, abbiamo due macchine virtuali del cliente RED e due macchine virtuali del cliente GREEN. Supponiamo che queste macchine siano disposte su due hypervisor in questo modo:

Al momento si tratta semplicemente di una virtualizzazione di 4 server e non di più, poiché finora abbiamo solo virtualizzato 4 server, posizionandoli su due server fisici. Inoltre, attualmente non sono nemmeno collegati alla rete.
Per creare un cloud dobbiamo aggiungere alcuni componenti. Innanzitutto, virtualizziamo la parte di rete: dobbiamo collegare queste 4 macchine a coppie, e i clienti richiedono specificamente una connessione L2. Possiamo usare ovviamente uno switch e configurare un trunk verso di esso, gestendo tutto con un bridge Linux oppure, per utenti più esperti, Open vSwitch (a cui torneremo). Ma le reti possono essere molte e continuare a spingere L2 attraverso uno switch non è la migliore idea: diversi reparti, servizio di assistenza, mesi in attesa dell'elaborazione della richiesta, settimane di troubleshooting — nel mondo moderno questo approccio non funziona più. E prima un'azienda comprende questo, più facile sarà per essa procedere. Pertanto, tra gli hypervisor, predisporremo una rete L3 attraverso la quale comunicheranno le nostre macchine virtuali, e su questa rete L3 costruiremo delle reti overlay L2, dove correrà il traffico delle nostre macchine virtuali. Possiamo utilizzare GRE, Geneve o VxLAN per l'incapsulamento. Per ora ci fermeremo sull'ultimo, anche se questo non è particolarmente importante.
Dobbiamo collocare da qualche parte il VTEP (spero che tutti conoscano la terminologia VxLAN). Poiché dai server esce immediatamente una rete L3, nulla ci impedisce di posizionare il VTEP sui server stessi, e OVS (Open vSwitch) è perfettamente in grado di farlo. Alla fine, abbiamo ottenuto questa configurazione:

Poiché il traffico tra le VM deve essere separato, le porte verso le macchine virtuali avranno numeri VLAN diversi. Il numero del tag ha importanza solo all'interno di uno switch virtuale, poiché durante l'incapsulamento in VxLAN possiamo rimuoverlo senza problemi, poiché avremo un VNI.

Ora possiamo creare le nostre macchine e le reti virtuali per esse senza alcun problema.
Tuttavia, cosa succede se il cliente ha un'altra macchina, ma si trova in un'altra rete? Abbiamo bisogno di routing tra le reti. Esamineremo un'opzione semplice, quando viene utilizzato un routing centralizzato, cioè il traffico viene instradato attraverso nodi di rete dedicati (di solito combinati con nodi di controllo, quindi avremo la stessa cosa).
Sembra facile: creiamo un'interfaccia bridge sul nodo di controllo, facciamo passare il traffico su di essa e da lì lo instradiamo dove ci serve. Ma il problema è che il cliente RED desidera utilizzare la rete 10.0.0.0/24 e il cliente GREEN desidera utilizzare la rete 10.0.0.0/24. Cioè, abbiamo un'intersezione degli spazi degli indirizzi. Inoltre, i clienti non vogliono che altri clienti possano essere instradati nelle loro reti interne, il che è logico. Per separare le reti e il traffico dei clienti, assegneremo a ciascuno di loro uno spazio dei nomi separato. Uno spazio dei nomi è di fatto una copia dello stack di rete Linux, cioè i clienti nello spazio dei nomi RED sono completamente isolati dai clienti nello spazio dei nomi GREEN (a meno che il routing tra questi spazi dei nomi non sia consentito tramite lo spazio dei nomi predefinito o già su attrezzature di trasporto di livello superiore).
Quindi otteniamo uno schema del genere:

I tunnel L2 convergono da tutti i nodi di calcolo sul nodo di controllo, dove si trova l'interfaccia L3 per queste reti, ognuna in uno spazio dei nomi dedicato per l'isolamento.
Tuttavia, abbiamo dimenticato la cosa più importante. La macchina virtuale deve fornire un servizio al cliente, ovvero deve avere almeno un'interfaccia esterna attraverso la quale possa essere contattata. Quindi, dobbiamo uscire nel mondo esterno. Ci sono diverse opzioni. Facciamo la soluzione più semplice. Aggiungeremo una rete a ciascun cliente, che sarà valida nella rete del provider e non si sovrapporrà ad altre reti. Le reti possono anche sovrapporsi e puntare a diverse VRF dalla parte della rete del provider. Queste reti vivranno anche nello spazio dei nomi di ciascun cliente. Tuttavia, usciranno comunque nel mondo esterno attraverso un'unica interfaccia fisica (o bond, cosa più logica). Per dividere il traffico dei clienti, il traffico esterno sarà gestito tramite la marcatura VLAN con un tag assegnato al cliente.
Alla fine abbiamo ottenuto questo schema:

Una domanda legittima è: perché non creare i gateway direttamente sui nodi di calcolo? Non c'è un grande problema in questo, anzi, attivando il router distribuito (DVR) funzionerà proprio in questo modo. In questo scenario, consideriamo la soluzione più semplice con un gateway centralizzato, che in OpenStack è utilizzato di default. Per funzionalità ad alto carico verranno utilizzati sia il router distribuito che tecnologie di accelerazione tipo SR-IOV e Passthrough, ma come si suol dire, questa è già un'altra storia. Per prima cosa, concentriamoci sulla parte di base e poi entreremo nei dettagli.
In realtà, il nostro schema è già funzionante, ma ci sono un paio di dettagli:
- Dobbiamo in qualche modo proteggere le nostre macchine, quindi dobbiamo applicare un filtro sull'interfaccia dello switch lato cliente.
- Creare la possibilità di ottenere automaticamente un indirizzo IP dalla macchina virtuale, in modo da non dover sempre accedere a essa tramite la console per impostare l'indirizzo.
Iniziamo con la protezione delle macchine. A questo scopo, possiamo usare i comuni iptables, perché no.
Quindi ora la nostra topologia si è già un po' complicata:

Andiamo avanti. Dobbiamo aggiungere un server DHCP. Il luogo ideale per posizionare i server DHCP per ciascun cliente sarà la già menzionata nodi di controllo, dove si trovano gli spazi dei nomi:

Tuttavia, c'è un piccolo problema. Cosa succede se tutto si riavvia e tutte le informazioni sugli indirizzi di affitto su DHCP scompaiono? È logico che ai computer vengano assegnati nuovi indirizzi, il che non è molto comodo. Qui ci sono due opzioni: o utilizzare nomi di dominio e aggiungere un server DNS per ogni client, in tal caso l'indirizzo non sarà particolarmente importante (analogamente alla parte di rete in k8s) — ma qui ci sono problemi con le reti esterne, poiché anche in esse gli indirizzi possono essere assegnati tramite DHCP — è necessaria una sincronizzazione tra i server DNS della piattaforma cloud e il server DNS esterno, il che, a mio avviso, non è molto flessibile, ma è comunque fattibile. Oppure la seconda opzione — utilizzare i metadata — cioè salvare le informazioni sull'indirizzo assegnato alla macchina in modo che il server DHCP sappia quale indirizzo assegnare alla macchina, se questa ha già ricevuto un indirizzo. La seconda opzione è più semplice e flessibile, poiché consente di mantenere ulteriori informazioni sulla macchina. Ora aggiungiamo alla mappa l'agente dei metadata:

Un'altra questione che merita di essere trattata è la possibilità di utilizzare una rete esterna comune da parte di tutti i clienti. Poiché le reti esterne devono essere valide in tutta la rete, ci saranno delle complessità — sarà necessario assegnare e controllare continuamente queste reti. La possibilità di utilizzare una rete preconfigurata unificata per tutti i clienti sarà molto utile nella creazione di un cloud pubblico. Questo semplificherà il dispiegamento delle macchine, poiché non sarà necessario fare riferimenti a un database di indirizzi e selezionare uno spazio di indirizzamento unico per la rete esterna di ogni cliente. Inoltre, possiamo definire la rete esterna in anticipo e al momento del dispiegamento ci basterà associare gli indirizzi esterni con le macchine dei clienti.
E qui ci viene in aiuto il NAT: semplicemente permetteremo ai client di accedere al mondo esterno attraverso il namespace predefinito utilizzando la traduzione NAT. Ma qui c'è un piccolo problema. Va bene se il server client funge da client e non da server, cioè avvia anziché ricevere connessioni. Ma nel nostro caso sarà l'opposto. In quel caso dobbiamo fare un destination NAT affinché la nodi di controllo comprenda che il traffico ricevuto è destinato alla macchina virtuale A del cliente A, il che significa che è necessario effettuare una traduzione NAT dall'indirizzo esterno, ad esempio 100.1.1.1 all'indirizzo interno 10.0.0.1. In questo caso, sebbene tutti i client utilizzino una rete comune, l'isolamento interno è completamente mantenuto. Dobbiamo quindi implementare dNAT e sNAT sulla nodi di controllo. L'uso di una rete unica con assegnazione di indirizzi variabili o reti esterne, o entrambe le cose contemporaneamente, dipende da ciò che si desidera portare nel cloud. Non aggiungeremo indirizzi variabili allo schema, ma manterremo le reti esterne già precedentemente aggiunte: ogni cliente ha la propria rete esterna (indicate nello schema come vlan 100 e 200 sull'interfaccia esterna).
Alla fine abbiamo ottenuto una soluzione interessante e allo stesso tempo ben ponderata, che possiede una certa flessibilità ma attualmente non dispone di meccanismi di tolleranza ai guasti.
Innanzitutto abbiamo solo una nodi di controllo: il suo guasto porterà al collasso di tutti i sistemi. Per risolvere questo problema, è necessario avere almeno un quorum di 3 nodi. Aggiungiamo questo allo schema:

Naturalmente, tutte le nodi si sincronizzeranno e in caso di guasto di una nodi attiva, le sue funzioni saranno assunte da un'altra nodi.
Il problema successivo sono i dischi delle macchine virtuali. Attualmente sono memorizzati sugli ipervisor e in caso di problemi con l'ipervisor perdiamo tutti i dati, e avere un raid non aiuta se perdiamo non un disco, ma l'intero server. Per questo dobbiamo creare un servizio che funzioni come front-end per qualche tipo di archiviazione. Non ci importa molto quale sarà questa archiviazione, ma deve proteggere i nostri dati da guasti sia del disco che della nodi, e forse anche dell'intero armadio. Ci sono diverse opzioni — ci sono naturalmente reti SAN con Fiber Channel, ma diciamolo chiaramente: FC è già un relitto del passato — l'equivalente di E1 nei trasporti — sì, sono d'accordo, è ancora utilizzato, ma solo dove semplicemente non se ne può fare a meno. Pertanto, non mi espanderei volontariamente su una rete FC nel 2020, sapendo dell'esistenza di altre alternative più interessanti. Anche se ognuno ha le proprie preferenze e potrebbero esserci quelli che ritengono che FC con tutte le sue limitazioni sia tutto ciò di cui abbiamo bisogno — non intendo discutere, ognuno ha la propria opinione. Tuttavia, la soluzione più interessante secondo me è l'uso del SDS, ad esempio Ceph.
Ceph consente di costruire una soluzione altamente disponibile per l'archiviazione dei dati con un'ampia gamma di opzioni di ridondanza, dai codici a verifica di parità (corrispondenti a RAID 5 o 6) fino alla replica completa dei dati su dischi diversi tenendo conto della posizione dei dischi nei server e dei server negli armadi, e così via.
Per assemblare Ceph sono necessarie ulteriori 3 nodi. L'interazione con l'archiviazione avverrà anche attraverso la rete utilizzando servizi di archiviazione a blocchi, oggetti e file. Aggiungiamo alla schema di archiviazione:

Nota: è possibile anche creare nodi compute iperconvergenti, un concetto che unisce più funzioni in un unico nodo, ad esempio storage+compute, senza dover dedicare nodi speciali al Ceph storage. Otterremo uno schema altrettanto resistente agli errori, poiché SDS riserva i dati con il livello di ridondanza che abbiamo specificato. Tuttavia, i nodi iperconvergenti sono sempre un compromesso, poiché il nodo di storage non serve solo a riempire spazio come potrebbe sembrare a prima vista (poiché non ospita macchine virtuali) ma consuma risorse CPU per gestire SDS (di fatto, esegue in background tutte le replicazioni, i ripristini dopo guasti di nodi, dischi, ecc.). Questo significa che perderai parte della potenza del nodo compute se lo combini con lo storage.
Tutte queste risorse devono essere gestite in qualche modo: abbiamo bisogno di qualcosa attraverso cui possiamo creare macchine, reti, router virtuali, ecc. A tal fine, aggiungeremo un servizio al nodo di controllo che fungerà da dashboard: il client potrà collegarsi a questo portale tramite http/https e fare tutto ciò di cui ha bisogno (quasi).
Alla fine, ora abbiamo un sistema resistente agli errori. Tutti gli elementi di questa infrastruttura devono essere gestiti in qualche modo. Come già descritto, OpenStack è un insieme di progetti, ognuno dei quali offre qualche funzione specifica. Come possiamo vedere, ci sono più che sufficienti elementi da configurare e controllare. Oggi parleremo della parte di rete.
Architettura Neutron
In OpenStack, Neutron è responsabile della connessione delle porte delle macchine virtuali alla rete L2 comune, della gestione della routing del traffico tra le VM che si trovano in diverse reti L2 e della routing verso l'esterno, fornendo servizi come NAT, Floating IP, DHCP, ecc.
Il funzionamento di alto livello del servizio di rete (parte fondamentale) può essere descritto così.
Quando viene avviata una VM, il servizio di rete:
- Crea una porta per questa VM (o porte) e notifica il servizio DHCP;
- Viene creato un nuovo dispositivo di rete virtuale (tramite libvirt);
- La VM si collega alla porta (o porte) creata al primo passo;
Stranamente, alla base del funzionamento di Neutron ci sono meccanismi standard noti a tutti coloro che hanno mai avuto a che fare con Linux: namespaces, iptables, ponti linux, openvswitch, conntrack, ecc.
Va subito chiarito che Neutron non è un controller SDN.
Neutron è composto da diversi componenti interconnessi:

Openstack-neutron-server — è un demone che lavora con richieste utente tramite API. Questo demone non si occupa di stabilire connessioni di rete, ma fornisce le informazioni necessarie ai suoi plugin, che successivamente configurano l'elemento di rete richiesto. Gli agenti Neutron sui nodi OpenStack si registrano sul server Neutron.
Neutron-server è fondamentalmente un'applicazione scritta in Python, composta da due parti:
- Servizio REST
- Plugin Neutron (core/service)
Il servizio REST è destinato a ricevere chiamate API dai componenti restanti (ad esempio, una richiesta per fornire informazioni, ecc.).
I plugin sono componenti/moduli software connessi che vengono attivati durante le richieste API, ovvero la registrazione di un qualche servizio avviene tramite essi. I plugin si dividono in due tipi: plugin di servizio e plugin core. Di solito, il plugin core è responsabile principalmente della gestione dello spazio degli indirizzi e delle connessioni L2 tra VM, mentre i plugin di servizio forniscono funzionalità aggiuntive come VPN o FW.
L'elenco dei plugin disponibili oggi può essere visualizzato ad esempio
Possono esserci diversi plugin di servizio, ma può esserci solo un plugin core.
Openstack-neutron-ml2 — è il plugin core standard di Openstack. Questo plugin ha un'architettura modulare (a differenza del suo predecessore) e configura il servizio di rete tramite driver a esso collegati. Esamineremo il plugin più avanti, poiché in effetti offre la flessibilità che OpenStack ha nella parte di rete. Il plugin core può essere sostituito (ad esempio, Contrail Networking fa tale sostituzione).
Servizio RPC (rabbitmq-server) — servizio che gestisce le code e l'interazione con altri servizi OpenStack, nonché l'interazione tra agenti del servizio di rete.
Gli agenti di rete — agenti che si trovano in ciascun nodo, tramite i quali vengono configurati i servizi di rete.
Gli agenti possono essere di diversi tipi.
L'agente principale è agente L2. Questi agenti vengono avviati su ciascuno degli ipervisori, comprese le nodi di controllo (per essere più precisi, su tutti i nodi che forniscono qualche servizio per i tenant) e la loro funzione principale è connettere le macchine virtuali alla rete L2 condivisa, oltre a generare avvisi in caso di eventi (ad esempio disconnessione/riaccensione di una porta).
Il successivo agente, altrettanto importante, è l'agente L3. Per impostazione predefinita, questo agente viene avviato esclusivamente sul nodo di rete (spesso il nodo di rete si combina con il nodo di controllo) e garantisce il routing tra le reti dei tenant (sia tra le sue reti e quelle di altri tenant, sia con accesso al mondo esterno, fornendo NAT, e anche il servizio DHCP). Tuttavia, nell'uso del DVR (router distribuito), la necessità del plugin L3 si presenta anche sui nodi di calcolo.
L'agente L3 utilizza i namespace Linux per fornire a ciascun tenant un insieme di reti isolate e le funzionalità dei router virtuali, che instradano il traffico e offrono servizi di gateway per le reti di livello 2.
Database — un database di identificatori di reti, sottoreti, porte, pool, ecc.
In effetti, Neutron riceve richieste API per la creazione di entità di rete, autentica la richiesta e, tramite RPC (se si sta rivolgendo a un plugin o agente) o REST API (se comunica con SDN), trasmette agli agenti (attraverso i plugin) le istruzioni necessarie per effettuare il servizio richiesto.
Ora rivolgiamoci all'installazione di test (come è stata implementata e cosa ne fa parte lo vedremo più avanti nella parte pratica) e vediamo dove si trovano le varie componenti:
(overcloud) [stack@undercloud ~]$ openstack network agent list
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| ID | Tipo di agente | Host | Zona di disponibilità | Vivo | Stato | Binario |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| 10495de9-ba4b-41fe-b30a-b90ec3f8728b | Agente Open vSwitch | overcloud-novacompute-1.localdomain | Nessuno | :-) | SU | neutron-openvswitch-agent |
| 1515ad4a-5972-46c3-af5f-e5446dff7ac7 | Agente L3 | overcloud-controller-0.localdomain | nova | :-) | SU | neutron-l3-agent |
| 322e62ca-1e5a-479e-9a96-4f26d09abdd7 | Agente DHCP | overcloud-controller-0.localdomain | nova | :-) | SU | neutron-dhcp-agent |
| 9c1de2f9-bac5-400e-998d-4360f04fc533 | Agente Open vSwitch | overcloud-novacompute-0.localdomain | Nessuno | :-) | SU | neutron-openvswitch-agent |
| d99c5657-851e-4d3c-bef6-f1e3bb1acfb0 | Agente Open vSwitch | overcloud-controller-0.localdomain | Nessuno | :-) | SU | neutron-openvswitch-agent |
| ff85fae6-5543-45fb-a301-19c57b62d836 | Agente Metadata | overcloud-controller-0.localdomain | Nessuno | :-) | SU | neutron-metadata-agent |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
(overcloud) [stack@undercloud ~]$ 
Questa è l'intera struttura di Neutron. Ora vale la pena dedicare un po' di tempo al plugin ML2.
Modular Layer 2
Come già detto, il plugin è il plugin radice standard di OpenStack ed ha un'architettura modulare.
Il predecessore del plugin ML2 aveva una struttura monolitica che non permetteva, ad esempio, di utilizzare un mix di diverse tecnologie in un'unica installazione. Ad esempio, non era possibile utilizzare sia openvswitch che linuxbridge contemporaneamente — o uno o l'altro. Per questo motivo è stato creato il plugin ML2 con la sua architettura.
ML2 ha due componenti: due tipi di driver: Type drivers e Mechanism drivers.
Type drivers definiscono le tecnologie che saranno utilizzate per organizzare le connessioni di rete, come VxLAN, VLAN, GRE. Questi driver consentono di utilizzare tecnologie diverse. La tecnologia standard è la VxLAN per l'incapsulamento nelle reti overlay e VLAN per le reti esterne.
I seguenti tipi di reti appartengono ai Type drivers:
Piatta — rete senza tagging
VLAN — rete taggata
Local — tipo speciale di rete per installazioni di tipo all-in-one (queste installazioni sono necessarie o per sviluppatori o per formazione)
GRE — rete overlay che utilizza tunnel GRE
VxLAN — rete overlay che utilizza tunnel VxLAN
Mechanism drivers definiscono i mezzi che garantiscono l'organizzazione delle tecnologie indicate in type driver — ad esempio, openvswitch, sr-iov, opendaylight, OVN, ecc.
A seconda dell'implementazione di questo driver, verranno utilizzati agenti gestiti da Neutron o verranno utilizzate connessioni con un controller SDN esterno, che si occupa di tutte le questioni relative all'organizzazione delle reti L2, al routing, ecc.
Ad esempio, se utilizziamo ML2 insieme a OVS, viene installato un agente L2 su ogni nodo di calcolo, che gestisce OVS. Tuttavia, se utilizziamo ad esempio OVN o OpenDayLight, la gestione di OVS passa sotto la loro giurisdizione: Neutron tramite il plugin radice invia comandi al controller, e lui esegue ciò che gli è stato detto.
Rinfreschiamo la memoria su Open vSwitch
Attualmente, uno dei componenti chiave di OpenStack è Open vSwitch.
Quando si installa OpenStack senza alcun SDN vendor aggiuntivo come Juniper Contrail o Nokia Nuage, OVS è il componente di rete principale della rete cloud e, insieme a iptables, conntrack, namespaces, consente di organizzare reti overlay complete con multitenancy. Ovviamente, questo componente può essere sostituito, ad esempio, nell'uso di soluzioni SDN proprietarie di terze parti.
OVS è uno switch software open-source progettato per essere utilizzato in ambienti virtualizzati come un forwarder virtuale di traffico.
Attualmente, OVS ha un funzionalità abbastanza significativa, che include tecnologie come QoS, LACP, VLAN, VxLAN, GENEVE, OpenFlow, DPDK, ecc.
Nota: inizialmente, OVS non era previsto come switch software per funzioni telecom ad alta richiesta e era più pensato per funzioni IT meno esigenti in termini di larghezza di banda come server WEB o server di posta. Tuttavia, OVS è stato migliorato e le attuali implementazioni di OVS hanno notevolmente migliorato le sue prestazioni e capacità, consentendo di utilizzarlo per operatori di telecomunicazioni con funzioni ad alta domanda, ad esempio c'è un'implementazione di OVS con supporto per l'accelerazione DPDK.
Ci sono tre componenti importanti di OVS che è necessario conoscere:
- Modulo del kernel — componente situata nello spazio del kernel, che esegue l'elaborazione del traffico basata sulle regole ricevute dall'elemento di controllo;
- vSwitch Il daemon (ovs-vswitchd) è un processo eseguito nello user space responsabile della programmazione del modulo kernel, ovvero rappresenta direttamente la logica di funzionamento dello switch.
- Server del database è un database locale situato su ogni host dove è in esecuzione OVS, che memorizza la configurazione. Attraverso questo modulo, i controller SDN possono comunicare tramite il protocollo OVSDB.
A tutto questo si aggiunge un insieme di utilità diagnostiche e di gestione, come ovs-vsctl, ovs-appctl, ovs-ofctl, ecc.
Attualmente, Openstack è ampiamente utilizzato dagli operatori telecom per migrazioni delle funzioni di rete, come EPC, SBC, HLR, ecc. Alcune funzioni possono operare senza problemi con OVS nella sua forma attuale, ma ad esempio EPC gestisce il traffico degli utenti, quindi deve gestire enormi volumi di traffico (attualmente, i volumi di traffico raggiungono diverse centinaia di gigabit al secondo). Naturalmente, instradare tale traffico attraverso lo space del kernel (poiché per impostazione predefinita il forwarder si trova proprio lì) non è la soluzione migliore. Pertanto, spesso si implementa OVS interamente nello user space utilizzando la tecnologia di accelerazione DPDK per inoltrare il traffico dalla NIC allo user space evitando il kernel.
Nota: per il cloud implementato per le funzioni telecom, è possibile configurare l'uscita del traffico dalla nodo di calcolo direttamente sull'hardware di commutazione bypassando OVS. A questo scopo vengono utilizzati meccanismi SR-IOV e Passthrough.
Come funziona in un prototipo reale?
Ora passiamo alla parte pratica e vediamo come funziona tutto in pratica.
Per iniziare, avvieremo una semplice installazione di Openstack. Poiché non ho a disposizione un insieme di server per esperimenti, costruiremo un prototipo su un singolo server fisico utilizzando macchine virtuali. Certo, per scopi commerciali questa soluzione non è adatta, ma per osservare come funziona la rete in un'installazione di Openstack, un tale prototipo è più che sufficiente. Inoltre, un'installazione di questo tipo è persino più interessante per scopi didattici, poiché consente di monitorare il traffico, ecc.
Poiché abbiamo bisogno di vedere solo la parte di base, possiamo non utilizzare più reti e configurarne solo due, mentre la seconda rete in questo prototipo sarà utilizzata esclusivamente per accedere all'undercloud e al server DNS. Non toccheremo per ora le reti esterne: questo è un tema per un altro grande articolo.
Iniziamo in modo ordinato. Prima di tutto, un po' di teoria. Installeremo Openstack utilizzando TripleO (Openstack su Openstack). La sostanza di TripleO è che installiamo Openstack all-in-one (cioè su un'unica nodo), chiamato undercloud, e poi usiamo le capacità di Openstack già installato per installare Openstack destinato all'operatività, chiamato overcloud. Undercloud utilizzerà la funzionalità incorporata di gestione dei server fisici (bare metal) — progetto Ironic — per il provisioning dei hypervisor che svolgeranno i ruoli di nodi compute, control e storage. In altre parole, non utilizziamo strumenti di terze parti per il deployment di Openstack: schieriamo Openstack attraverso Openstack. Durante l'installazione tutto diventerà molto più chiaro, quindi non ci fermeremo qui e andiamo avanti.
Nota: In questo articolo, per semplicità, non ho usato l'isolamento di rete per le reti interne di Openstack e ho schierato tutto utilizzando solo una rete. Tuttavia, la presenza o l'assenza di isolamento delle reti non influisce sulla funzionalità di base della soluzione: tutto funzionerà esattamente come con l'isolamento, ma il traffico passerà in una sola rete. Per un'installazione commerciale, è naturalmente necessario utilizzare l'isolamento tramite VLAN e interfacce diverse. Ad esempio, il traffico di gestione dello storage Ceph e il traffico di dati effettivi (accesso delle macchine ai dischi, ecc.) quando isolato utilizzano sottoreti diverse (Storage management e Storage) e questo rende la soluzione più resiliente, separando tale traffico, ad esempio, su porte diverse, o utilizzando profili QoS differenti per traffico diverso, affinché il traffico dati non sopprima il traffico di segnalazione. Nel nostro caso, invece, passeranno tutte nella stessa rete e questo di fatto non ci limita affatto.
Nota: Poiché intendiamo avviare macchine virtuali in un ambiente virtuale basato su macchine virtuali, dobbiamo prima abilitare la virtualizzazione nested.
Per verificare se la virtualizzazione nested è abilitata, puoi farlo in questo modo:
[root@hp-gen9 bormoglotx]# cat /sys/module/kvm_intel/parameters/nested N [root@hp-gen9 bormoglotx]#Se vedi la lettera N, abilitiamo il supporto per la virtualizzazione nested seguendo qualsiasi guida che trovi in rete, ad esempio .
Dobbiamo costruire uno schema di questo tipo con macchine virtuali:

Nel mio caso, per la connettività delle macchine virtuali incluse nella futura installazione (ne ho ottenute 7, ma si può anche fare con 4 se non si hanno molte risorse), ho utilizzato OpenvSwitch. Ho creato un bridge ovs e ho collegato le macchine virtuali tramite port-groups. A tal fine, ho creato un file xml di questo tipo:
[root@hp-gen9 ~]# virsh net-dumpxml ovs-network-1
ovs-network-1
7a2e7de7-fc16-4e00-b1ed-4d190133af67Qui sono dichiarati tre gruppi di porte: due access e uno trunk (l'ultimo era necessario per il server DNS, ma si può anche fare a meno, oppure crearlo sulla macchina host — a seconda delle vostre preferenze). Successivamente, utilizzando questo modello, dichiariamo il nostro attraverso virsh net-define:
virsh net-define ovs-network-1.xml
virsh net-start ovs-network-1
virsh net-autostart ovs-network-1 Ora modifichiamo le configurazioni delle porte dell'ipervisor:
[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: in questo scenario l'indirizzo sulla porta ovs-br1 non sarà disponibile, poiché non ha un tag VLAN. Per risolvere questo problema, è necessario dare il comando sudo ovs-vsctl set port ovs-br1 tag=100. Tuttavia, dopo il riavvio, questo tag scomparirà (se qualcuno sa come mantenerlo, sarei molto grato). Ma non è così importante, poiché questo indirizzo ci servirà solo durante l'installazione e non sarà necessario quando OpenStack sarà completamente distribuito.
Dopo creiamo la macchina 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=ttyS0Durante l'installazione, impostate tutti i parametri necessari, come il nome della macchina, le password, gli utenti, i server NTP, ecc. È possibile configurare anche le porte fin da subito, ma per me è più facile accedere alla macchina tramite console dopo l'installazione e modificare i file necessari. Se avete già un'immagine pronta, potete usarla, oppure procedere come me: scaricare l'immagine minima di CentOS 7 e utilizzarla per l'installazione della VM.
Dopo un'installazione riuscita, dovreste avere una macchina virtuale sulla quale sarà possibile installare l'undercloud.
[root@hp-gen9 bormoglotx]# virsh list
Id Name State
----------------------------------------------------
6 dns-server running
62 undercloud runningIniziamo installando gli strumenti necessari durante il processo di installazione:
sudo yum update -y
sudo yum install -y net-tools
sudo yum install -y wget
sudo yum install -y ipmitool
Installazione di Undercloud
Creiamo l'utente stack, impostiamo la password, lo aggiungiamo ai sudoer e gli concediamo la possibilità di eseguire comandi root tramite sudo senza inserire la password:
useradd stack
passwd stack
echo "stack ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/stack
chmod 0440 /etc/sudoers.d/stackOra specifichiamo nel file hosts il nome completo dell'undercloud:
vi /etc/hosts
127.0.0.1 undercloud.openstack.rnd localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6Successivamente, aggiungiamo i repository e installiamo il software necessario:
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-ansibleNota: se non prevedete di installare ceph, non è necessario eseguire i comandi relativi a ceph. Ho utilizzato la release Queens, ma potete usare qualsiasi altra release di vostro gradimento.
Successivamente, copiamo il file di configurazione dell'undercloud nella home directory dell'utente stack:
cp /usr/share/instack-undercloud/undercloud.conf.sample ~/undercloud.confOra è necessario modificare questo file, adattandolo alla nostra installazione.
All'inizio del file è necessario aggiungere queste righe:
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 = 10Quindi, esaminiamo le impostazioni:
undercloud_hostname — nome completo del server undercloud, deve corrispondere alla registrazione sul server DNS
local_ip — indirizzo locale undercloud verso la rete di provisioning
network_gateway — questo stesso indirizzo locale, che fungerà da gateway per l'accesso al mondo esterno durante l'installazione delle nodi overcloud, coincide anche con l'ip locale
undercloud_public_host — indirizzo API esterno, assegnato a qualsiasi indirizzo disponibile dalla rete di provisioning
undercloud_admin_host indirizzo API interno, assegnato a qualsiasi indirizzo disponibile dalla rete di provisioning
undercloud_nameservers — server DNS
generate_service_certificate — questa riga è molto importante nell'esempio attuale, poiché se non viene impostata su false si riceverà un errore durante l'installazione, il problema è descritto nel bug tracker di Red Hat
local_interface interfaccia nella rete di provisioning. Questa interfaccia sarà riconfigurata durante il dispiegamento dell'undercloud, quindi l'undercloud deve avere due interfacce: una per l'accesso e l'altra per il provisioning
local_mtu — MTU. Poiché abbiamo un laboratorio di test e il MTU è 1500 sulle porte dello switch OVS, è necessario impostare il valore a 1450 affinché i pacchetti incapsulati in VxLAN possano passare
network_cidr — rete di provisioning
masquerade — utilizzo di NAT per accedere alla rete esterna
masquerade_network — rete che sarà sottoposta a NAT
dhcp_start — indirizzo iniziale del pool di indirizzi, da cui saranno assegnati gli indirizzi ai nodi durante il deployment dell'overcloud
dhcp_end — indirizzo finale del pool di indirizzi, da cui saranno assegnati gli indirizzi ai nodi durante il deployment dell'overcloud
inspection_iprange — pool di indirizzi necessari per eseguire l'ispezione (non deve sovrapporsi al pool sopra indicato)
scheduler_max_attempts — numero massimo di tentativi per installare l'overcloud (deve essere maggiore o uguale al numero di nodi)
Dopo che il file è stato descritto, è possibile dare il comando per il deployment dell'undercloud:
openstack undercloud install
La procedura richiede da 10 a 30 minuti a seconda dell'hardware. Alla fine dovreste vedere un output simile a questo:
vi undercloud.conf
2020-08-13 23:13:12,668 INFO:
#############################################################################
Installazione dell'Undercloud completata.
Il file contenente le password di questa installazione si trova in
/home/stack/undercloud-passwords.conf.
C'è anche un file stackrc in /home/stack/stackrc.
Questi file sono necessari per interagire con i servizi OpenStack e devono essere
protetti.
#############################################################################Questo output indica che avete installato correttamente l'undercloud e ora potete controllarne lo stato e procedere all'installazione dell'overcloud.
Se guardate l'output di ifconfig, vedrete che è apparsa una nuova interfaccia bridge
[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 0Ora questo interfaccia verrà utilizzata per il deployment dell'overcloud.
Dall'output qui sotto si può vedere che tutti i servizi sono sulla stessa nodo:
(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 |
+--------------------------+-----------+----------+Di seguito è mostrata la configurazione della parte di rete dell'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 ~]$Installazione dell'overcloud
Al momento abbiamo solo l'undercloud e ci mancano le nodi da cui costituire l'overcloud. Pertanto, come primo passo, procederemo a creare le macchine virtuali necessarie. Durante il deployment, l'undercloud installerà il sistema operativo e il software richiesti sulle macchine dell'overcloud — quindi non dobbiamo configurare completamente la macchina, ma solo creare un disco (o dischi) per essa e definire le sue caratteristiche — di fatto otteniamo un server nudo senza un sistema operativo installato.
Ci spostiamo nella cartella con i dischi delle nostre macchine virtuali e creiamo i dischi delle dimensioni necessarie:
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 160GPoiché stiamo operando come root, dobbiamo cambiare il proprietario di questi dischi per evitare problemi di permessi:
[root@hp-gen9 images]# ls -lh
total 5.8G
drwxr-xr-x. 2 qemu qemu 4.0K 13 Aug 16:15 backups
-rw-r--r--. 1 root root 61G 14 Aug 03:07 compute-1.qcow2
-rw-r--r--. 1 root root 61G 14 Aug 03:07 compute-2.qcow2
-rw-r--r--. 1 root root 61G 14 Aug 03:07 control-1.qcow2
-rw-------. 1 qemu qemu 41G 14 Aug 03:03 dns-server.qcow2
-rw-r--r--. 1 root root 161G 14 Aug 03:07 storage-1.qcow2
-rw-r--r--. 1 root root 161G 14 Aug 03:07 storage-2.qcow2
-rw-------. 1 qemu qemu 41G 14 Aug 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 13 Aug 16:15 backups
-rw-r--r--. 1 qemu qemu 61G 14 Aug 03:07 compute-1.qcow2
-rw-r--r--. 1 qemu qemu 61G 14 Aug 03:07 compute-2.qcow2
-rw-r--r--. 1 qemu qemu 61G 14 Aug 03:07 control-1.qcow2
-rw-------. 1 qemu qemu 41G 14 Aug 03:03 dns-server.qcow2
-rw-r--r--. 1 qemu qemu 161G 14 Aug 03:07 storage-1.qcow2
-rw-r--r--. 1 qemu qemu 161G 14 Aug 03:07 storage-2.qcow2
-rw-------. 1 qemu qemu 41G 14 Aug 03:08 undercloud.qcow2
[root@hp-gen9 images]# Nota: se non prevedi di installare ceph per motivi di apprendimento, allora non creare comandi con almeno 3 nodi con almeno due dischi e nel template indica che verranno utilizzati dischi virtuali vda, vdb e così via.
Ottimo, ora dobbiamo definire tutte queste macchine:
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 Alla fine ci sono comandi —print-xml > /tmp/storage-1.xml, che crea un file xml con la descrizione di ogni macchina nella cartella /tmp/, se non lo aggiungi, non potrai definire le macchine virtuali.
Ora dobbiamo definire tutte queste macchine in 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 Nome Stato
----------------------------------------------------
6 dns-server in esecuzione
64 undercloud in esecuzione
- compute-1 spento
- compute-2 spento
- control-1 spento
- storage-1 spento
- storage-2 spento
[root@hp-gen9 ~]#Ora un piccolo dettaglio — tripleO utilizza IPMI per gestire i server durante l'installazione e l'introspezione.
L'introspezione è il processo di ispezione dell'hardware al fine di ottenere i parametri necessari per il provisioning successivo dei nodi. L'introspezione viene eseguita tramite ironic — un servizio progettato per lavorare con server bare metal.
Ma qui sorge un problema — se per i server fisici l'IPMI è una porta separata (o una porta condivisa, ma non è fondamentale), per le macchine virtuali non esistono tali porte. A questo punto, ci viene in aiuto un workaround chiamato vbmc — un'utilità che consente di emulare una porta IPMI. Questo dettaglio è particolarmente importante per chi vorrà sollevare un laboratorio su un hypervisor ESXI — sinceramente, non so se in esso esista un analogo di vbmc, quindi vale la pena porsi questa domanda prima di avviare tutto.
Installiamo vbmc:
yum install python2-virtualbmcSe il tuo sistema operativo non riesce a trovare il pacchetto, aggiungi il repository:
yum install -y https://www.rdoproject.org/repos/rdo-release.rpmOra configuriamo l'utilità. Qui tutto è incredibilmente semplice. Ora è logico che nell'elenco vbmc non ci siano server.
[root@hp-gen9 ~]# vbmc list
[root@hp-gen9 ~]# Per farli apparire è necessario dichiararli manualmente in questo modo:
[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 dominio | Stato | Indirizzo | Porta |
+-------------+--------+---------+------+
| compute-1 | giù | :: | 7004 |
| compute-2 | giù | :: | 7005 |
| control-1 | giù | :: | 7001 |
| storage-1 | giù | :: | 7002 |
| storage-2 | giù | :: | 7003 |
+-------------+--------+---------+------+
[root@hp-gen9 ~]#Penso che la sintassi del comando sia chiara senza bisogno di spiegazioni. Tuttavia, al momento tutte le nostre sessioni sono in stato DOWN. Per farle passare allo stato UP, è necessario accenderle:
[root@hp-gen9 ~]# vbmc start control-1
2020-08-14 03:15:57,826.826 13149 INFO VirtualBMC [-] Avviata l'istanza vBMC per il dominio control-1
[root@hp-gen9 ~]# vbmc start storage-1
2020-08-14 03:15:58,316.316 13149 INFO VirtualBMC [-] Avviata l'istanza vBMC per il dominio storage-1
[root@hp-gen9 ~]# vbmc start storage-2
2020-08-14 03:15:58,851.851 13149 INFO VirtualBMC [-] Avviata l'istanza vBMC per il dominio storage-2
[root@hp-gen9 ~]# vbmc start compute-1
2020-08-14 03:15:59,307.307 13149 INFO VirtualBMC [-] Avviata l'istanza vBMC per il dominio compute-1
[root@hp-gen9 ~]# vbmc start compute-2
2020-08-14 03:15:59,712.712 13149 INFO VirtualBMC [-] Avviata l'istanza vBMC per il dominio compute-2
[root@hp-gen9 ~]#
[root@hp-gen9 ~]#
[root@hp-gen9 ~]# vbmc list
+-------------+---------+---------+------+
| Nome dominio | Stato | Indirizzo | Porta |
+-------------+---------+---------+------+
| compute-1 | in esecuzione | :: | 7004 |
| compute-2 | in esecuzione | :: | 7005 |
| control-1 | in esecuzione | :: | 7001 |
| storage-1 | in esecuzione | :: | 7002 |
| storage-2 | in esecuzione | :: | 7003 |
+-------------+---------+---------+------+
[root@hp-gen9 ~]#E l'ultimo tocco è necessario correggere le regole del firewall (o disattivarlo 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
Ora entriamo in undercloud e controlliamo se tutto funziona. L'indirizzo della macchina host è 192.168.255.200, su undercloud abbiamo aggiunto il pacchetto necessario ipmitool durante la preparazione per il deploy:
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power status
L'alimentazione del chassis è spenta
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power on
Controllo dell'alimentazione del chassis: Acceso
[stack@undercloud ~]$
[root@hp-gen9 ~]# virsh list
Id Nome Stato
----------------------------------------------------
6 dns-server in esecuzione
64 undercloud in esecuzione
65 control-1 in esecuzioneCome potete vedere, abbiamo avviato con successo il nodo di controllo tramite vbmc. Ora lo spegneremo e procederemo:
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power off
Controllo dell'alimentazione del chassis: Spento
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power status
L'alimentazione del chassis è spenta
[stack@undercloud ~]$
[root@hp-gen9 ~]# virsh list --all
Id Nome Stato
----------------------------------------------------
6 dns-server in esecuzione
64 undercloud in esecuzione
- compute-1 spento
- compute-2 spento
- control-1 spento
- storage-1 spento
- storage-2 spento
[root@hp-gen9 ~]#Il passo successivo è l'ispezione dei nodi su cui verrà installato l'overcloud. Per fare questo, dobbiamo preparare un file json con la descrizione dei nostri nodi. Notate che, a differenza dell'installazione su server nudi, nel file è specificata la porta su cui è in esecuzione vbmc per ciascuna delle macchine.
[root@hp-gen9 ~]# virsh domiflist --domain control-1
Interfaccia Tipo Sorgente Modello MAC
-------------------------------------------------------
- rete ovs-network-1 virtio 52:54:00:20:a2:2f
- rete ovs-network-1 virtio 52:54:00:3f:87:9f
[root@hp-gen9 ~]# virsh domiflist --domain compute-1
Interfaccia Tipo Sorgente Modello MAC
-------------------------------------------------------
- rete ovs-network-1 virtio 52:54:00:98:e9:d6
[root@hp-gen9 ~]# virsh domiflist --domain compute-2
Interfaccia Tipo Sorgente Modello MAC
-------------------------------------------------------
- rete ovs-network-1 virtio 52:54:00:6a:ea:be
[root@hp-gen9 ~]# virsh domiflist --domain storage-1
Interfaccia Tipo Sorgente Modello MAC
-------------------------------------------------------
- rete ovs-network-1 virtio 52:54:00:79:0b:cb
[root@hp-gen9 ~]# virsh domiflist --domain storage-2
Interfaccia Tipo Sorgente Modello MAC
-------------------------------------------------------
- rete ovs-network-1 virtio 52:54:00:a7:fe:27Nota: sul nodo di controllo ci sono due interfacce, ma in questo caso non è importante, in questa installazione ci basterà anche una sola.
Ora prepariamo il file json. Dobbiamo specificare l'indirizzo MAC della porta, tramite la quale avverrà il provisioning, i parametri dei nodi, dare loro dei nomi e indicare come accedere a 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"
}
]
}Ora dobbiamo preparare le immagini per ironic. Per fare ciò, le scarichiamo tramite wget e le installiamo:
(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 ~]$Stiamo caricando le immagini in undercloud:
(undercloud) [stack@undercloud ~]$ openstack overcloud image upload --image-path ~/images/
L'immagine "overcloud-full-vmlinuz" è stata caricata.
+--------------------------------------+------------------------+-------------+---------+--------+
| ID | Nome | Formato Disco | Dimensione | Stato |
+--------------------------------------+------------------------+-------------+---------+--------+
| c2553770-3e0f-4750-b46b-138855b5c385 | overcloud-full-vmlinuz | aki | 6761064 | attivo |
+--------------------------------------+------------------------+-------------+---------+--------+
L'immagine "overcloud-full-initrd" è stata caricata.
+--------------------------------------+-----------------------+-------------+----------+--------+
| ID | Nome | Formato Disco | Dimensione | Stato |
+--------------------------------------+-----------------------+-------------+----------+--------+
| 949984e0-4932-4e71-af43-d67a38c3dc89 | overcloud-full-initrd | ari | 55183045 | attivo |
+--------------------------------------+-----------------------+-------------+----------+--------+
L'immagine "overcloud-full" è stata caricata.
+--------------------------------------+----------------+-------------+------------+--------+
| ID | Nome | Formato Disco | Dimensione | Stato |
+--------------------------------------+----------------+-------------+------------+--------+
| a2f2096d-c9d7-429a-b866-c7543c02a380 | overcloud-full | qcow2 | 1487475712 | attivo |
+--------------------------------------+----------------+-------------+------------+--------+
L'immagine "bm-deploy-kernel" è stata caricata.
+--------------------------------------+------------------+-------------+---------+--------+
| ID | Nome | Formato Disco | Dimensione | Stato |
+--------------------------------------+------------------+-------------+---------+--------+
| e413aa78-e38f-404c-bbaf-93e582a8e67f | bm-deploy-kernel | aki | 6761064 | attivo |
+--------------------------------------+------------------+-------------+---------+--------+
L'immagine "bm-deploy-ramdisk" è stata caricata.
+--------------------------------------+-------------------+-------------+-----------+--------+
| ID | Nome | Formato Disco | Dimensione | Stato |
+--------------------------------------+-------------------+-------------+-----------+--------+
| 5cf3aba4-0e50-45d3-929f-27f025dd6ce3 | bm-deploy-ramdisk | ari | 461759376 | attivo |
+--------------------------------------+-------------------+-------------+-----------+--------+
(undercloud) [stack@undercloud ~]$Controlliamo che tutte le immagini siano state caricate
(undercloud) [stack@undercloud ~]$ openstack image list
+--------------------------------------+------------------------+--------+
| ID | Nome | Stato |
+--------------------------------------+------------------------+--------+
| e413aa78-e38f-404c-bbaf-93e582a8e67f | bm-deploy-kernel | attivo |
| 5cf3aba4-0e50-45d3-929f-27f025dd6ce3 | bm-deploy-ramdisk | attivo |
| a2f2096d-c9d7-429a-b866-c7543c02a380 | overcloud-full | attivo |
| 949984e0-4932-4e71-af43-d67a38c3dc89 | overcloud-full-initrd | attivo |
| c2553770-3e0f-4750-b46b-138855b5c385 | overcloud-full-vmlinuz | attivo |
+--------------------------------------+------------------------+--------+
(undercloud) [stack@undercloud ~]$Un'altra cosa — dobbiamo aggiungere il server DNS:
(undercloud) [stack@undercloud ~]$ openstack subnet list
+--------------------------------------+-----------------+--------------------------------------+------------------+
| ID | Nome | Rete | Sottorete |
+--------------------------------------+-----------------+--------------------------------------+------------------+
| 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 | Valore |
+-------------------+-----------------------------------------------------------+
| allocation_pools | 192.168.255.11-192.168.255.50 |
| cidr | 192.168.255.0/24 |
| created_at | 2020-08-13T20:10:37Z |
| description | |
| dns_nameservers | |
| enable_dhcp | True |
| 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 | None |
| ipv6_ra_mode | None |
| name | ctlplane-subnet |
| network_id | 6ca013dc-41c2-42d8-9d69-542afad53392 |
| prefix_length | None |
| project_id | a844ccfcdb2745b198dde3e1b28c40a3 |
| revision_number | 0 |
| segment_id | None |
| service_types | |
| subnetpool_id | None |
| 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 è deprecato e sarà rimosso in futuro. Usa invece l’openstack CLI.
Sottorete aggiornata: f45dea46-4066-42aa-a3c4-6f84b8120cab
(undercloud) [stack@undercloud ~]$Ora possiamo dare il comando per l'introspezione:
(undercloud) [stack@undercloud ~]$ openstack overcloud node import --introspect --provide inspection.json
Avviato il workflow Mistral tripleo.baremetal.v1.register_or_update. ID Esecuzione: d57456a3-d8ed-479c-9a90-dff7c752d0ec
Attesa di messaggi sulla coda 'tripleo' senza timeout.
5 nodo(i) spostati con successo nello stato "gestibile".
Nodulo registrato con successo UUID b4b2cf4a-b7ca-4095-af13-cc83be21c4f5
Nodulo registrato con successo UUID b89a72a3-6bb7-429a-93bc-48393d225838
Nodulo registrato con successo UUID 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e
Nodulo registrato con successo UUID bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8
Nodulo registrato con successo UUID 766ab623-464c-423d-a529-d9afb69d1167
Attesa che l'introspezione finisca...
Avviato il workflow Mistral tripleo.baremetal.v1.introspect. ID Esecuzione: 6b4d08ae-94c3-4a10-ab63-7634ec198a79
Attesa di messaggi sulla coda 'tripleo' senza timeout.
L'introspezione del nodo b89a72a3-6bb7-429a-93bc-48393d225838 è completata. Stato:SUCCESS. Errori:Nessuno
L'introspezione del nodo 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e è completata. Stato:SUCCESS. Errori:Nessuno
L'introspezione del nodo bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 è completata. Stato:SUCCESS. Errori:Nessuno
L'introspezione del nodo 766ab623-464c-423d-a529-d9afb69d1167 è completata. Stato:SUCCESS. Errori:Nessuno
L'introspezione del nodo b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 è completata. Stato:SUCCESS. Errori:Nessuno
5 nodo(i) introspezionati con successo.
Avviato il workflow Mistral tripleo.baremetal.v1.provide. ID Esecuzione: f5594736-edcf-4927-a8a0-2a7bf806a59a
Attesa di messaggi sulla coda 'tripleo' senza timeout.
5 nodo(i) spostati con successo nello stato "disponibile".
(undercloud) [stack@undercloud ~]$Come si può vedere dall'output, tutto è terminato senza errori. Verifichiamo che tutti i nodi siano nello stato disponibile:
(undercloud) [stack@undercloud ~]$ openstack baremetal node list
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
| UUID | Nome | Instance UUID | Stato Alimentazione | Stato Provisionamento | Manutenzione |
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | control-1 | None | spento | disponibile | Falso |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | None | spento | disponibile | Falso |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | None | spento | disponibile | Falso |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | None | spento | disponibile | Falso |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | None | spento | disponibile | Falso |
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
(undercloud) [stack@undercloud ~]$ Se i nodi saranno in un altro stato, di solito gestibile, vuol dire che qualcosa è andato storto e bisogna controllare i log per capire perché. Ricordate che in questo scenario utilizziamo la virtualizzazione e potrebbero esserci bug legati all'uso di macchine virtuali o vbmc.
Successivamente, dobbiamo indicare quale nodo avrà quale funzione — ovvero, specificare il profilo con cui il nodo sarà distribuito:
(undercloud) [stack@undercloud ~]$ openstack overcloud profiles list
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| Node UUID | Node Name | Provision State | Current Profile | Possible Profiles |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | control-1 | disponibile | Nessuno | |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | disponibile | Nessuno | |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | disponibile | Nessuno | |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | disponibile | Nessuno | |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | disponibile | Nessuno | |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
(undercloud) [stack@undercloud ~]$ openstack flavor list
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
| ID | Name | RAM | Disk | Ephemeral | VCPUs | Is Public |
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
| 168af640-7f40-42c7-91b2-989abc5c5d8f | swift-storage | 4096 | 40 | 0 | 1 | True |
| 52148d1b-492e-48b4-b5fc-772849dd1b78 | baremetal | 4096 | 40 | 0 | 1 | True |
| 56e66542-ae60-416d-863e-0cb192d01b09 | control | 4096 | 40 | 0 | 1 | True |
| af6796e1-d0c4-4bfe-898c-532be194f7ac | block-storage | 4096 | 40 | 0 | 1 | True |
| e4d50fdd-0034-446b-b72c-9da19b16c2df | compute | 4096 | 40 | 0 | 1 | True |
| fc2e3acf-7fca-4901-9eee-4a4d6ef0265d | ceph-storage | 4096 | 40 | 0 | 1 | True |
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
(undercloud) [stack@undercloud ~]$Specifichiamo il profilo per ogni nodo:
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-d9afb69d1167Verifichiamo che abbiamo fatto tutto correttamente:
(undercloud) [stack@undercloud ~]$ openstack overcloud profiles list
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| Node UUID | Node Name | Provision State | Current Profile | Possible Profiles |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | controllo-1 | disponibile | controllo | |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | disponibile | ceph-storage | |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | disponibile | ceph-storage | |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | disponibile | compute | |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | disponibile | compute | |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
(undercloud) [stack@undercloud ~]$Se tutto è corretto, diamo il comando per il deployment dell'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 qemuNell'installazione reale verranno ovviamente utilizzati template personalizzati, nel nostro caso questo complicherà notevolmente il processo, poiché sarà necessario spiegare ogni modifica nel template. Come detto in precedenza, anche un'installazione semplice sarà sufficiente per vedere come funziona.
Nota: la variabile --libvirt-type qemu è necessaria in questo caso, poiché utilizzeremo la virtualizzazione nested. Altrimenti le macchine virtuali non verranno avviate.
Ora avete circa un'ora, o forse di più (dipende dalle capacità dell'hardware) e non vi resta che sperare di vedere questo messaggio alla scadenza del tempo:
2020-08-14 08:39:21Z [overcloud]: CREATE_COMPLETE Stack CREATE completato con successo
Stack overcloud CREATE_COMPLETE
Host 192.168.255.21 non trovato in /home/stack/.ssh/known_hosts
È stato avviato il workflow di Mistral tripleo.deployment.v1.get_horizon_url. ID esecuzione: fcb996cd-6a19-482b-b755-2ca0c08069a9
Endpoint Overcloud: http://192.168.255.21:5000/
URL del Dashboard Horizon Overcloud: http://192.168.255.21:80/dashboard
File rc Overcloud: /home/stack/overcloudrc
Overcloud Deployed
(undercloud) [stack@undercloud ~]$Ora avete una versione quasi completa di OpenStack, sulla quale potete imparare, fare esperimenti, ecc.
Verifichiamo che tutto funzioni correttamente. Nella directory home dell'utente stack ci sono due file: uno stackrc (per gestire l'undercloud) e il secondo overcloudrc (per gestire l'overcloud). Questi file devono essere specificati come source, poiché contengono le informazioni necessarie per l'autenticazione.
(undercloud) [stack@undercloud ~]$ openstack server list
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
| ID | Nome | Stato | Reti | Immagine | Tipo |
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
| fd7d36f4-ce87-4b9a-93b0-add2957792de | overcloud-controller-0 | ATTIVO | ctlplane=192.168.255.15 | overcloud-full | controllo |
| edc77778-8972-475e-a541-ff40eb944197 | overcloud-novacompute-1 | ATTIVO | ctlplane=192.168.255.26 | overcloud-full | computo |
| 5448ce01-f05f-47ca-950a-ced14892c0d4 | overcloud-cephstorage-1 | ATTIVO | ctlplane=192.168.255.34 | overcloud-full | ceph-storage |
| ce6d862f-4bdf-4ba3-b711-7217915364d7 | overcloud-novacompute-0 | ATTIVO | ctlplane=192.168.255.19 | overcloud-full | computo |
| e4507bd5-6f96-4b12-9cc0-6924709da59e | overcloud-cephstorage-0 | ATTIVO | 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 | servizio |
+----------------------------------+---------+
(overcloud) [stack@undercloud ~]$
(overcloud) [stack@undercloud ~]$
(overcloud) [stack@undercloud ~]$ openstack network agent list
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| ID | Tipo di agente | Host | Zona di disponibilità| Vivo | Stato | Binario |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| 10495de9-ba4b-41fe-b30a-b90ec3f8728b | Open vSwitch agent | overcloud-novacompute-1.localdomain | Nessuno | :-) | ATTIVO| neutron-openvswitch-agent |
| 1515ad4a-5972-46c3-af5f-e5446dff7ac7 | L3 agent | overcloud-controller-0.localdomain | nova | :-) | ATTIVO| neutron-l3-agent |
| 322e62ca-1e5a-479e-9a96-4f26d09abdd7 | DHCP agent | overcloud-controller-0.localdomain | nova | :-) | ATTIVO| neutron-dhcp-agent |
| 9c1de2f9-bac5-400e-998d-4360f04fc533 | Open vSwitch agent | overcloud-novacompute-0.localdomain | Nessuno | :-) | ATTIVO| neutron-openvswitch-agent |
| d99c5657-851e-4d3c-bef6-f1e3bb1acfb0 | Open vSwitch agent | overcloud-controller-0.localdomain | Nessuno | :-) | ATTIVO| neutron-openvswitch-agent |
| ff85fae6-5543-45fb-a301-19c57b62d836 | Metadata agent | overcloud-controller-0.localdomain | Nessuno | :-) | ATTIVO| neutron-metadata-agent |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
(overcloud) [stack@undercloud ~]$Nella mia installazione è necessario un ultimo ritocco: aggiungere una rotta sul controller, poiché la macchina da cui sto lavorando si trova in un'altra rete. Per fare ciò, accediamo a control-1 con l'account heat-admin e configuriamo la rotta.
(undercloud) [stack@undercloud ~]$ ssh heat-admin@192.168.255.15
Ultimo accesso: ven 14 ago 2020 09:47:40 da 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.254E ora potete accedere a Horizon. Tutte le informazioni - indirizzi, login e password - sono contenute nel file /home/stack/overcloudrc. Lo schema finale appare come segue:

A proposito, nella nostra installazione gli indirizzi delle macchine sono stati assegnati tramite DHCP e, come potete vedere, vengono distribuiti "a caso". Potete specificare in modo rigoroso nel template quale indirizzo deve essere associato a quale macchina durante il deployment, se necessario.
Come circola il traffico tra le macchine virtuali?
In questo articolo esamineremo tre opzioni per il passaggio del traffico.
- Due macchine su un hypervisor nella stessa rete L2.
- Due macchine su hypervisor diversi nella stessa rete L2.
- Due macchine in reti diverse (routing tra le reti).
I casi con uscita verso il mondo esterno tramite la rete esterna, utilizzando indirizzi flottanti, così come il routing distribuito, verranno trattati la prossima volta; per ora ci fermeremo sul traffico interno.
Per la verifica, raccoglieremo questo schema:

Abbiamo creato 4 macchine virtuali: 3 nella stessa rete L2 - net-1, e un'altra nella rete net-2.
(overcloud) [stack@undercloud ~]$ nova list --tenant 5e18ce8ec9594e00b155485f19895e6c
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
| ID | Nome | ID Inquilino | Stato | Stato Compito | Stato Alimentazione | Reti |
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
| f53b37b5-2204-46cc-aef0-dba84bf970c0 | vm-1 | 5e18ce8ec9594e00b155485f19895e6c | ATTIVO | - | In Esecuzione | net-1=10.0.1.85 |
| fc8b6722-0231-49b0-b2fa-041115bef34a | vm-2 | 5e18ce8ec9594e00b155485f19895e6c | ATTIVO | - | In Esecuzione | net-1=10.0.1.88 |
| 3cd74455-b9b7-467a-abe3-bd6ff765c83c | vm-3 | 5e18ce8ec9594e00b155485f19895e6c | ATTIVO | - | In Esecuzione | net-1=10.0.1.90 |
| 7e836338-6772-46b0-9950-f7f06dbe91a8 | vm-4 | 5e18ce8ec9594e00b155485f19895e6c | ATTIVO | - | In Esecuzione | net-2=10.0.2.8 |
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
(overcloud) [stack@undercloud ~]$ Controlliamo su quali hypervisor sono collocate le macchine create:
(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 ~]$
Le macchine vm-1 e vm-3 sono collocate su compute-0, mentre le macchine vm-2 e vm-4 sono collocate su compute-1.
Inoltre, è stato creato un router virtuale per consentire il routing tra le reti specificate:
(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 ~]$ Il router ha due porte virtuali che fungono da gateway per le reti:
(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 ~]$ Ma prima di vedere come fluisce il traffico, diamo un'occhiata a cosa abbiamo attualmente sul nodo di controllo (che è anche il nodo di rete) e sul nodo compute. Iniziamo dal nodo compute.
[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: (interno)
phy-br-ex 1/none: (patch: peer=int-br-ex)
br-int:
br-int 65534/2: (interno)
int-br-ex 1/none: (patch: peer=phy-br-ex)
patch-tun 2/none: (patch: peer=patch-int)
br-tun:
br-tun 65534/3: (interno)
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 ~]$Attualmente ci sono tre bridge ovs nella nod: br-int, br-tun, br-ex. Tra di loro, come possiamo vedere, ci sono un insieme di interfacce. Per semplicità, rappresentiamo tutte queste interfacce in uno schema e vediamo cosa ne risulta.

Dagli indirizzi su cui sono attivati i tunnel VxLAN, si vede che un tunnel è attivato su compute-1 (192.168.255.26), mentre il secondo tunnel punta a control-1 (192.168.255.15). Ma la cosa più interessante è che br-ex non ha interfacce fisiche, e se guardiamo quali flussi sono configurati, possiamo vedere che questo bridge al momento può solo scartare il traffico.
[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 ~]$ Come si può vedere dall'output, l'indirizzo è collegato direttamente alla porta fisica, e non a un'interfaccia di bridge virtuale.
[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 ~]$ Secondo la prima regola, tutto ciò che arriva dalla porta phy-br-ex deve essere scartato.
In effetti, non ci sono altre fonti di traffico per questo bridge, se non da questo interfaccia (collegamento con br-int), e considerando i drop, è chiaro che al bridge era già giunto traffico BUM.
Cioè, da questo nodo il traffico può uscire solo attraverso un tunnel VxLAN e non in altro modo. Tuttavia, se si attiva il DVR, la situazione cambierà, ma ne discuteremo un'altra volta. Utilizzando l'isolamento delle reti, ad esempio tramite VLAN, avrete più interfacce L3 nella VLAN 0, non una sola. Tuttavia, il traffico VxLAN uscirà dal nodo allo stesso modo, ma incapsulato in una VLAN specifica.
Abbiamo chiarito la nodo compute, passiamo ora alla nodo control.
[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/none: (patch: peer=int-br-ex)
br-int:
br-int 65534/3: (interno)
int-br-ex 1/none: (patch: peer=phy-br-ex)
patch-tun 2/none: (patch: peer=patch-int)
br-tun:
br-tun 65534/4: (interno)
patch-int 1/none: (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 ~]$Di fatto, si può dire che è tutto uguale, tuttavia l'indirizzo IP non si trova più su un'interfaccia fisica, ma su un bridge virtuale. Questo è stato fatto perché questa porta è quella attraverso la quale il traffico verrà instradato nel mondo esterno.
[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 ~]$ Questa porta è collegata al bridge br-ex e poiché non ci sono tag VLAN su di essa, essa è una porta trunk sulla quale sono consentite tutte le VLAN. Attualmente il traffico esce verso l'esterno senza tag, come indicato dal vlan-id 0 nell'output sopra.

Tutto il resto al momento è simile alla nodo compute: gli stessi bridge, gli stessi tunnel che portano a due nodi compute.
Non ci occuperemo delle nodi di archiviazione in questo articolo, ma per comprendere è essenziale dire che la parte di rete di questi nodi è terribilmente banale. Nel nostro caso c'è solo una porta fisica (eth0) a cui è assegnato un indirizzo IP e basta. Non ci sono tunnel VxLAN, bridge di tunnel e così via — non c'è affatto ovs, perché non ha senso. Quando si utilizza l'isolamento delle reti — su questo nodo ci saranno due interfacce (porte fisiche, bond o semplicemente due VLAN — non importa — dipende da ciò che si desidera) — una per la gestione, l'altra per il traffico (scrittura su disco VM, lettura da disco, ecc.).
Abbiamo compreso quali nodi abbiamo in assenza di servizi. Ora avvieremo 4 macchine virtuali e vedremo come cambierà lo schema descritto sopra — dovremmo avere porte, router virtuali, ecc.
Per ora la nostra rete appare così:

Abbiamo due macchine virtuali su ogni nodo computer. Prendiamo ad esempio compute-0 per vedere come tutto è connesso.
[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh list
Id Name State
----------------------------------------------------
1 instance-00000001 running
3 instance-00000003 running
[heat-admin@overcloud-novacompute-0 ~]$ La macchina ha solo un'interfaccia virtuale — tap95d96a75-a0:
[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 ~]$
Questa interfaccia guarda nel bridge linux:
[heat-admin@overcloud-novacompute-0 ~]$ sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242904c92a8 no
qbr5bd37136-47 8000.5e4e05841423 no qvb5bd37136-47
tap5bd37136-47
qbr95d96a75-a0 8000.de076cb850f6 no qvb95d96a75-a0
tap95d96a75-a0
[heat-admin@overcloud-novacompute-0 ~]$ Come si vede dall'output, nel bridge ci sono solo due interfacce — tap95d96a75-a0 e qvb95d96a75-a0.
Qui vale la pena fermarsi un attimo sui tipi di dispositivi di rete virtuale in OpenStack:
vtap — interfaccia virtuale collegata all'istanza (VM)
qbr — bridge Linux
qvb e qvo — coppia vEth, collegata al bridge Linux e al bridge Open vSwitch
br-int, br-tun, br-vlan — bridge Open vSwitch
patch-, int-br-, phy-br- — interfacce patch Open vSwitch che collegano i bridge
qg, qr, ha, fg, sg — porte Open vSwitch utilizzate dai dispositivi virtuali per connettersi a OVS
Come capirete, se nel bridge abbiamo una porta qvb95d96a75-a0, che è una coppia vEth, allora da qualche parte c'è il suo lato opposto, che logicamente dovrebbe chiamarsi qvo95d96a75-a0. Vediamo quali porte ci sono su 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: (interno)
phy-br-ex 1/none: (patch: peer=int-br-ex)
br-int:
br-int 65534/2: (interno)
int-br-ex 1/none: (patch: peer=phy-br-ex)
patch-tun 2/none: (patch: peer=patch-int)
qvo5bd37136-47 6/6: (sistema)
qvo95d96a75-a0 3/5: (sistema)
br-tun:
br-tun 65534/3: (interno)
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 ~]$ Come vediamo, la porta si trova in br-int. Br-int funge da commutatore, terminando le porte delle macchine virtuali. Oltre a qvo95d96a75-a0, nell'output è visibile anche la porta qvo5bd37136-47. Questa è la porta per la seconda macchina virtuale. Alla fine, il nostro schema ora appare così:

La domanda che dovrebbe subito interessare il lettore attento è: perché un bridge Linux tra la porta della macchina virtuale e la porta OVS? La questione è che per proteggere la macchina vengono utilizzati i gruppi di sicurezza, che non sono altro che iptables. OVS non lavora con iptables, quindi è stato ideato questo "workaround". Tuttavia, è giunto al termine della sua vita — è stato sostituito da conntrack nelle nuove versioni.
Quindi, in definitiva, lo schema appare così:

Due macchine su un hypervisor nella stessa rete L2.
Poiché entrambe queste VM si trovano nella stessa rete L2 e sullo stesso hypervisor, il traffico tra di loro passerà logicamente localmente attraverso br-int, dato che entrambe le macchine saranno nello stesso VLAN:
[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000001
Interfaccia Tipo Sorgente Modello 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
Interfaccia Tipo Sorgente Modello 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
porta VLAN MAC Età
6 1 fa:16:3e:83:ad:a4 0
3 1 fa:16:3e:44:98:20 0
[heat-admin@overcloud-novacompute-0 ~]$ Due macchine su hypervisor diversi nella stessa rete L2.
Ora vediamo come il traffico si muoverà tra due macchine nella stessa rete L2, ma situate su hypervisor diversi. A essere onesti, non cambierà molto, semplicemente il traffico tra gli hypervisor passerà attraverso un tunnel vxlan. Vediamo con un esempio.
Gli indirizzi delle macchine virtuali tra cui osserveremo il traffico:
[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-1 ~]$ sudo virsh domiflist instance-00000002
Interfaccia Tipo Origine Modello MAC
-------------------------------------------------------
tape7e23f1b-07 bridge qbre7e23f1b-07 virtio fa:16:3e:72:ad:53
[heat-admin@overcloud-novacompute-1 ~]$ Controlliamo la tabella di forwarding in br-int su 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 ~]Il traffico deve andare sulla porta 2 — vediamo di che porta si tratta:
[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 ~]$Questa è patch-tun — cioè l'interfaccia in br-tun. Vediamo cosa succede con il pacchetto su 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 ~]$ Il pacchetto viene incapsulato in VxLAN e inviato alla porta 2. Vediamo dove porta la 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 ~]$Questo è un tunnel vxlan su 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 ~]$Andiamo su compute-1 e vediamo cosa succede successivamente con il pacchetto:
[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 ~]$ Il MAC è presente nella tabella di forwarding di br-int su compute-1, e come si può vedere dall'output sopra risulta visibile tramite la porta 2, che è un porta verso 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:46E infine vediamo che in br-int su compute-1 è presente il MAC di destinazione:
[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 ~]$ Cioè, il pacchetto ricevuto verrà inviato alla porta 3, dietro la quale si trova la macchina virtuale instance-00000003.
Tutta la bellezza della distribuzione di Openstack per l'apprendimento su un'infrastruttura virtuale sta nel fatto che possiamo senza problemi catturare il traffico tra gli ipervisori e vedere cosa succede. Questo è ciò che faremo ora, avviando tcpdump sulla porta vnet verso compute-0:
[root@hp-gen9 bormoglotx]# tcpdump -vvv -i vnet3
tcpdump: ascoltando su vnet3, tipo link EN10MB (Ethernet), dimensione di cattura 262144 byte
*****************omesso*******************
04:39:04.583459 IP (tos 0x0, ttl 64, id 16868, offset 0, flags [DF], proto UDP (17), lunghezza 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), lunghezza 84)
10.0.1.85 > 10.0.1.88: richiesta echo ICMP, id 5634, seq 16, lunghezza 64
04:39:04.584449 IP (tos 0x0, ttl 64, id 35181, offset 0, flags [DF], proto UDP (17), lunghezza 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), lunghezza 84)
10.0.1.88 > 10.0.1.85: risposta echo ICMP, id 5634, seq 16, lunghezza 64
*****************omesso*******************La prima riga mostra che un pacchetto con indirizzo 10.0.1.85 sta andando verso l'indirizzo 10.0.1.88 (traffico ICMP), ed è incapsulato in un pacchetto VxLAN con vni 22, mentre il pacchetto proviene dall'host 192.168.255.19 (compute-0) e va all'host 192.168.255.26 (compute-1). Possiamo verificare che il VNI corrisponde a quello specificato in ovs.
Torniamo a questa riga actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:2. 0x16 è il vni in sistema esadecimale. Traduciamo questo numero nel sistema decimale:
16 = 6*16^0+1*16^1 = 6+16 = 22Quindi, il vni corrisponde alla realtà.
La seconda riga mostra il traffico di ritorno, non c'è bisogno di spiegarlo: è già tutto chiaro.
Due macchine in reti diverse (routing tra le reti)
L'ultimo caso per oggi riguarda il routing tra le reti all'interno di un unico progetto utilizzando un router virtuale. Stiamo considerando il caso senza DVR (ne parleremo in un altro articolo), quindi il routing avviene sul nodo di rete. Nel nostro caso, il nodo di rete non è estratto in un'entità separata ed è situato sul nodo di controllo.
Per cominciare, verifichiamo che il routing funzioni:
$ ping 10.0.2.8
PING 10.0.2.8 (10.0.2.8): 56 byte di dati
64 byte da 10.0.2.8: seq=0 ttl=63 time=7.727 ms
64 byte da 10.0.2.8: seq=1 ttl=63 time=3.832 ms
^C
--- statistiche ping per 10.0.2.8 ---
2 pacchetti trasmessi, 2 pacchetti ricevuti, 0% perdita di pacchetti
tempo di andata e ritorno min/medio/max = 3.832/5.779/7.727 msPoiché in questo caso il pacchetto deve andare al gateway per essere instradato, dobbiamo scoprire l'indirizzo MAC del gateway, per questo controlleremo la tabella ARP nell'istanza:
$ arp
host-10-0-1-254.openstacklocal (10.0.1.254) at fa:16:3e:c4:64:70 [ether] su eth0
host-10-0-1-1.openstacklocal (10.0.1.1) at fa:16:3e:e6:2c:5c [ether] su eth0
host-10-0-1-90.openstacklocal (10.0.1.90) at fa:16:3e:83:ad:a4 [ether] su eth0
host-10-0-1-88.openstacklocal (10.0.1.88) at fa:16:3e:72:ad:53 [ether] su eth0Ora vediamo dove deve essere inviato il traffico con destinazione (10.0.1.254) fa:16:3e:c4:64:70:
[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 ~]$ Controlliamo dove porta la porta 2:
[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 ~]$ Tutto è logico, il traffico va verso br-tun. Vediamo in quale tunnel vxlan verrà incapsulato:
[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 ~]$ La terza porta è il tunnel 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 ~]$ Che è collegato al nodo di controllo:
[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 ~]$ Il traffico è arrivato al nodo di controllo, quindi dobbiamo passarci e vedere come avverrà il routing.
Come ricordate, il nodo di controllo all'interno era esattamente come il nodo di calcolo: gli stessi tre bridge, solo che br-ex aveva una porta fisica attraverso la quale il nodo poteva inviare traffico all'esterno. La creazione di istanze ha modificato la configurazione sui nodi di calcolo: sono stati aggiunti linux bridge, iptables e interfacce nei nodi. La creazione di reti e di un router virtuale ha anche lasciato il suo segno sulla configurazione del nodo di controllo.
Quindi, è evidente che l'indirizzo MAC del gateway deve essere nella tabella di forwarding di br-int sul nodo di controllo. Controlliamo se è presente e dove punta:
[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 ~]$ Il MAC è visibile dalla porta qr-0c52b15f-8f. Se torniamo indietro alla lista delle porte virtuali in Openstack, questo tipo di porta viene utilizzato per collegare vari dispositivi virtuali a OVS. Per essere più precisi, qr è la porta verso il router virtuale, che è rappresentato sotto forma di namespace.
Controlliamo quali namespace ci sono sul server:
[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 ~]$ Ci sono tre istanze. Ma a giudicare dai nomi, possiamo intuire lo scopo di ciascuna di esse. Torneremo più tardi alle istanze con ID 0 e 1, ora ci interessa il 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 ~]$ In questo namespace ci sono due interfacce interne, create in precedenza. Entrambi i porti virtuali sono stati aggiunti a br-int. Controlliamo l'indirizzo MAC della porta qr-0c52b15f-8f, poiché il traffico, a giudicare dall'indirizzo MAC di destinazione, è diretto verso questo interfaccia.
[heat-admin@overcloud-controller-0 ~]$ sudo ip netns exec qrouter-0a4d2420-4b9c-46bd-aec1-86a1ef299abe ifconfig qr-0c52b15f-8f
qr-0c52b15f-8f: flags=4163 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
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 ~]$ In questo caso, tutto funziona secondo le leggi della standard routing. Poiché il traffico è destinato all'host 10.0.2.8, deve uscire attraverso il secondo interfaccia qr-92fa49b5-54 e passare attraverso il tunnel vxlan verso il nodo di calcolo:
[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 ~]$ Tutto sembra logico, nessuna sorpresa. Vediamo da dove è visibile l'indirizzo MAC dell'host 10.0.2.8 in 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 ~]$ Come previsto, il traffico passa in br-tun, vediamo in quale tunnel continuerà il traffico:
[heat-admin@overcloud-controller-0 ~]$ sudo ovs-ofctl dump-flows br-tun | grep fa:16:3e:6c:ad:9c
cookie=0x2ab04bf27114410e, durata=5346.829s, tabella=20, n_packets=5248, n_bytes=498512, hard_timeout=300, idle_age=0, hard_age=0, priorità=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 ~]$ Il traffico passa attraverso il tunnel fino a compute-1. E su compute-1 è semplice: dal br-tun il pacchetto arriva nel br-int e da lì all'interfaccia della macchina virtuale:
[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 ~]$ Controlliamo che questo sia effettivamente l'interfaccia corretta:
[heat-admin@overcloud-novacompute-1 ~]$ brctl show
nome del bridge id del bridge STP abilitato interfacce
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
Interfaccia Tipo Fonte Modello MAC
-------------------------------------------------------
tap3210e8ec-c0 bridge qbr3210e8ec-c0 virtio fa:16:3e:6c:ad:9c
[heat-admin@overcloud-novacompute-1 ~]$ In effetti abbiamo seguito tutto il percorso del pacchetto. Penso che abbiate notato che il traffico è passato attraverso diversi tunnel vxlan e usciva con diversi VNI. Diamo un'occhiata a quali sono questi VNI, dopodiché raccoglieremo un dump sulla porta del nodo di controllo e ci assicureremo che il traffico si comporti esattamente come descritto sopra.
Quindi, il tunnel verso compute-0 ha le seguenti actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:3. Traduciamo 0x16 nel sistema decimale:
0x16 = 6*16^0+1*16^1 = 6+16 = 22Il tunnel verso compute-1 ha il seguente VNI:actions=load:0->NXM_OF_VLAN_TCI[],load:0x63->NXM_NX_TUN_ID[],output:2. Traduciamo 0x63 nel sistema decimale:
0x63 = 3*16^0+6*16^1 = 3+96 = 99E adesso diamo un'occhiata al dump:
[root@hp-gen9 bormoglotx]# tcpdump -vvv -i vnet4
tcpdump: in ascolto su vnet4, tipo di collegamento EN10MB (Ethernet), dimensione cattura 262144 bytes
*****************omesso*******************
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: [no 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: richiesta di echo ICMP, 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: [no 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: richiesta di echo ICMP, 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: [no 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: risposta di echo ICMP, 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: [no 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: risposta di echo ICMP, id 5378, seq 9, length 64
*****************omesso*******************Il primo pacchetto è un pacchetto vxlan dall'host 192.168.255.19 (compute-0) all'host 192.168.255.15 (control-1) con vni 22, all'interno del quale è racchiuso un pacchetto ICMP dall'host 10.0.1.85 all'host 10.0.2.8. Come abbiamo calcolato sopra, il vni corrisponde a quello che abbiamo visto nelle uscite.
Il secondo pacchetto è un pacchetto vxlan dall'host 192.168.255.15 (control-1) all'host 192.168.255.26 (compute-1) con vni 99, all'interno del quale è racchiuso un pacchetto ICMP dall'host 10.0.1.85 all'host 10.0.2.8. Come abbiamo calcolato sopra, il vni corrisponde a quello che abbiamo visto nelle uscite.
I due pacchetti successivi sono il traffico di ritorno da 10.0.2.8 a 10.0.1.85.
Quindi, alla fine, abbiamo ottenuto questo schema per il nodo di controllo:

Sembra che sia tutto? Abbiamo dimenticato due namespace:
[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 ~]$ Come abbiamo detto riguardo all'architettura della piattaforma cloud, sarebbe utile che le macchine ricevessero indirizzi automaticamente dal server DHCP. Sono questi i due server DHCP per le nostre due reti 10.0.1.0/24 e 10.0.2.0/24.
Controlliamo se è così. In questo namespace c'è solo un indirizzo: 10.0.1.1 — l'indirizzo del server DHCP stesso, ed è anche incluso in 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 0Vediamo se ci sono processi che contengono nel loro nome qdhcp-67a3798c-32c0-4c18-8502-2531247e3cc2 sul nodo di controllo:
[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 ~]$ Esiste questo processo e in base alle informazioni presentate nell'output sopra possiamo, ad esempio, vedere cosa abbiamo in affitto al 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 ~]$Di conseguenza otteniamo un set di servizi su nodo di controllo:

Tenete presente che si tratta solo di 4 macchine, 2 reti interne e un router virtuale... Attualmente non abbiamo reti esterne, né una miriade di progetti, ciascuno con le proprie reti (che si sovrappongono), e abbiamo disattivato il router distribuito. Infine, nel nostro ambiente di test, c'era solo un nodo di controllo (per la tolleranza ai guasti, dovrebbe esserci un quorum di tre nodi). È logico che nella commercializzazione sia tutto “un po'” più complicato, ma in questo semplice esempio comprendiamo come dovrebbe funzionare: avere 3 o 300 namespace è sicuramente importante, ma dal punto di vista del funzionamento dell'intera struttura, non cambierà molto… a meno che non si introduca un qualche SDN di un fornitore. Ma questa è un'altra storia del tutto.
Spero che sia stato interessante. Se ci sono commenti o integrazioni o se in qualche parte ho mentito chiaramente (sono umano e la mia opinione sarà sempre soggettiva) - scrivetemi cosa correggere o aggiungere - sistemeremo e aggiungeremo tutto.
In conclusione, vorrei dire due parole sul confronto tra Openstack (sia nella versione vanilla sia in quella di fornitori) e la soluzione cloud di VMWare: questa domanda mi è stata posta troppo spesso negli ultimi due anni e, a dire il vero, sono già stanco di rispondere, ma comunque... A mio avviso, è molto difficile comparare queste due soluzioni, ma si può sicuramente affermare che ci sono svantaggi in entrambe le soluzioni e scegliendo una di esse è necessario valutare tutti i pro e i contro.
Se OpenStack è una soluzione guidata dalla comunità, VMWare può fare solo ciò che desidera (leggi – ciò che le conviene) ed è logico, poiché è un'azienda commerciale abituata a guadagnare denaro dai propri clienti. Ma c'è un MA grande e grosso: puoi uscire da OpenStack, ad esempio da Nokia, e passare senza troppi problemi a una soluzione di, per esempio, Juniper (Contrail Cloud), ma uscire da VMWare sarà molto difficile. Per me, queste due soluzioni sembrano così: Openstack (quello del fornitore) è una semplice gabbia in cui ti chiudono, ma hai la chiave e puoi uscire in qualsiasi momento. VMWare è una gabbia d'oro, la chiave della gabbia è del padrone e ti costerà molto.
Non sto sostenendo né il primo né il secondo prodotto: scegliete ciò di cui avete bisogno. Ma se dovessi fare questa scelta, sceglierei entrambe le soluzioni: VMWare per il cloud IT (bassi carichi di lavoro, gestione comoda), OpenStack da un qualche fornitore (Nokia e Juniper offrono soluzioni chiavi in mano piuttosto buone) per il cloud Telecom. Non userei Openstack per un cloud puramente IT: è come sparare a un passero con un cannone, ma non vedo controindicazioni ad usarlo, tranne l'eccesso. Tuttavia, usare VMWare nel telecom; è come trasportare ghiaia con un Ford Raptor: bello da vedere, ma il conducente deve fare 10 viaggi invece di uno.
A mio avviso, il più grande svantaggio di VMWare è la sua totale chiusura: l'azienda non fornisce alcuna informazione su come è strutturato, per esempio, il vSAN o cosa ci sia nel core dell'iper-visore; non le conviene semplicemente: ciò significa che non diventerete mai esperti in VMWare: senza il supporto del fornitore, siete destinati a rimanere intrappolati (spesso incontro esperti di VMWare che vengono messi in difficoltà da domande banali). Per me, VMWare è come comprare un'auto con il cofano chiuso a chiave: sì, magari avete specialisti che possono cambiare la cinghia di distribuzione, ma solo chi vi ha venduto questa soluzione può aprire il cofano. Personalmente, non mi piacciono le soluzioni in cui non posso mettere mano. Direte che forse non dovrete mettere mano sotto il cofano. Sì, è possibile, ma vi osserverò quando dovrete assemblare nel cloud una grande funzione composta da 20-30 macchine virtuali, 40-50 reti, metà delle quali vuole uscire all'esterno, e l'altra metà richiede accelerazione SR-IOV; altrimenti, ne dovrete avere un'altra dozzina di quelle macchine, o non ci sarà sufficiente performance.
Esistono anche altri punti di vista, quindi spetta solo a voi decidere cosa scegliere e, soprattutto, sarete voi a dover rispondere per la vostra scelta. Questa è solo la mia opinione, quella di una persona che ha visto e toccato con mano almeno 4 prodotti: Nokia, Juniper, Red Hat e VMWare. Ho dunque materiale con cui comparare.
Fonte: habr.com
