Wprowadzenie do sieciowej części infrastruktury chmurowej

Wprowadzenie do sieciowej części infrastruktury chmurowej

Chmura obliczeniowa coraz głębiej przenika w nasze życie i chyba nie ma już nikogo, kto choć raz nie korzystałby z jakichkolwiek usług chmurowych. Jednak co takiego jest chmura i jak to działa, w większości nikt nie wie nawet na poziomie idei. 5G staje się już rzeczywistością, a infrastruktura telekomunikacyjna zaczyna przechodzić od rozwiązań stacjonarnych do rozwiązań chmurowych, tak jak kiedyś przechodziła od w pełni żelaznych rozwiązań do zwirtualizowanych „słupów”.

Dziś porozmawiamy o wewnętrznym świecie infrastruktury chmurowej, a w szczególności omówimy podstawy części sieciowej.

Czym jest chmura? To samo co wirtualizacja — widok w profilu?

Bardzo logiczne pytanie. Nie — to nie jest wirtualizacja, chociaż nie obeszło się bez niej. Rozważmy dwa definicje:

Chmura obliczeniowa (dalej Chmura) — to model zapewniający użytkownikowi wygodny dostęp do rozproszonych zasobów obliczeniowych, które powinny być uruchomione na żądanie z minimalnym możliwym opóźnieniem i minimalnymi kosztami ze strony dostawcy usług.

Wirtualizacja — to możliwość podziału jednej fizycznej jednostki (na przykład serwera) na kilka wirtualnych, tym samym zwiększając wykorzystanie zasobów (na przykład, jeśli miałeś 3 serwery obciążone w 25-30 procentach, po wirtualizacji otrzymujesz 1 serwer obciążony w 80-90 procentach). Oczywiście wirtualizacja zabiera część zasobów — musisz „nakarmić” hipernadzorcę, jednak, jak pokazuje praktyka, gra jest warta świeczki. Idealnym przykładem wirtualizacji jest VMWare, która doskonale przygotowuje maszyny wirtualne, lub na przykład KVM, który bardziej mi odpowiada, ale to już sprawa gustu.

Korzystamy z wirtualizacji, nie zdając sobie z tego sprawy, nawet fizyczne routery już korzystają z wirtualizacji — na przykład w ostatnich wersjach systemu operacyjnego JunOS instalowany jest jako maszyna wirtualna na dystrybucji Linuxa czasu rzeczywistego (Wind River 9). Ale wirtualizacja to nie chmura, jednak chmura nie może istnieć bez wirtualizacji.

Wirtualizacja to jeden z fundamentów, na których budowana jest chmura.

Stworzenie chmury poprzez połączenie kilku hypervisorów w jedną domenę L2, dodanie kilku skryptów YAML do automatyzacji przypisywania VLAN-ów przez ansible i nałożenie na to jakiegoś systemu orkiestracji do automatycznego tworzenia maszyn wirtualnych — to nie zadziała. Dokładniej mówiąc, zadziała, ale otrzymany Frankenstein to nie jest ta chmura, której potrzebujemy, chociaż może dla niektórych to jest spełnienie marzeń. Poza tym jeśli weźmiemy OpenStack, to zasadniczo też jest zawikłanym Frankensteinem, ale nie o tym teraz mówmy.

Ale rozumiem, że z powyższej definicji nie do końca wynika, co właściwie można nazwać chmurą.

Dlatego w dokumencie NIST (National Institute of Standards and Technology) wymieniono 5 podstawowych cech, którymi powinna charakteryzować się infrastruktura chmurowa:

Dostarczenie usługi na żądanie. Użytkownik powinien mieć łatwy dostęp do przydzielonych mu zasobów komputerowych (takich jak sieci, wirtualne dyski, pamięć, rdzenie procesorów itp.), przy czym te zasoby powinny być udostępniane automatycznie — to znaczy bez ingerencji ze strony dostawcy usług.

Szeroka dostępność usługi. Dostęp do zasobów powinien być zapewniany przy użyciu standardowych mechanizmów, aby umożliwić dostęp zarówno z standardowych komputerów, jak i z terminali cienkowarstwowych oraz urządzeń mobilnych.

Łączenie zasobów w pule. Pule zasobów powinny umożliwiać jednoczesne dostarczanie zasobów wielu klientom, zapewniając izolację między nimi oraz brak wzajemnego oddziaływania i konkurencji o zasoby. Pule obejmują również sieci, co sugeruje możliwość stosowania zbieżnego adresowania. Pule powinny wspierać skalowanie na żądanie. Użycie pul pozwala zapewnić niezbędny poziom odporności na awarie zasobów oraz abstrakcję zasobów fizycznych i wirtualnych — odbiorca usługi po prostu otrzymuje żądany zestaw zasobów (gdzie te zasoby są fizycznie zlokalizowane, na ilu serwerach i switchach — dla klienta to nie ma znaczenia). Jednak należy uwzględnić fakt, że dostawca musi zapewnić przezroczyste rezerwowanie tych zasobów.

Szybka adaptacja do różnych warunków. Usługi muszą być elastyczne – szybkie udostępnianie zasobów, ich redistribucja oraz dodawanie lub redukowanie zasobów na żądanie klienta, przy czym klient powinien mieć wrażenie, że zasoby chmury są nieskończone. Dla uproszczenia zrozumienia, na przykład, nie widzisz powiadomienia, że w Apple iCloud zniknęła część przestrzeni dyskowej z powodu awarii twardego dysku serwera, a dyski się psują. Ponadto z twojej perspektywy możliwości tego serwisu są praktycznie nieograniczone – potrzebujesz 2 TB – żaden problem, zapłać i otrzymaj. Podobnie można przytoczyć przykład z Google Drive lub Yandex.Disk.

Możliwość pomiaru świadczonej usługi. Systemy chmurowe muszą automatycznie monitorować i optymalizować zużywane zasoby, przy czym mechanizmy te powinny być przejrzyste zarówno dla użytkownika, jak i dla dostawcy usług. Oznacza to, że zawsze możesz sprawdzić, ile zasobów zużywają ty i twoi klienci.

Należy wziąć pod uwagę, że te wymagania w większości są wymaganiami dla publicznej chmury, dlatego dla chmury prywatnej (czyli chmury uruchomionej dla wewnętrznych potrzeb firmy) te wymagania mogą być nieco skorygowane. Muszą być jednak spełnione, w przeciwnym razie nie uzyskamy wszystkich korzyści z obliczeń chmurowych.

Po co nam chmura?

Jednak każda nowa lub już istniejąca technologia, każdy nowy protokół jest tworzony w jakimś celu (no, poza RIP-ng oczywiście). Protokół dla protokołu – nikomu nie jest potrzebny (no, poza RIP-ng oczywiście). Logicznym jest, że chmura jest tworzona, aby dostarczyć jakiś serwis użytkownikowi/klientowi. Wszyscy znamy przynajmniej kilka chmurowych usług, takich jak Dropbox czy Google Docs, i przypuszczam, że większość z nich skutecznie korzysta – na przykład ten artykuł został napisany przy użyciu chmurowej usługi Google Docs. Ale znane nam usługi chmurowe to tylko część możliwości chmury – dokładniej, to tylko usługa typu SaaS. Oferowanie usługi chmurowej możemy realizować na trzy sposoby: w formie SaaS, PaaS lub IaaS. Jakiej usługi potrzebujesz, zależy od twoich życzeń i możliwości.

Zastanówmy się nad każdym z nich po kolei:

Oprogramowanie jako usługa (SaaS) to jest model dostarczania pełnoprawnej usługi klientowi, na przykład usług pocztowych takich jak Yandex.Mail czy Gmail. W takim modelu dostarczania usługi, jako klient, de facto nic nie robisz oprócz korzystania z serwisu — to znaczy, nie musisz się martwić o konfigurację usługi, jej awaryjność czy rezerwację. Najważniejsze to nie skompromitować swojego hasła, a wszystko inne załatwi dostawca tej usługi. Z punktu widzenia dostawcy usługi — ponosi on pełną odpowiedzialność za cały serwis — począwszy od sprzętu serwerowego i systemów operacyjnych hostów, a skończywszy na konfiguracjach baz danych i oprogramowania.

Platforma jako usługa (PaaS) to model, w którym dostawca usług udostępnia klientowi szablon pod usługę, na przykład serwer Web. Dostawca usług zapewnił klientowi wirtualny serwer (de facto zestaw zasobów, takich jak RAM / CPU / Storage / Nets itd.), a nawet zainstalował na tym serwerze system operacyjny i niezbędne oprogramowanie, jednak całą konfigurację tego sprzętu klient wykonuje sam i za działanie usługi odpowiada już klient. Dostawca usług, podobnie jak w poprzednim przypadku, odpowiada za działanie fizycznego sprzętu, hipernadzorców, samej wirtualnej maszyny, jej dostępności sieciowej itd., ale sama usługa już nie leży w jego gestii.

Infrastruktura jako usługa (IaaS) wykorzystuje podejście, które jest znacznie ciekawsze, ponieważ dostawca usług faktycznie udostępnia klientowi pełną wirtualizowaną infrastrukturę — to znaczy pewien zestaw (pulę) zasobów, takich jak rdzenie CPU, RAM, sieci itd. Wszystko inne zależy od klienta — co klient chce zrobić z tymi zasobami w ramach przydzielonej mu puli (kwot) — dostawcy nie interesuje zbytnio. Jeśli klient chce stworzyć własny vEPC lub wręcz zostać mini operatorem i świadczyć usługi telekomunikacyjne — nie ma problemu — rób to. W takim scenariuszu dostawca usług odpowiada za dostarczenie zasobów, ich niezawodność oraz dostępność, a także za system operacyjny umożliwiający łączenie tych zasobów w pule i udostępnianie ich klientowi z możliwością w każdej chwili zwiększenia lub zmniejszenia zasobów na żądanie klienta. Wszystkie maszyny wirtualne i inne opcje klient konfiguruje samodzielnie przez portal samoobsługowy i konsolę, w tym również konfigurację sieci (z wyjątkiem sieci zewnętrznych).

Czym jest OpenStack?

We wszystkich trzech wariantach dostawca usług potrzebuje systemu operacyjnego, który pozwoli stworzyć infrastrukturę chmurową. W rzeczywistości w przypadku SaaS za cały stos technologiczny odpowiada nie jedno, a kilka działów — jest dział, który odpowiada za infrastrukturę, czyli zapewnia IaaS innemu działowi, ten dział dostarcza klientowi SaaS. OpenStack jest jednym z systemów operacyjnych chmurowych, który pozwala połączyć wiele przełączników, serwerów i systemów pamięci masowej w jeden zasobowy pul, dzielić ten ogólny pul na subpule (tenancy) i udostępniać te zasoby klientom przez sieć.

OpenStack — to chmurowy system operacyjny, który pozwala kontrolować duże pule zasobów obliczeniowych, pamięci masowej i zasobów sieciowych, których przydzielanie i zarządzanie odbywa się za pośrednictwem API z wykorzystaniem standardowych mechanizmów uwierzytelniania.

Innymi słowy, to zestaw projektów wolnego oprogramowania, który ma na celu tworzenie usług chmurowych (zarówno publicznych, jak i prywatnych) — czyli zestaw narzędzi, które pozwalają zintegrować sprzęt serwerowy i przełącznikowy w jeden pul zasobów, zarządzać tymi zasobami, zapewniając wymagany poziom odporności na awarie.

W momencie pisania tego materiału struktura OpenStack wygląda następująco:
Wprowadzenie do sieciowej części infrastruktury chmurowej
Obraz przejęty z openstack.org

Każda z komponent, które wchodzą w skład OpenStack, wykonuje jakąś określoną funkcję. Taka rozproszona architektura pozwala na włączenie do rozwiązania tych komponentów, które są Ci potrzebne. Jednak część komponentów jest podstawowymi komponentami, a ich usunięcie spowoduje całkowitą lub częściową niezdolność działania rozwiązania jako całości. Do takich komponentów należy zaliczyć:

  • Dashboard — GUI na bazie sieci do zarządzania usługami OpenStack
  • Keystone — zcentralizowana usługa identyfikacji, która zapewnia funkcjonalność uwierzytelniania i autoryzacji dla innych usług, a także zarządza danymi użytkowników i ich rolami.
  • Neutron — usługa sieciowa, zapewniająca łączność między interfejsami różnych usług OpenStack (w tym łączność między VM a dostępem do zewnętrznego świata)
  • Cinder — zapewnia dostęp do pamięci blokowej dla maszyn wirtualnych
  • Nova — zarządzanie cyklem życia maszyn wirtualnych
  • Glance — repozytorium obrazów maszyn wirtualnych i zrzutów pamięci
  • Swift — zapewnia dostęp do obiektowego magazynu
  • Ceilometer — usługa umożliwiająca zbieranie telemetrii oraz pomiar dostępnych i używanych zasobów
  • Heat — orkiestracja oparta na szablonach dla automatycznego tworzenia i provisioning zasobów

Pełna lista wszystkich projektów i ich przeznaczenie jest dostępna do wglądu tutaj.

Każdy z komponentów OpenStack to usługa odpowiedzialna za określoną funkcję, która zapewnia API do zarządzania tą funkcją oraz współdziałania tej usługi z innymi usługami systemu operacyjnego chmury w celu stworzenia jednolitej infrastruktury. Na przykład, Nova zajmuje się zarządzaniem zasobami obliczeniowymi oraz API do dostępu do konfiguracji tych zasobów, Glance – zarządza obrazami i API do ich obsługi, Cinder – zajmuje się magazynowaniem bloków i API do ich zarządzania itd. Wszystkie funkcje są ze sobą ściśle powiązane.

Jednak jeśli spojrzeć na to, to wszystkie usługi uruchomione w OpenStack ostatecznie reprezentują jakąś maszynę wirtualną (lub kontener) podłączoną do sieci. Powstaje więc pytanie — po co nam tyle elementów?

Przejdźmy przez algorytm tworzenia maszyny wirtualnej i jej podłączenia do sieci oraz pamięci trwałej w OpenStack.

  1. Kiedy składasz żądanie utworzenia maszyny, niezależnie od tego, czy jest to żądanie poprzez Horizon (pulpit nawigacyjny) czy za pomocą CLI, pierwszą rzeczą, która się dzieje, jest autoryzacja twojego żądania w Keystone — czy możesz tworzyć maszyny, masz prawo korzystać z danej sieci, czy projekt ma wystarczającą ilość kwoty itd.
  2. Keystone autoryzuje twoje żądanie i generuje w odpowiedzi token auth, który będzie użyty później. Po otrzymaniu odpowiedzi od Keystone żądanie jest wysyłane w stronę Nova (nova api).
  3. Nova-api sprawdza ważność twojego żądania, zwracając się do Keystone, używając wcześniej wygenerowanego tokena auth.
  4. Keystone przeprowadza autoryzację i na podstawie tego tokena auth przekazuje informacje o zezwoleniach i ograniczeniach.
  5. Nova-api tworzy w bazie danych nova-database wpis o nowej VM i przesyła żądanie utworzenia maszyny do nova-scheduler.
  6. Nova-scheduler wybiera hosta (węzeł komputerowy), na którym VM zostanie wdrożona na podstawie określonych parametrów, wag i stref. Informacja o tym oraz identyfikator VM są zapisywane w bazie danych nova.
  7. Następnie nova-scheduler zwraca się do nova-compute z prośbą o wdrożenie instancji. Nova-compute kontaktuje się z nova-conductor, aby uzyskać informacje o parametrach maszyny (nova-conductor jest elementem nova, który pełni rolę serwera proxy między nova-database a nova-compute, ograniczając liczbę zapytań kierowanych do nova-database w celu uniknięcia problemów z konsystencją bazy danych i zmniejszenia obciążenia).
  8. Nova-conductor otrzymuje z nova-database żądane informacje i przekazuje je do nova-compute.
  9. Następnie nova-compute zwraca się do glance po ID obrazu. Glance przeprowadza walidację żądania w Keystone i zwraca żądane informacje.
  10. Nova-compute kontaktuje się z neutron, aby uzyskać informacje o parametrach sieci. Podobnie jak glance, neutron przeprowadza walidację żądania w Keystone, następnie tworzy zapis w bazie danych (identyfikator portu itd.), tworzy żądanie o utworzenie portu i zwraca żądane informacje do nova-compute.
  11. Nova-compute zwraca się do cinder z prośbą o przydzielenie woluminu maszynie wirtualnej. Podobnie jak glance, cinder przeprowadza walidację żądania w Keystone, tworzy żądanie o utworzenie woluminu i zwraca żądane informacje.
  12. Nova-compute kontaktuje się z libvirt z prośbą o wdrożenie maszyny wirtualnej z określonymi parametrami.

W rzeczywistości, wydaje się, że prosta operacja stworzenia wirtualnej maszyny przekształca się w wir wywołań API między elementami platformy chmurowej. Jak widzisz, nawet wcześniej określone usługi składają się z mniejszych komponentów, które ze sobą współdziałają. Utworzenie maszyny to tylko mała część możliwości, jakie daje platforma chmurowa — istnieje usługa odpowiedzialna za równoważenie ruchu, usługa odpowiedzialna za pamięć blokową, usługa odpowiedzialna za DNS, usługa odpowiedzialna za provisionowanie serwerów bare metal itd. Chmura pozwala Ci traktować Twoje wirtualne maszyny jak stado owiec (w przeciwieństwie do wirtualizacji). W przypadku środowiska wirtualnego, gdy coś się dzieje z maszyną, przywracasz ją z kopii zapasowych itd., podczas gdy aplikacje chmurowe są skonstruowane tak, aby wirtualna maszyna nie odgrywała tak ważnej roli — wirtualna maszyna „umarła” — to nie problem — po prostu tworzona jest nowa maszyna na podstawie szablonu i, jak to się mówi, oddział nie zauważył straty żołnierza. Oczywiście wymaga to posiadania mechanizmów orkiestracji — korzystając z szablonów Heat, możesz bez większych problemów wdrożyć skomplikowaną funkcję składającą się z dziesiątek sieci i wirtualnych maszyn.

Zawsze należy mieć na uwadze, że infrastruktura chmurowa nie istnieje bez sieci — każdy element w ten czy inny sposób współdziała z innymi elementami przez sieć. Ponadto chmura ma absolutnie niestatyczną sieć. Oczywiście sieć underlay jest bardziej lub mniej statyczna — nowe węzły i przełączniki nie są dodawane codziennie, jednak składnik overlay może i nieuchronnie będzie się zmieniać — mogą być dodawane lub usuwane nowe sieci, pojawiać się nowe wirtualne maszyny i umierać stare. Jak pamiętasz z definicji chmury podanej na początku artykułu — zasoby powinny być przydzielane użytkownikowi automatycznie i z jak najmniejszą (a najlepiej bez) interwencją ze strony dostawcy usług. Oznacza to, że typ udostępniania zasobów sieci, który obecnie istnieje w formie frontendowej w postaci twojego panelu osobistego dostępnego przez http/https oraz dyżurnego inżyniera sieciowego Wasilija jako backendu — to nie jest chmura, nawet przy ośmiu rękach Wasilija.

Neutron, będący usługą sieciową, zapewnia API do zarządzania częścią sieciową infrastruktury chmurowej. Usługa ta umożliwia działanie i zarządzanie siecią OpenStack, zapewniając poziom abstrakcji zwany Network-as-a-Service (NaaS). Oznacza to, że sieć jest takim samym wirtualnym, mierzalnym zasobem, jak na przykład wirtualne rdzenie CPU czy ilość RAM.

Jednak zanim przejdziemy do architektury sieciowej OpenStack, przyjrzyjmy się, jak ta sieć działa w OpenStack i dlaczego jest ona ważną i nieodłączną częścią chmury.

Mamy dwie wirtualne maszyny klienta RED i dwie wirtualne maszyny klienta GREEN. Załóżmy, że te maszyny są rozmieszczone na dwóch hypervisorach w ten sposób:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Na obecnym etapie to tylko wirtualizacja 4 serwerów i nic więcej, ponieważ jak dotąd wszystko, co zrobiliśmy – to wirtualizacja 4 serwerów, umieszczając je na dwóch fizycznych serwerach. Co więcej, one nawet nie są jeszcze podłączone do sieci.

Aby stworzyć chmurę, musimy dodać kilka komponentów. Po pierwsze, wirtualizujemy część sieciową – musimy połączyć te 4 maszyny parami, przy czym klienci chcą połączenia L2. Można oczywiście użyć przełącznika i skonfigurować w jego stronę trunk oraz rozwiązać wszystko za pomocą linux bridge, albo dla bardziej zaawansowanych użytkowników openvswitch (do którego jeszcze wrócimy). Ale sieci może być bardzo dużo, a ciągłe przepychanie L2 przez switch – to nie najlepszy pomysł; różne działy, serwis helpdesk, miesiące oczekiwania na realizację zgłoszenia, tygodnie rozwiązywania problemów – w nowoczesnym świecie takie podejście już nie działa. Im szybciej firma to zrozumie, tym łatwiej jej będzie ruszyć naprzód. Dlatego między hypervisorami wydzielimy sieć L3, przez którą będą komunikować się nasze wirtualne maszyny, a już na tej sieci L3 zbudujemy wirtualne nakładkowe sieci L2 (overlay), w których będzie biegał ruch naszych wirtualnych maszyn. Jako enkapsulację możemy wykorzystać GRE, Geneve lub VxLAN. Na razie zatrzymamy się na ostatnim, chociaż to nie jest szczególnie istotne.

Musimy gdzieś umieścić VTEP (mam nadzieję, że wszyscy znają terminologię VxLAN). Ponieważ z serwerów wychodzi od razu sieć L3, nic nie stoi na przeszkodzie, aby umieścić VTEP na samych serwerach, a OVS (OpenvSwitch) doskonale potrafi to robić. W rezultacie uzyskaliśmy taką konstrukcję:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Ponieważ ruch między VM musi być podzielony, porty w stronę maszyn wirtualnych będą miały różne numery VLAN. Numer taga ma znaczenie tylko w obrębie jednego wirtualnego przełącznika, ponieważ przy enkapsulacji w VxLAN możemy go bez problemu usunąć, ponieważ będziemy mieć VNI.

Wprowadzenie do sieciowej części infrastruktury chmurowej

Teraz możemy swobodnie tworzyć nasze maszyny i wirtualne sieci dla nich bez żadnych problemów.

Co jednak jeśli klient ma jeszcze jedną maszynę, ale znajduje się ona w innej sieci? Potrzebujemy routingu między sieciami. Zajmiemy się prostym wariantem, gdy używa się zcentralizowanego routingu — czyli ruch jest routowany przez specjalne wydzielone węzły sieciowe (zazwyczaj łączą się one z węzłami kontrolnymi, więc będziemy mieć to samo).

Niby nic trudnego — robimy interfejs mostka na węźle kontrolnym, kierujemy ruch na niego i stamtąd routujemy go tam, gdzie potrzebujemy. Ale problemem jest to, że klient RED chce używać sieci 10.0.0.0/24, a klient GREEN chce używać sieci 10.0.0.0/24. To oznacza, że zaczyna nam się nakładać przestrzeń adresowa. Ponadto klienci nie chcą, aby inni klienci mieli dostęp do ich sieci wewnętrznych, co jest logiczne. Aby oddzielić sieci i ruch danych klientów, przydzielimy każdemu z nich oddzielną przestrzeń nazw. Przestrzeń nazw to w zasadzie kopia stosu sieciowego Linuxa, czyli klienci w przestrzeni nazw RED są całkowicie izolowani od klientów w przestrzeni nazw GREEN (lub routing między tymi sieciami klientów jest dozwolony przez domyślną przestrzeń nazw lub już na wyższym sprzęcie transportowym).

Otrzymujemy więc następujący schemat:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Tuneli L2 zbiega się ze wszystkich węzłów obliczeniowych do węzła kontrolnego, gdzie znajduje się interfejs L3 dla tych sieci, każdy w wydzielonej przestrzeni nazw dla izolacji.

Jednak zapomnieliśmy o najważniejszym. Wirtualna maszyna musi zapewniać usługi klientowi, to znaczy, że musi mieć przynajmniej jeden zewnętrzny interfejs, przez który można się do niej dostać. Musimy więc wyjść na zewnątrz. Istnieje kilka opcji. Zastosujmy najprostsze rozwiązanie. Dodamy klientom po jednej sieci, które będą ważne w sieci dostawcy i nie będą się pokrywać z innymi sieciami. Sieci mogą również być nakładające się i korzystać z różnych VRF w sieci dostawcy. Te sieci będą również żyły w przestrzeni nazw każdego z klientów. Jednak wyjście na zewnątrz odbędzie się przez jeden fizyczny (lub zgrupowany, co jest bardziej logiczne) interfejs. Aby rozdzielić ruch klientów, ruch wychodzący na zewnątrz będzie oznaczany tagiem VLAN przydzielonym klientowi.

W efekcie uzyskaliśmy taką schemę:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Rozsądne pytanie – dlaczego nie stworzyć bramek na samych węzłach obliczeniowych? Nie ma w tym wielkiego problemu, więcej, przy włączeniu rozproszonego routera (DVR) to również będzie działać. W tym scenariuszu rozważamy najprostsze rozwiązanie z centralizowaną bramą, która jest używana domyślnie w Openstack. Dla wysoko obciążonych funkcji będą wykorzystywane zarówno rozproszony router, jak i technologie przyspieszające, takie jak SR-IOV i Passthrough, ale jak to się mówi, to już zupełnie inna historia. Na początek zajmijmy się podstawową częścią, a potem przejdźmy do szczegółów.

Właściwie nasza schemat już działa, jednak są pewne niuanse:

  • Musimy jakoś zabezpieczyć nasze maszyny, to znaczy, nałożyć filtr na interfejs przełącznika w stronę klienta.
  • Zróbmy możliwość automatycznego uzyskiwania adresu IP przez wirtualną maszynę, aby nie trzeba było za każdym razem wchodzić do niej przez konsolę i wpisywać adresu.

Zacznijmy od zabezpieczenia maszyn. Można do tego użyć zwykłych iptables, czemu nie.

To znaczy, że teraz nasza topologia już nieco się skomplikowała:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Idźmy dalej. Musimy dodać serwer DHCP. Najlepszym miejscem na umieszczenie serwerów DHCP dla każdego z klientów będzie już wspomniana kontrolna noda, gdzie znajdują się przestrzenie nazw:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Jednakże, istnieje mały problem. Co jeśli wszystko się zrestartuje i wszystkie informacje o wynajmie adresów w DHCP znikną? Logiczne jest, że maszynom będą przydzielane nowe adresy, co jest dość niewygodne. Istnieją dwa rozwiązania - albo użyć nazw domenowych i dodać serwer DNS dla każdego klienta, wtedy adres nie będzie dla nas zbyt ważny (analogicznie do części sieci w k8s) - ale tutaj pojawia się problem z zewnętrznymi sieciami, ponieważ w nich także mogą być przydzielane adresy przez DHCP - potrzebna jest synchronizacja z serwerami DNS w chmurze i zewnętrznym serwerem DNS, co moim zdaniem nie jest zbyt elastyczne, jednak całkowicie możliwe. Drugą opcją jest użycie metadanych - to znaczy zapisanie informacji o przydzielonym adresie maszyny, aby serwer DHCP wiedział, jaki adres przydzielić, jeśli maszyna już otrzymała adres. Druga opcja jest prostsza i bardziej elastyczna, ponieważ pozwala na zachowanie dodatkowych informacji o maszynie. Teraz dodajmy do schematu agenta metadanych:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Jeszcze jedno pytanie, które także warto poruszyć - to możliwość korzystania z jednej zewnętrznej sieci przez wszystkich klientów, ponieważ zewnętrzne sieci, jeśli mają być ważne w całej sieci, będą powodować trudności - trzeba nieustannie przydzielać i kontrolować przydzielanie tych sieci. Możliwość wykorzystania jednolitej, wstępnie skonfigurowanej zewnętrznej sieci dla wszystkich klientów będzie bardzo użyteczna przy tworzeniu publicznej chmury. To uprości wdrażanie maszyn, ponieważ nie trzeba będzie porównywać z bazą danych adresów i wybierać unikalnej przestrzeni adresowej dla zewnętrznej sieci każdego klienta. Ponadto możemy zapisać zewnętrzną sieć z wyprzedzeniem, a w momencie wdrażania będziemy musieli jedynie skojarzyć zewnętrzne adresy z maszynami klientów.

I tutaj na pomoc przychodzi NAT — po prostu umożliwimy klientom wychodzenie na zewnątrz przez default namespace z wykorzystaniem translacji NAT. Tutaj pojawia się mały problem. To działa dobrze, jeśli serwer klienta działa jako klient, a nie jako serwer — to znaczy inicjuje, a nie odbiera połączenia. Ale u nas będzie odwrotnie. W tym przypadku musimy zrobić destination NAT, aby przy odbieraniu ruchu węzeł kontrolny zrozumiał, że dany ruch jest przeznaczony dla maszyny wirtualnej klienta A, a więc musi zostać zastosowana translacja NAT z adresu zewnętrznego, np. 100.1.1.1 na adres wewnętrzny 10.0.0.1. W takim przypadku, chociaż wszyscy klienci będą korzystać z tej samej sieci, wewnętrzna izolacja pozostaje całkowicie zachowana. Musimy więc na węźle kontrolnym wykonać dNAT i sNAT. Użycie jednej sieci z przydzieleniem adresów pływających lub zewnętrznych sieci, lub obu jednocześnie, zależy od tego, co chcecie wciągnąć do chmury. Nie będziemy nanosić na schemat pływających adresów, a zostawimy już wcześniej dodane zewnętrzne sieci — każdy klient ma swoją zewnętrzną sieć (na schemacie oznaczone jako VLAN 100 i 200 na interfejsie zewnętrznym).

Ostatecznie otrzymaliśmy interesujące i jednocześnie przemyślane rozwiązanie, które ma pewną elastyczność, ale na razie nie dysponuje mechanizmami odporności na awarie.

Po pierwsze, mamy tylko jeden węzeł kontrolny — jego awaria doprowadzi do upadku wszystkich systemów. Aby rozwiązać ten problem, konieczne jest stworzenie co najmniej kworum z 3 węzłów. Dodamy to do schematu:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Oczywiście wszystkie węzły synchronizują się, a w przypadku awarii aktywnego węzła, jego obowiązki przejmie inny węzeł.

Następny problem dotyczy dysków maszyn wirtualnych. Obecnie są one przechowywane na samych hipernadzorcach, a w przypadku problemów z hipernadzorcą tracimy wszystkie dane — a RAID nic tu nie pomoże, jeśli stracimy nie tylko dysk, ale cały serwer. Dlatego musimy stworzyć usługę, która będzie działać jako frontend dla dowolnego magazynu. Nie jest dla nas szczególnie ważne, jakie to będzie magazyn, ale musi chronić nasze dane przed awarią zarówno dysku, jak i węzła, a być może nawet całej szafy. Istnieje kilka opcji — są oczywiście sieci SAN z Fiber Channel, ale powiedzmy szczerze — FC to już relikt przeszłości — analog E1 w transporcie — zgadzam się, nadal jest używany, ale tylko tam, gdzie nie ma innego wyjścia. Dlatego dobrowolne uruchamianie sieci FC w 2020 roku bym nie zrobił, mając na uwadze inne, bardziej interesujące alternatywy. Choć każdy ma swoje zdanie i mogą się znaleźć tacy, którzy uważają, że FC ze swoimi ograniczeniami to wszystko, czego potrzebujemy — nie będę dyskutował, każdy ma swoje zdanie. Najciekawszym rozwiązaniem, moim zdaniem, jest użycie SDS, na przykład Ceph.

Ceph pozwala na zbudowanie wysoce dostępnego rozwiązania do przechowywania danych z wieloma możliwymi opcjami rezerwacji, zaczynając od kodów z parzystością (analog RAID 5 lub 6) po pełną replikację danych na różne dyski, z uwzględnieniem lokalizacji dysków w serwerach oraz serwerów w szafach itd.

Aby zbudować Ceph, potrzebujemy jeszcze 3 węzłów. Interakcja z magazynem będzie również odbywać się przez sieć z wykorzystaniem usług blokowego, obiektowego i plikowego przechowywania. Dodajemy do schematu magazyn:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Uwaga: można tworzyć hiperzwirtualizowane węzły obliczeniowe — to koncepcja łączenia kilku funkcji w jednym węźle — na przykład storage + compute — nie wydzielać specjalnych węzłów pod ceph storage. Otrzymujemy taką samą architekturę odporną na awarie — ponieważ SDS zarezerwuje dane zgodnie z podanym przez nas poziomem rezerwacji. Jednak hiperzwirtualizowane węzły to zawsze kompromis — ponieważ węzeł storage nie tylko „nie grzeje powietrza”, jak to się wydaje na pierwszy rzut oka (ponieważ nie ma na nim maszyn wirtualnych) — zużywa zasoby CPU na obsługę SDS (w rzeczywistości w tle realizuje wszystkie replikacje, przywracanie po awariach węzłów, dysków, itd.). Oznacza to, że stracisz część mocy węzła obliczeniowego, łącząc go z storage.

Całym tym dobrodziejstwem należy jakoś zarządzać — potrzebujemy czegoś, przez co możemy stworzyć maszynę, sieć, wirtualny router itd. W tym celu dodamy do węzła kontrolnego usługę, która pełni rolę pulpitu nawigacyjnego — klient będzie mógł połączyć się z tym portalem przez http/https i zrobić wszystko, co potrzebuje (no prawie).

W rezultacie teraz mamy system odporny na awarie. Wszystkimi elementami tej infrastruktury należy jakoś zarządzać. Wcześniej opisano, że OpenStack to zbiór projektów, z których każdy zapewnia jakąś określoną funkcję. Jak widzimy, elementów, które trzeba konfigurować i kontrolować, jest więcej niż wystarczająco. Dziś porozmawiamy o części sieciowej.

Architektura Neutron

W OpenStack Neutron odpowiada za łączenie portów maszyn wirtualnych z wspólną siecią L2, zapewnienie routingu ruchu między VM znajdującymi się w różnych sieciach L2 oraz routingu na zewnątrz, dostarczanie takich usług jak NAT, Floating IP, DHCP itd.

Wysoko poziomowo pracę usługi sieciowej (podstawowa część) można opisać w ten sposób.

Podczas uruchamiania VM usługa sieciowa:

  1. Tworzy port dla danej VM (lub porty) i informuje o tym usługę DHCP;
  2. Tworzony jest nowy wirtualny sprzęt sieciowy (przez libvirt);
  3. VM łączy się z portem stworzonym w kroku 1 (portami);

Jak to dziwne, podstawa działania Neutron opiera się na standardowych mechanizmach znanych każdemu, kto kiedykolwiek zanurzył się w Linux — to namespaces, iptables, mosty linuxowe, openvswitch, conntrack itd.

Należy od razu wyjaśnić, że Neutron nie jest kontrolerem SDN.

Neutron składa się z kilku powiązanych ze sobą komponentów:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Openstack-neutron-server — to demon, który działa na podstawie zapytań użytkowników za pośrednictwem API. Ten demon nie zajmuje się konfiguracją połączeń sieciowych, ale dostarcza niezbędne informacje swoim wtyczkom, które następnie konfigurują odpowiadający element sieci. Agenci Neutrona na węzłach OpenStack rejestrują się na serwerze Neutron.

Neutron-server to w zasadzie aplikacja napisana w Pythonie, składająca się z dwóch części:

  • Usługa REST
  • Wtyczka Neutron (core/service)

Usługa REST jest przeznaczona do przyjmowania wywołań API od innych komponentów (np. żądania dostarczenia jakichkolwiek informacji itp.)

Wtyczki to programowe komponenty/moduły, które są wywoływane przy zapytaniach API — to znaczy, przypisanie jakiejś usługi odbywa się przez nie. Wtyczki dzielą się na dwa rodzaje — wtyczkę serwisową i korzenną. Zazwyczaj wtyczka korzenna odpowiada głównie za zarządzanie przestrzenią adresową i połączeniami L2 między VM, podczas gdy wtyczki serwisowe zapewniają dodatkowe funkcje, takie jak VPN lub FW.

Listę dostępnych dzisiaj wtyczek można zobaczyć na przykład tutaj

Może być kilka wtyczek serwisowych, jednak wtyczka korzenna może być tylko jedna.

Openstack-neutron-ml2 — to standardowa wtyczka korzenna Openstack. Ta wtyczka ma architekturę modułową (w przeciwieństwie do swojego poprzednika) i poprzez dołączone do niej sterowniki konfiguruje usługę sieciową. Samą wtyczkę omówimy nieco później, ponieważ praktycznie ona zapewnia tę elastyczność, którą OpenStack ma w zakresie sieci. Wtyczka korzenna może być wymieniona (na przykład Contrail Networking dokonuje takiej wymiany).

Usługa RPC (rabbitmq-server) — usługa, która zapewnia zarządzanie kolejkami i interakcję z innymi usługami OpenStack oraz komunikację między agentami usług sieciowych.

Agenci sieciowi — agenci, którzy znajdują się w każdej nodze, przez których realizowana jest konfiguracja usług sieciowych.

Agenci występują w kilku rodzajach.

Główny agent — to agent L2. Te agenty są uruchamiane na każdym z hipervizorów, w tym na węzłach kontrolnych (dokładniej mówiąc, na wszystkich węzłach, które zapewniają jakiekolwiek usługi dla dzierżawców) i ich główną funkcją jest podłączenie maszyn wirtualnych do wspólnej sieci L2, a także generowanie powiadomień w przypadku wystąpienia jakichkolwiek zdarzeń (na przykład wyłączenia/włączenia portu).

Kolejnym, nie mniej ważnym agentem jest agent L3. Domyślnie ten agent uruchamiany jest wyłącznie na węźle sieci (często węzeł sieciowy jest połączony z węzłem kontrolnym) i zapewnia routowanie pomiędzy sieciami dzierżawców (zarówno pomiędzy jego sieciami a sieciami innych dzierżawców, jak i dostęp do świata zewnętrznego, zapewniając NAT oraz usługę DHCP). Jednak w przypadku użycia DVR (rozproszonego routera) potrzeba wtyczki L3 pojawia się także na węzłach obliczeniowych.

Agent L3 wykorzystuje przestrzenie nazw Linux do zapewnienia każdemu dzierżawcy zestawu własnych izolowanych sieci oraz funkcjonalności wirtualnych routerów, które kierują ruchem i zapewniają usługi bramy dla sieci warstwy 2.

Baza danych — baza danych identyfikatorów sieci, podsieci, portów, pul itp.

W rzeczywistości Neutron przyjmuje zapytania API o tworzenie jakichkolwiek bytów sieciowych, autoryzuje zapytanie, a następnie przez RPC (jeśli odnosi się do jakiejś wtyczki lub agenta) lub REST API (jeśli komunikuje się w SDN) przekazuje agentom (przez wtyczki) instrukcje niezbędne do zorganizowania żądanej usługi.

Teraz zwróćmy się do instalacji testowej (jak została wdrożona i co w niej zawiera, przyjrzymy się później w części praktycznej) i zobaczmy, gdzie znajduje się każdy komponent:

(overcloud) [stack@undercloud ~]$ openstack network agent list  
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| ID                                   | Typ agenta         | Host                                | Strefa dostępności | Żywy | Stan  | Binarny                  |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| 10495de9-ba4b-41fe-b30a-b90ec3f8728b | agent Open vSwitch | overcloud-novacompute-1.localdomain | Brak              | :-)   | Włączony | neutron-openvswitch-agent |
| 1515ad4a-5972-46c3-af5f-e5446dff7ac7 | agent L3           | overcloud-controller-0.localdomain  | nova              | :-)   | Włączony | neutron-l3-agent          |
| 322e62ca-1e5a-479e-9a96-4f26d09abdd7 | agent DHCP         | overcloud-controller-0.localdomain  | nova              | :-)   | Włączony | neutron-dhcp-agent        |
| 9c1de2f9-bac5-400e-998d-4360f04fc533 | agent Open vSwitch | overcloud-novacompute-0.localdomain | Brak              | :-)   | Włączony | neutron-openvswitch-agent |
| d99c5657-851e-4d3c-bef6-f1e3bb1acfb0 | agent Open vSwitch | overcloud-controller-0.localdomain  | Brak              | :-)   | Włączony | neutron-openvswitch-agent |
| ff85fae6-5543-45fb-a301-19c57b62d836 | agent Metadanych   | overcloud-controller-0.localdomain  | Brak              | :-)   | Włączony | neutron-metadata-agent    |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
(overcloud) [stack@undercloud ~]$ 

Wprowadzenie do sieciowej części infrastruktury chmurowej

Oto cała struktura Neutron. Teraz warto poświęcić chwilę na wtyczkę ML2.

Modular Layer 2

Jak już wspomniano, wtyczka jest standardową, główną wtyczką OpenStack i ma modułową architekturę.

Poprzednik wtyczki ML2 miał monolityczną strukturę, co uniemożliwiało na przykład użycie mieszanki różnych technologii w jednej instalacji. Na przykład, nie można było używać jednocześnie openvswitch i linuxbridge — musiałeś wybrać jedno z nich. Z tego powodu stworzono wtyczkę ML2 z jej architekturą.

ML2 ma dwie składniki — dwa typy sterowników: Type drivers i Mechanism drivers.

Type drivers określają technologie, które będą używane do organizacji połączeń sieciowych, takie jak VxLAN, VLAN, GRE. W tym przypadku sterownik pozwala na użycie różnych technologii. Standardową technologią jest enkapsulacja VxLAN dla sieci overlay i vlan dla sieci zewnętrznych.

Do Type drivers należą następujące typy sieci:

Flat — sieć bez tagowania
VLAN — sieć tagowana
Local — specjalny typ sieci dla instalacji typu all-in-one (te instalacje są potrzebne albo dla deweloperów, albo do nauki)
GRE — sieć overlay, wykorzystująca tunele GRE
VxLAN — sieć overlay, wykorzystująca tunele VxLAN

Mechanism drivers określają środki, które zapewniają organizację wskazanych w type driver technologii — na przykład openvswitch, sr-iov, opendaylight, OVN itd.

W zależności od implementacji tego sterownika będą wykorzystywane albo agenci zarządzani przez Neutron, albo będą wykorzystywane połączenia z zewnętrznym kontrolerem SDN, który przejmuje wszystkie kwestie związane z organizacją sieci L2, routingu itd.

Na przykład, jeśli używamy ML2 razem z OVS, to na każdej węźle obliczeniowym instalowany jest agent L2, który zarządza OVS. Jednak jeśli używamy na przykład OVN lub OpenDayLight, to zarządzanie OVS przechodzi pod ich jurysdykcję — Neutron za pośrednictwem głównego wtyczki wydaje polecenia kontrolerowi, a ten już robi, co mu powiedziano.

Przypomnijmy sobie Open vSwitch

W tej chwili jednym z kluczowych komponentów OpenStack jest Open vSwitch.
Podczas instalacji OpenStack bez jakiegokolwiek dodatkowego komercyjnego SDN, takiego jak Juniper Contrail lub Nokia Nuage, OVS jest głównym komponentem sieci chmurowej i w połączeniu z iptables, conntrack, namespaces pozwala na organizowanie w pełni funkcjonalnych sieci owerlejowych z multitenancy. Oczywiście ten komponent może być zastąpiony, na przykład przy użyciu zewnętrznych rozwiązań SDN.

OVS to programowy przełącznik z otwartym kodem źródłowym, który jest przeznaczony do użycia w środowiskach wirtualizacyjnych jako wirtualny forwarder ruchu.

W tej chwili OVS ma bardzo przyzwoitą funkcjonalność, która obejmuje takie technologie jak QoS, LACP, VLAN, VxLAN, GENEVE, OpenFlow, DPDK itd.

Uwaga: pierwotnie OVS nie był myślany jako programowy przełącznik dla funkcji telekomunikacyjnych o dużym obciążeniu i był bardziej dostosowany do mniej wymagających funkcji IT, takich jak serwery WEB czy serwery pocztowe. Jednak OVS jest rozwijany, a aktualne realizacje OVS znacznie poprawiły jego wydajność i możliwości, co pozwala na jego wykorzystanie przez operatorów telekomunikacyjnych z funkcjami o wysokim obciążeniu, na przykład istnieje realizacja OVS z wsparciem dla akceleracji DPDK.

Istnieją trzy ważne komponenty OVS, o których należy wiedzieć:

  • Moduł jądra — komponent, który jest zlokalizowany w przestrzeni jądra i wykonuje przetwarzanie ruchu na podstawie otrzymanych od kontrolera reguł;
  • vSwitch Demon (ovs-vswitchd) to proces uruchomiony w przestrzeni użytkownika, który odpowiada za programowanie modułu jądra — czyli bezpośrednio reprezentuje logikę działania przełącznika.
  • Serwer bazy danych — lokalna baza danych umieszczona na każdym hoście, na którym działa OVS, w której przechowywana jest konfiguracja. Dzięki temu modułowi kontrolery SDN mogą komunikować się przez protokół OVSDB.

Do tego wszystkiego dołączony jest zestaw narzędzi diagnostycznych i zarządzających, takich jak ovs-vsctl, ovs-appctl, ovs-ofctl itd.

Obecnie Openstack jest szeroko stosowany przez operatorów telekomunikacyjnych do migracji funkcji sieciowych, takich jak EPC, SBC, HLR itd. Część funkcji może bez problemu działać z OVS w jego obecnej formie, ale na przykład EPC przetwarza ruch abonentów — to znaczy przepuszcza przez siebie ogromne ilości ruchu (aktualnie objętości ruchu osiągają kilka setek gigabitów na sekundę). Oczywiście przesyłanie takiego ruchu przez przestrzeń jądra (ponieważ domyślnie przekazywanie odbywa się tam) — to nie najlepszy pomysł. Dlatego często OVS uruchamiany jest całkowicie w przestrzeni użytkownika z wykorzystaniem technologii przyspieszenia DPDK do przekazywania ruchu z NIC do przestrzeni użytkownika, omijając jądro.

Uwaga: dla chmury uruchomionej dla funkcji telekomunikacyjnych możliwe jest opcjonalne wyjście ruchu z węzła obliczeniowego, omijając OVS, bezpośrednio do sprzętu przełączającego. W tym celu stosowane są mechanizmy SR-IOV i Passthrough.

Jak to działa na rzeczywistym makiecie?

A teraz przejdźmy do części praktycznej i zobaczmy, jak to wszystko działa w praktyce.

Na początek uruchomimy prostą instalację Openstack. Ponieważ nie mam pod ręką zestawu serwerów do eksperymentów, stworzymy makietę na jednym fizycznym serwerze z maszyn wirtualnych. Tak, oczywiście pod cele komercyjne takie rozwiązanie się nie nadaje, ale aby na przykładzie zobaczyć, jak działa sieć w Openstack, taka instalacja w zupełności wystarczy. Co więcej, taka instalacja do celów szkoleniowych jest nawet ciekawsza — ponieważ można przechwytywać ruch itd.

Ponieważ musimy zobaczyć tylko podstawową część, nie musimy używać kilku sieci, a wszystko możemy uruchomić z użyciem tylko dwóch sieci, przy czym druga sieć w tym makiecie będzie używana wyłącznie do dostępu do undercloud i serwera DNS. Na razie nie będziemy dotykać sieci zewnętrznych — to temat na osobny, obszerny artykuł.

Zaczniemy od podstaw. Na początku trochę teorii. Zainstalujemy OpenStack za pomocą TripleO (OpenStack na OpenStack). Istota TripleO polega na tym, że instalujemy OpenStack all-in-one (czyli na jednej nodzie), nazywanej undercloud, a następnie wykorzystujemy możliwości uruchomionego OpenStacka do zainstalowania produkcyjnego OpenStacka, znanego jako overcloud. Undercloud będzie korzystać z wbudowanej funkcji zarządzania fizycznymi serwerami (bare metal) — projektu Ironic — do provisionowania hyperwizorów, które będą pełniły rolę nodów compute, control i storage. To znaczy, że nie używamy żadnych zewnętrznych narzędzi do uruchamiania OpenStacka — uruchamiamy OpenStack siłami OpenStacka. W trakcie instalacji stanie się to znacznie jaśniejsze, więc nie zatrzymujmy się na tym i idźmy dalej.

Uwaga: W tym artykule dla uproszczenia nie zastosowałem izolacji sieci dla wewnętrznych sieci OpenStack, a wszystko zostało zainstalowane przy użyciu tylko jednej sieci. Niemniej jednak obecność lub brak izolacji sieci nie wpływa na podstawową funkcjonalność rozwiązania — wszystko będzie działać dokładnie tak samo, jak przy użyciu izolacji, ale ruch będzie odbywał się w jednej sieci. W przypadku komercyjnej instalacji oczywiście trzeba używać izolacji z wykorzystaniem różnych VLAN-ów i interfejsów. Na przykład, ruch zarządzający magazynem Ceph i ruch dotyczący danych (zapytania maszyn do dysków itd.) przy izolacji korzystają z różnych podsieci (Storage management i Storage), co pozwala na zwiększenie odporności rozwiązania, oddzielając ten ruch na przykład po różnych portach, lub używając różnych profili QoS dla różnego ruchu, aby ruch danych nie zakłócał ruchu sygnalizacyjnego. W naszym przypadku będą one przebiegać w tej samej sieci i w rzeczywistości w żaden sposób nas to nie ogranicza.

Uwaga: Ponieważ zamierzamy uruchamiać maszyny wirtualne w wirtualnym środowisku opartym na maszynach wirtualnych, na początku musimy włączyć zagnieżdżoną wirtualizację.

Można sprawdzić, czy zagnieżdżona wirtualizacja jest włączona, w następujący sposób:


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

Jeśli widzisz literę N, włączamy wsparcie dla zagnieżdżonej wirtualizacji według jakiegokolwiek przewodnika, który znajdziesz w sieci, na przykład taki .

Musimy zbudować taką strukturę z maszyn wirtualnych:

Wprowadzenie do sieciowej części infrastruktury chmurowej

W moim przypadku, dla połączenia maszyn wirtualnych wchodzących w skład przyszłej instalacji (mam ich 7, ale można się obejść z 4, jeśli nie masz dużo zasobów), użyłem OpenvSwitch. Stworzyłem jeden most ovs i podłączyłem do niego maszyny wirtualne przez port-groups. W tym celu stworzyłem plik xml w następującym formacie:


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

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

Tutaj zdefiniowane są trzy grupy portów — dwa dostępy i jeden trunk (ostatni był potrzebny do serwera DNS, ale można się obejść bez niego, lub uruchomić go na maszynie hosta — jak wolisz). Następnie za pomocą tego szablonu definiujemy naszą sieć przez virsh net-define:


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

Teraz edytujemy konfiguracje portów hyperwizora:


[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 ~]# 

Uwaga: w tym scenariuszu adres na porcie ovs-br1 nie będzie dostępny, ponieważ nie ma tagu VLAN. Aby to naprawić, należy wydać polecenie sudo ovs-vsctl set port ovs-br1 tag=100. Jednak po restarcie ten tag zniknie (jeśli ktoś wie, jak go zatrzymać — będę bardzo wdzięczny). Nie jest to jednak tak istotne, ponieważ ten adres będzie nam potrzebny tylko w czasie instalacji i nie będzie potrzebny, gdy OpenStack będzie w pełni wdrożony.

Następnie tworzymy maszynę undercloud:


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

Podczas instalacji ustaw wszystkie potrzebne parametry, takie jak nazwa maszyny, hasła, użytkownicy, serwery ntp itd. Możesz od razu skonfigurować porty, ale osobiście łatwiej mi jest po instalacji wejść do maszyny przez konsolę i poprawić potrzebne pliki. Jeśli masz już gotowy obraz, możesz go użyć lub postąpić jak ja — pobrać minimalny obraz CentOS 7 i użyć go do instalacji VM.

Po udanej instalacji powinna pojawić się maszyna wirtualna, na której można zainstalować undercloud.


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

Najpierw instalujemy niezbędne narzędzia do procesu instalacji:

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

Instalacja Undercloud

Tworzymy użytkownika stack, ustawiamy hasło, dodajemy do sudoer i dajemy mu możliwość wykonywania poleceń root przez sudo bez potrzeby wprowadzania hasła:


useradd stack
passwd stack

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

Teraz wskazujemy w pliku hosts pełną nazwę undercloud:


vi /etc/hosts

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

Następnie dodajemy repozytoria i instalujemy potrzebne oprogramowanie:


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

Uwaga: jeśli nie planujesz instalować ceph, nie wprowadzaj poleceń dotyczących ceph. Użyłem wydania Queens, ale możesz użyć dowolnego innego, które ci się podoba.

Następnie kopiujemy plik konfiguracyjny undercloud do domowego katalogu użytkownika stack:


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

Teraz musimy poprawić ten plik, dostosowując go do naszej instalacji.

Na początku pliku należy dodać te linie:

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

Przejdźmy do ustawień:

undercloud_hostname — pełna nazwa serwera undercloud, musi zgadzać się z zapisem na serwerze DNS

local_ip — lokalny adres undercloud w kierunku sieci provisioning

network_gateway — ten sam lokalny adres, który będzie pełnił rolę bramy (gateway) do dostępu do świata zewnętrznego podczas instalacji nodów overcloud, również pokrywa się z local ip

undercloud_public_host — adres zewnętrznego API, przypisywany dowolny wolny adres z sieci provisioning

undercloud_admin_host adres wewnętrznego API, przypisywany dowolny wolny adres z sieci provisioning

undercloud_nameservers — serwer DNS

generate_service_certificate — ten wpis jest bardzo istotny w obecnym przykładzie, ponieważ jeśli nie ustawisz na false, otrzymasz błąd podczas instalacji, problem opisany jest w bugtrackerze Red Hat

local_interface interfejs w sieci provisioning. Ten interfejs zostanie prze-konfigurowany podczas uruchamiania undercloud, dlatego undercloud musi mieć dwa interfejsy — jeden do dostępu do niego, drugi do provisioning

local_mtu — MTU. Ponieważ mamy laboratorium testowe i MTU wynosi 1500 na portach przełącznika OVS, należy ustawić na 1450, aby przechodziły kapsułkowane w pakiety VxLAN

network_cidr — sieć provisioning

masquerade — użycie NAT do dostępu do sieci zewnętrznej

masquerade_network — sieć, która będzie NAT-owana

dhcp_start — początkowy adres puli adresów, z której będą przydzielane adresy nodom podczas wdrażania overcloud

dhcp_end — końcowy adres puli adresów, z której będą przydzielane adresy nodom podczas wdrażania overcloud

inspection_iprange — pula adresów potrzebnych do przeprowadzenia introspekcji (nie może pokrywać się z wyżej wymienioną pulą)

scheduler_max_attempts — maksymalna liczba prób instalacji overcloud (powinna wynosić co najmniej tyle, ile jest nodów)

Po tym, jak plik został opisany, można wydać polecenie na wdrożenie undercloud:


openstack undercloud install

Procedura zajmuje od 10 do 30 minut w zależności od twojego sprzętu. Ostatecznie powinieneś zobaczyć taki wynik:

vi undercloud.conf
2020-08-13 23:13:12,668 INFO: 
#############################################################################
Instalacja undercloud ukończona.

Plik zawierający hasła tej instalacji znajduje się w
/home/stack/undercloud-passwords.conf.

Jest również plik stackrc w /home/stack/stackrc.

Te pliki są potrzebne do interakcji z usługami OpenStack i powinny być
zabezpieczone.

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

Ten wynik mówi, że pomyślnie zainstalowałeś undercloud i teraz możesz sprawdzić stan undercloud oraz przejść do instalacji overcloud.

Jeśli spojrzysz na wynik ifconfig, zobaczysz, że pojawił się nowy interfejs mostkowy

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

Przez ten interfejs będzie teraz odbywać się wdrożenie overcloud.

Z poniższego wyjścia widać, że wszystkie usługi są na jednym węźle:

(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     |
+--------------------------+-----------+----------+

Poniżej przedstawiona jest konfiguracja sieciowa 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 ~]$

Instalacja overcloud

Na ten moment mamy tylko undercloud i brakuje nam węzłów, z których zbudujemy overcloud. Dlatego najpierw wdrożymy potrzebne nam maszyny wirtualne. Podczas wdrożenia undercloud sam zainstaluje system operacyjny i potrzebne oprogramowanie na maszynach overcloud — to znaczy, że nie musimy całkowicie wdrażać maszyny, a tylko stworzyć dla niej dysk (lub dyski) i określić jej parametry — tak więc w rzeczywistości otrzymujemy nagi serwer bez zainstalowanego systemu operacyjnego.

Przechodzimy do folderu z dyskami naszych maszyn wirtualnych i tworzymy dyski o odpowiedniej wielkości:


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

Ponieważ działamy jako root, musimy zmienić właściciela tych dysków, aby uniknąć problemów z prawami:


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

Uwaga: jeśli nie planujesz instalować ceph w celach edukacyjnych, nie twórz co najmniej 3 węzłów z co najmniej dwoma dyskami, a w szablonie wskaż, że będą używane wirtualne dyski vda, vdb itd.

Świetnie, teraz musimy zdefiniować wszystkie te maszyny:


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 

Na końcu znajdują się polecenia —print-xml > /tmp/storage-1.xml, które tworzy plik xml z opisem każdej maszyny w folderze /tmp/, jeśli go nie dodasz, nie będziesz mógł zdefiniować maszyn wirtualnych.

Teraz musimy zdefiniować wszystkie te maszyny w virsh:


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

[root@hp-gen9 ~]# virsh list --all
 Id    Name                           State
----------------------------------------------------
 6     dns-server                     running
 64    undercloud                     running
 -     compute-1                      wyłączony
 -     compute-2                      wyłączony
 -     control-1                      wyłączony
 -     storage-1                      wyłączony
 -     storage-2                      wyłączony

[root@hp-gen9 ~]#

Teraz mały niuans – tripleO używa IPMI do zarządzania serwerami podczas instalacji i introspekcji.

Introspekcja to proces inspekcji sprzętu w celu uzyskania parametrów potrzebnych do dalszego provizionowania węzłów. Introspekcja odbywa się przy pomocy ironic – usługi przeznaczonej do pracy z bare metal serwerami.

Ale jest tu problem – jeśli w serwerach fizycznych IPMI to osobny port (lub port współdzielony, ale to nie jest kluczowe), to w maszynach wirtualnych takich portów nie ma. Tu z pomocą przychodzi obejście o nazwie vbmc – narzędzie, które emuluje port IPMI. Na ten niuans warto zwrócić uwagę szczególnie tym, którzy chcieliby stworzyć takie laboratorium na hipernadzorze ESXI – szczerze mówiąc, nie wiem, czy w nim istnieje analog vbmc, więc warto zająć się tym pytaniem przed rozbudowaniem wszystkiego.

Instalujemy vbmc:


yum install python2-virtualbmc

Jeśli twój system operacyjny nie może znaleźć pakietu, dodaj repozytorium:

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

Teraz konfigurujemy narzędzie. Tutaj wszystko jest banalne do bólu. Teraz logiczne jest, że na liście vbmc nie ma żadnych serwerów


[root@hp-gen9 ~]# vbmc list

[root@hp-gen9 ~]# 

Aby się pojawiły, należy je ręcznie zadeklarować w ten sposób:


[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
+-------------+--------+---------+------+
| Nazwa domeny| Status | Adres   | Port |
+-------------+--------+---------+------+
| compute-1   | wyłączony | ::      | 7004 |
| compute-2   | wyłączony | ::      | 7005 |
| control-1   | wyłączony | ::      | 7001 |
| storage-1   | wyłączony | ::      | 7002 |
| storage-2   | wyłączony | ::      | 7003 |
+-------------+--------+---------+------+
[root@hp-gen9 ~]#

Myślę, że składnia polecenia jest zrozumiała bez wyjaśnień. Jednak dopóki wszystkie nasze sesje są w stanie DOWN, aby przeszły do statusu UP, należy je włączyć:


[root@hp-gen9 ~]# vbmc start control-1
2020-08-14 03:15:57,826.826 13149 INFO VirtualBMC [-] Uruchomiono instancję vBMC dla domeny control-1
[root@hp-gen9 ~]# vbmc start storage-1 
2020-08-14 03:15:58,316.316 13149 INFO VirtualBMC [-] Uruchomiono instancję vBMC dla domeny storage-1
[root@hp-gen9 ~]# vbmc start storage-2
2020-08-14 03:15:58,851.851 13149 INFO VirtualBMC [-] Uruchomiono instancję vBMC dla domeny storage-2
[root@hp-gen9 ~]# vbmc start compute-1
2020-08-14 03:15:59,307.307 13149 INFO VirtualBMC [-] Uruchomiono instancję vBMC dla domeny compute-1
[root@hp-gen9 ~]# vbmc start compute-2
2020-08-14 03:15:59,712.712 13149 INFO VirtualBMC [-] Uruchomiono instancję vBMC dla domeny compute-2
[root@hp-gen9 ~]# 
[root@hp-gen9 ~]# 
[root@hp-gen9 ~]# vbmc list
+-------------+---------+---------+------+
| Nazwa domeny | Status  | Adres   | Port |
+-------------+---------+---------+------+
| compute-1   | działający | ::      | 7004 |
| compute-2   | działający | ::      | 7005 |
| control-1   | działający | ::      | 7001 |
| storage-1   | działający | ::      | 7002 |
| storage-2   | działający | ::      | 7003 |
+-------------+---------+---------+------+
[root@hp-gen9 ~]#

Ostatni krok — konieczne jest dostosowanie reguł zapory (lub całkowite jej wyłączenie):


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

Teraz przejdziemy do undercloud i sprawdzimy, czy wszystko działa. Adres maszyny gospodarza to 192.168.255.200; na undercloud dodaliśmy potrzebny pakiet ipmitool podczas przygotowań do wdrożenia:


[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power status          
Zasilanie obudowy jest wyłączone
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power on
Kontrola zasilania obudowy: Włącz/On
[stack@undercloud ~]$ 

[root@hp-gen9 ~]# virsh list 
 Id    Nazwa                           Stan
----------------------------------------------------
 6     dns-server                     działający
 64    undercloud                     działający
 65    control-1                      działający

Jak widać, pomyślnie uruchomiliśmy węzeł control za pomocą vbmc. Teraz go wyłączymy i przejdziemy dalej:


[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power off
Kontrola zasilania obudowy: Wyłącz/Off
[stack@undercloud ~]$ ipmitool -I lanplus -U admin -P admin -H 192.168.255.200 -p 7001 power status
Zasilanie obudowy jest wyłączone
[stack@undercloud ~]$ 

[root@hp-gen9 ~]# virsh list --all
 Id    Nazwa                           Stan
----------------------------------------------------
 6     dns-server                     działający
 64    undercloud                     działający
 -     compute-1                      wyłączony
 -     compute-2                      wyłączony
 -     control-1                      wyłączony
 -     storage-1                      wyłączony
 -     storage-2                      wyłączony

[root@hp-gen9 ~]#

Kolejny krok to introspekcja węzłów, na których będzie instalowany overcloud. W tym celu musimy przygotować plik JSON z opisem naszych węzłów. Zauważ, że w przeciwieństwie do instalacji na surowych serwerach w pliku wskazany jest port, na którym uruchomiony jest vbmc dla każdej z maszyn.


[root@hp-gen9 ~]# virsh domiflist --domain control-1 
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
-          sieć      ovs-network-1 virtio      52:54:00:20:a2:2f
-          sieć      ovs-network-1 virtio      52:54:00:3f:87:9f

[root@hp-gen9 ~]# virsh domiflist --domain compute-1
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
-          sieć      ovs-network-1 virtio      52:54:00:98:e9:d6

[root@hp-gen9 ~]# virsh domiflist --domain compute-2
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
-          sieć      ovs-network-1 virtio      52:54:00:6a:ea:be

[root@hp-gen9 ~]# virsh domiflist --domain storage-1
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
-          sieć      ovs-network-1 virtio      52:54:00:79:0b:cb

[root@hp-gen9 ~]# virsh domiflist --domain storage-2
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
-          sieć      ovs-network-1 virtio      52:54:00:a7:fe:27

Uwaga: na nodzie kontrolnej są dwa interfejsy, ale w tym przypadku to nie ma znaczenia, w tej instalacji wystarczy jeden.

Teraz przygotowujemy plik JSON. Musimy wskazać adres MAC portu, przez który będzie odbywało się provisionowanie, parametry nodów, nadać im nazwy i wskazać, jak dostać się do 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"
        }
    ]
}

Teraz musimy przygotować obrazy dla Ironic. Aby to zrobić, pobieramy je przez wget i instalujemy:

(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 ~]$

Ładujemy obrazy do undercloud:

(undercloud) [stack@undercloud ~]$ openstack overcloud image upload --image-path ~/images/
Obraz "overcloud-full-vmlinuz" został przesłany.
+--------------------------------------+------------------------+-------------+---------+--------+
|                  ID                  |          Nazwa         | Format Dysku |   Rozmiar | Status |
+--------------------------------------+------------------------+-------------+---------+--------+
| c2553770-3e0f-4750-b46b-138855b5c385 | overcloud-full-vmlinuz |     aki     | 6761064 | aktywny |
+--------------------------------------+------------------------+-------------+---------+--------+
Obraz "overcloud-full-initrd" został przesłany.
+--------------------------------------+-----------------------+-------------+----------+--------+
|                  ID                  |          Nazwa         | Format Dysku |   Rozmiar   | Status |
+--------------------------------------+-----------------------+-------------+----------+--------+
| 949984e0-4932-4e71-af43-d67a38c3dc89 | overcloud-full-initrd |     ari     | 55183045 | aktywny |
+--------------------------------------+-----------------------+-------------+----------+--------+
Obraz "overcloud-full" został przesłany.
+--------------------------------------+----------------+-------------+------------+--------+
|                  ID                  |      Nazwa      | Format Dysku |    Rozmiar    | Status |
+--------------------------------------+----------------+-------------+------------+--------+
| a2f2096d-c9d7-429a-b866-c7543c02a380 | overcloud-full |    qcow2    | 1487475712 | aktywny |
+--------------------------------------+----------------+-------------+------------+--------+
Obraz "bm-deploy-kernel" został przesłany.
+--------------------------------------+------------------+-------------+---------+--------+
|                  ID                  |       Nazwa       | Format Dysku |   Rozmiar  | Status |
+--------------------------------------+------------------+-------------+---------+--------+
| e413aa78-e38f-404c-bbaf-93e582a8e67f | bm-deploy-kernel |     aki     | 6761064 | aktywny |
+--------------------------------------+------------------+-------------+---------+--------+
Obraz "bm-deploy-ramdisk" został przesłany.
+--------------------------------------+-------------------+-------------+-----------+--------+
|                  ID                  |        Nazwa       | Format Dysku |    Rozmiar   | Status |
+--------------------------------------+-------------------+-------------+-----------+--------+
| 5cf3aba4-0e50-45d3-929f-27f025dd6ce3 | bm-deploy-ramdisk |     ari     | 461759376 | aktywny |
+--------------------------------------+-------------------+-------------+-----------+--------+
(undercloud) [stack@undercloud ~]$

Sprawdzamy, czy wszystkie obrazy zostały wysłane


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

Jeszcze jeden krok — dodajemy serwer DNS:


(undercloud) [stack@undercloud ~]$ openstack subnet list
+--------------------------------------+-----------------+--------------------------------------+------------------+
| ID                                   | Nazwa           | Sieć                                | Subnet           |
+--------------------------------------+-----------------+--------------------------------------+------------------+
| 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
+-------------------+-----------------------------------------------------------+
| Pole              | Wartość                                                  |
+-------------------+-----------------------------------------------------------+
| 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       | Prawda                                                   |
| 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 | Brak                                                     |
| ipv6_ra_mode      | Brak                                                     |
| name              | ctlplane-subnet                                           |
| network_id        | 6ca013dc-41c2-42d8-9d69-542afad53392                      |
| prefix_length     | Brak                                                     |
| project_id        | a844ccfcdb2745b198dde3e1b28c40a3                          |
| revision_number   | 0                                                         |
| segment_id        | Brak                                                     |
| service_types     |                                                           |
| subnetpool_id     | Brak                                                     |
| 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 jest przestarzałe i zostanie usunięte w przyszłości. Użyj zamiast tego CLI openstack.
Zaktualizowany subnet: f45dea46-4066-42aa-a3c4-6f84b8120cab
(undercloud) [stack@undercloud ~]$

Teraz możemy wydać polecenie inspekcji:

(undercloud) [stack@undercloud ~]$ openstack overcloud node import --introspect --provide inspection.json 
Rozpoczęto workflow Mistral tripleo.baremetal.v1.register_or_update. ID wykonania: d57456a3-d8ed-479c-9a90-dff7c752d0ec
Czekam na wiadomości w kolejce 'tripleo' bez limitu czasowego.


5 węzłów zostało pomyślnie przeniesionych do stanu "zarządzalnego".
Pomyślnie zarejestrowano UUID węzła b4b2cf4a-b7ca-4095-af13-cc83be21c4f5
Pomyślnie zarejestrowano UUID węzła b89a72a3-6bb7-429a-93bc-48393d225838
Pomyślnie zarejestrowano UUID węzła 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e
Pomyślnie zarejestrowano UUID węzła bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8
Pomyślnie zarejestrowano UUID węzła 766ab623-464c-423d-a529-d9afb69d1167
Czekam na zakończenie introspekcji...
Rozpoczęto workflow Mistral tripleo.baremetal.v1.introspect. ID wykonania: 6b4d08ae-94c3-4a10-ab63-7634ec198a79
Czekam na wiadomości w kolejce 'tripleo' bez limitu czasowego.
Introspekcja węzła b89a72a3-6bb7-429a-93bc-48393d225838 zakończona. Status: SUKCES. Błędy: Brak
Introspekcja węzła 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e zakończona. Status: SUKCES. Błędy: Brak
Introspekcja węzła bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 zakończona. Status: SUKCES. Błędy: Brak
Introspekcja węzła 766ab623-464c-423d-a529-d9afb69d1167 zakończona. Status: SUKCES. Błędy: Brak
Introspekcja węzła b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 zakończona. Status: SUKCES. Błędy: Brak
Pomyślnie introspekcyjnie przetworzono 5 węzłów.
Rozpoczęto workflow Mistral tripleo.baremetal.v1.provide. ID wykonania: f5594736-edcf-4927-a8a0-2a7bf806a59a
Czekam na wiadomości w kolejce 'tripleo' bez limitu czasowego.
5 węzłów zostało pomyślnie przeniesionych do stanu "dostępnego".
(undercloud) [stack@undercloud ~]$

Jak widać z wyjścia, wszystko zakończyło się bez błędów. Sprawdźmy, czy wszystkie węzły są w stanie dostępny:


(undercloud) [stack@undercloud ~]$ openstack baremetal node list
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
| UUID                                 | Nazwa     | UUID instancji | Stan zasilania | Stan provisioningowy | Utrzymanie |
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | kontrola-1 | Brak          | wyłączony    | dostępny          | Fałsz       |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | Brak          | wyłączony    | dostępny          | Fałsz       |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | Brak          | wyłączony    | dostępny          | Fałsz       |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | Brak          | wyłączony    | dostępny          | Fałsz       |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | Brak          | wyłączony    | dostępny          | Fałsz       |
+--------------------------------------+-----------+---------------+-------------+--------------------+-------------+
(undercloud) [stack@undercloud ~]$ 

Jeśli węzły będą w innym stanie, zazwyczaj zarządzalnym, to coś poszło nie tak i należy sprawdzić logi, aby dowiedzieć się, dlaczego tak się stało. Pamiętaj, że w tym scenariuszu używamy wirtualizacji i mogą wystąpić błędy związane z używaniem maszyn wirtualnych lub vbmc.

Następnie musimy wskazać, który węzeł jaką funkcję będzie pełnił — czyli określić profil, według którego węzeł będzie wdrażany:


(undercloud) [stack@undercloud ~]$ openstack overcloud profiles list
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| UUID węzła                           | Nazwa węzła | Stan przydziału | Bieżący profil  | Możliwe profile    |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
| b4b2cf4a-b7ca-4095-af13-cc83be21c4f5 | control-1 | dostępny       | Brak            |                   |
| b89a72a3-6bb7-429a-93bc-48393d225838 | storage-1 | dostępny       | Brak            |                   |
| 20a16cc0-e0ce-4d88-8f17-eb0ce7b4d69e | storage-2 | dostępny       | Brak            |                   |
| bfc1eb98-a17a-4a70-b0b6-6c0db0eac8e8 | compute-1 | dostępny       | Brak            |                   |
| 766ab623-464c-423d-a529-d9afb69d1167 | compute-2 | dostępny       | Brak            |                   |
+--------------------------------------+-----------+-----------------+-----------------+-------------------+
(undercloud) [stack@undercloud ~]$ openstack flavor list
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
| ID                                   | Nazwa         |  RAM | Dysk | Ephemeral | VCPUs | Jest publiczny |
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
| 168af640-7f40-42c7-91b2-989abc5c5d8f | swift-storage | 4096 |   40 |         0 |     1 | Tak        |
| 52148d1b-492e-48b4-b5fc-772849dd1b78 | baremetal     | 4096 |   40 |         0 |     1 | Tak        |
| 56e66542-ae60-416d-863e-0cb192d01b09 | control       | 4096 |   40 |         0 |     1 | Tak        |
| af6796e1-d0c4-4bfe-898c-532be194f7ac | block-storage | 4096 |   40 |         0 |     1 | Tak        |
| e4d50fdd-0034-446b-b72c-9da19b16c2df | compute       | 4096 |   40 |         0 |     1 | Tak        |
| fc2e3acf-7fca-4901-9eee-4a4d6ef0265d | ceph-storage  | 4096 |   40 |         0 |     1 | Tak        |
+--------------------------------------+---------------+------+------+-----------+-------+-----------+
(undercloud) [stack@undercloud ~]$

Określamy profil dla każdego węzła:


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

Sprawdzamy, czy wszystko zrobiliśmy poprawnie:


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

Jeśli wszystko jest poprawnie, wydajemy polecenie do wdrożenia overcloud:

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

W rzeczywistej instalacji używane będą dostosowane szablony, co w naszym przypadku znacznie skomplikuje proces, ponieważ będziemy musieli wyjaśnić każdą poprawkę w szablonie. Jak już wcześniej napisano — nawet prosta instalacja wystarczy, aby zobaczyć, jak to działa.

Uwaga: zmienna —libvirt-type qemu jest w tym przypadku niezbędna, ponieważ będziemy używać zagnieżdżonej wirtualizacji. W przeciwnym razie nie będzie można uruchomić maszyn wirtualnych.

Teraz masz około godziny, a może nawet więcej (w zależności od możliwości sprzętowych) i pozostaje ci mieć nadzieję, że po upływie tego czasu zobaczysz taki komunikat:


2020-08-14 08:39:21Z [overcloud]: CREATE_COMPLETE  Stworzenie stosu ukończone pomyślnie

 Stos overcloud CREATE_COMPLETE 

Host 192.168.255.21 nie znaleziony w /home/stack/.ssh/known_hosts
Rozpoczęto proces roboczy Mistral tripleo.deployment.v1.get_horizon_url. ID wykonania: fcb996cd-6a19-482b-b755-2ca0c08069a9
Endpoint Overcloud: http://192.168.255.21:5000/
URL panelu sterowania Overcloud: http://192.168.255.21:80/dashboard
Plik rc Overcloud: /home/stack/overcloudrc
Overcloud wdrożony
(undercloud) [stack@undercloud ~]$

Teraz masz prawie pełną wersję OpenStack, na której możesz uczyć się, eksperymentować itd.

Sprawdźmy, czy wszystko działa poprawnie. W katalogu domowym użytkownika stack znajdują się dwa pliki — jeden stackrc (do zarządzania undercloud) i drugi overcloudrc (do zarządzania overcloud). Pliki te należy wskazać jako source, ponieważ zawierają niezbędne informacje do uwierzytelniania.


(undercloud) [stack@undercloud ~]$ openstack server list
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
| ID                                   | Name                    | Status | Networks                | Image          | Flavor       |
+--------------------------------------+-------------------------+--------+-------------------------+----------------+--------------+
| fd7d36f4-ce87-4b9a-93b0-add2957792de | overcloud-controller-0  | ACTIVE | ctlplane=192.168.255.15 | overcloud-full | control      |
| edc77778-8972-475e-a541-ff40eb944197 | overcloud-novacompute-1 | ACTIVE | ctlplane=192.168.255.26 | overcloud-full | compute      |
| 5448ce01-f05f-47ca-950a-ced14892c0d4 | overcloud-cephstorage-1 | ACTIVE | ctlplane=192.168.255.34 | overcloud-full | ceph-storage |
| ce6d862f-4bdf-4ba3-b711-7217915364d7 | overcloud-novacompute-0 | ACTIVE | ctlplane=192.168.255.19 | overcloud-full | compute      |
| e4507bd5-6f96-4b12-9cc0-6924709da59e | overcloud-cephstorage-0 | ACTIVE | 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                               | Name    |
+----------------------------------+---------+
| 4eed7d0f06544625857d51cd77c5bd4c | admin   |
| ee1c68758bde41eaa9912c81dc67dad8 | service |
+----------------------------------+---------+
(overcloud) [stack@undercloud ~]$ 
(overcloud) [stack@undercloud ~]$ 
(overcloud) [stack@undercloud ~]$ openstack network agent list  
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| ID                                   | Agent Type         | Host                                | Availability Zone | Alive | State | Binary                    |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
| 10495de9-ba4b-41fe-b30a-b90ec3f8728b | Open vSwitch agent | overcloud-novacompute-1.localdomain | None              | :-)   | UP    | neutron-openvswitch-agent |
| 1515ad4a-5972-46c3-af5f-e5446dff7ac7 | L3 agent           | overcloud-controller-0.localdomain  | nova              | :-)   | UP    | neutron-l3-agent          |
| 322e62ca-1e5a-479e-9a96-4f26d09abdd7 | DHCP agent         | overcloud-controller-0.localdomain  | nova              | :-)   | UP    | neutron-dhcp-agent        |
| 9c1de2f9-bac5-400e-998d-4360f04fc533 | Open vSwitch agent | overcloud-novacompute-0.localdomain | None              | :-)   | UP    | neutron-openvswitch-agent |
| d99c5657-851e-4d3c-bef6-f1e3bb1acfb0 | Open vSwitch agent | overcloud-controller-0.localdomain  | None              | :-)   | UP    | neutron-openvswitch-agent |
| ff85fae6-5543-45fb-a301-19c57b62d836 | Metadata agent     | overcloud-controller-0.localdomain  | None              | :-)   | UP    | neutron-metadata-agent    |
+--------------------------------------+--------------------+-------------------------------------+-------------------+-------+-------+---------------------------+
(overcloud) [stack@undercloud ~]$

W mojej instalacji potrzebny jest jeszcze jeden, nieduży krok — dodanie trasy na kontrolerze, ponieważ maszyna, z której pracuję, znajduje się w innej sieci. W tym celu zaloguję się na control-1 jako heat-admin i dodam trasę.


(undercloud) [stack@undercloud ~]$ ssh heat-admin@192.168.255.15         
Ostatnie logowanie: Pt 14 Sie 09:47:40 2020 z 192.168.255.1
[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ 
[heat-admin@overcloud-controller-0 ~]$ sudo ip route add 10.169.0.0/16 via 192.168.255.254

A teraz możecie wejść w poziom. Wszystkie informacje — adresy, login i hasło — znajdują się w pliku /home/stack/overcloudrc. Ostateczny schemat wygląda następująco:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Na marginesie, w naszej instalacji adresy maszyn były przydzielane przez DHCP i, jak widać, są przydzielane "losowo". Możecie w szablonie sztywno zdefiniować, jaki adres ma być przypisany której maszynie podczas wdrażania, jeśli tego potrzebujecie.

Jak przebiega ruch między maszynami wirtualnymi?

W tym artykule omówimy trzy warianty przepływu ruchu

  • Dwie maszyny na jednym hypervisorze w jednej sieci L2
  • Dwie maszyny na różnych hypervisorach w jednej sieci L2
  • Dwie maszyny w różnych sieciach (routing między sieciami)

Omówimy przypadki z dostępem do zewnętrznego świata przez sieć zewnętrzną, z wykorzystaniem pływających adresów oraz rozdzielonej routingu w przyszłym czasie, a na razie skupimy się na ruchu wewnętrznym.

Dla weryfikacji stworzymy taki schemat:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Mamy utworzone 4 maszyny wirtualne — 3 w jednej sieci L2 — net-1, a jeszcze 1 w sieci net-2

(overcloud) [stack@undercloud ~]$ nova list --tenant 5e18ce8ec9594e00b155485f19895e6c             
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
| ID                                   | Nazwa | ID najemcy                       | Status | Stan zadania | Stan zasilania | Sieci          |
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
| f53b37b5-2204-46cc-aef0-dba84bf970c0 | vm-1 | 5e18ce8ec9594e00b155485f19895e6c | AKTYWNE | -          | Działająca  | net-1=10.0.1.85 |
| fc8b6722-0231-49b0-b2fa-041115bef34a | vm-2 | 5e18ce8ec9594e00b155485f19895e6c | AKTYWNE | -          | Działająca  | net-1=10.0.1.88 |
| 3cd74455-b9b7-467a-abe3-bd6ff765c83c | vm-3 | 5e18ce8ec9594e00b155485f19895e6c | AKTYWNE | -          | Działająca  | net-1=10.0.1.90 |
| 7e836338-6772-46b0-9950-f7f06dbe91a8 | vm-4 | 5e18ce8ec9594e00b155485f19895e6c | AKTYWNE | -          | Działająca  | net-2=10.0.2.8  |
+--------------------------------------+------+----------------------------------+--------+------------+-------------+-----------------+
(overcloud) [stack@undercloud ~]$ 

Przyjrzymy się, na jakich hypervisorach znajdują się utworzone maszyny:

(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 ~]$
Maszyny vm-1 i vm-3 znajdują się na compute-0, maszyny vm-2 i vm-4 znajdują się na nodzie compute-1.

Został również utworzony wirtualny router, aby umożliwić routowanie między wskazanymi sieciami:

(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 ~]$ 

Router ma dwa wirtualne porty, które pełnią rolę bram dla sieci:

(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 ~]$ 

Ale zanim sprawdzimy, jak działa ruch, przeanalizujmy, co mamy obecnie na węźle kontrolnym (który jednocześnie jest węzłem sieciowym) i na węźle compute. Zaczniemy od węzła 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: (internal)
    phy-br-ex 1/none: (patch: peer=int-br-ex)
  br-int:
    br-int 65534/2: (internal)
    int-br-ex 1/none: (patch: peer=phy-br-ex)
    patch-tun 2/none: (patch: peer=patch-int)
  br-tun:
    br-tun 65534/3: (internal)
    patch-int 1/none: (patch: peer=patch-tun)
    vxlan-c0a8ff0f 3/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.15)
    vxlan-c0a8ff1a 2/4: (vxlan: egress_pkt_mark=0, key=flow, local_ip=192.168.255.19, remote_ip=192.168.255.26)
[heat-admin@overcloud-novacompute-0 ~]$

Obecnie na węźle znajdują się trzy mosty ovs — br-int, br-tun, br-ex. Między nimi, jak widzimy, znajduje się zestaw interfejsów. Aby uprościć odbiór, naniesiemy wszystkie dane interfejsy na schemat i zobaczymy, co z tego wyniknie.

Wprowadzenie do sieciowej części infrastruktury chmurowej

Na adresach, na które uruchomione są tunele VxLAN, widać, że jeden tunel jest uruchomiony na compute-1 (192.168.255.26), a drugi zwraca się do control-1 (192.168.255.15). Jednak najbardziej interesujące jest to, że br-ex nie ma interfejsów fizycznych, a jeśli spojrzymy, jakie przepływy są skonfigurowane, widać, że ten most w danej chwili może tylko zrzucać ruch.


[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 ~]$ 

Jak widać z wyjścia, adres jest podłączony bezpośrednio do fizycznego portu, a nie do wirtualnego mostu interfejsu.


[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 ~]$ 

Zgodnie z pierwszą zasadą, wszystko, co przychodzi z portu phy-br-ex, należy odrzucić.
Generalnie w tym moście nie ma teraz innego źródła ruchu oprócz tego interfejsu (połączenie z br-int), a sądząc po zrzutach, do mostu już docierał ruch BUM.

Oznacza to, że ruch z tego węzła może opuścić tylko przez tunel VxLAN i w żaden inny sposób. Jednak włączenie DVR zmieni sytuację, ale tym zajmiemy się innym razem. Przy użyciu izolacji sieci, na przykład za pomocą VLAN-ów, będziecie mieli nie jeden interfejs L3 w VLAN-ie 0, ale kilka interfejsów. Jednak ruch VxLAN będzie wychodzić z węzła w taki sam sposób, ale jeszcze dodatkowo enkapsulowany w jakiś dedykowany VLAN.

Z węzłem obliczeniowym się uporaliśmy, przechodzimy do węzła kontrolnego.


[heat-admin@overcloud-controller-0 ~]$ sudo ovs-appctl dpif/show
system@ovs-system: hit:930491 missed:825
  br-ex:
    br-ex 65534/1: (internal)
    eth0 1/2: (system)
    phy-br-ex 2/none: (patch: peer=int-br-ex)
  br-int:
    br-int 65534/3: (internal)
    int-br-ex 1/none: (patch: peer=phy-br-ex)
    patch-tun 2/none: (patch: peer=patch-int)
  br-tun:
    br-tun 65534/4: (internal)
    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 ~]$

W rzeczywistości można powiedzieć, że wszystko jest takie samo, jednak adres IP znajduje się już nie na interfejsie fizycznym, a na wirtualnym bridge. Zostało to zrobione, ponieważ ten port jest portem, przez który ruch będzie opuszczał świat zewnętrzny.


[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 ~]$ 

Ten port jest podłączony do bridge'a br-ex i ponieważ nie ma na nim żadnych znaczników VLAN, jest to port trunkowy, na którym dozwolone są wszystkie VLAN-y. Aktualnie ruch wychodzi na zewnątrz bez znacznika, o czym świadczy vlan-id 0 w wyjściu powyżej.

Wprowadzenie do sieciowej części infrastruktury chmurowej

Wszystko inne w tej chwili jest analogiczne do węzła obliczeniowego — te same bridge'e, te same tunele prowadzące do dwóch węzłów obliczeniowych.

W tej artykule nie będziemy się zajmować nodami przechowywania, ale dla zrozumienia należy powiedzieć, że sieciowa część tych nodów jest banalna do bólu. W naszym przypadku jest tylko jeden fizyczny port (eth0) z przypisanym adresem IP i to wszystko. Nie ma tam żadnych tuneli VxLAN, mostów tunelowych itd. — nie ma w ogóle OVS, ponieważ nie ma to sensu. Przy użyciu izolacji sieci na tej nodzie będą dwa interfejsy (fizyczne porty, bodny, lub po prostu dwa VLANy — to nie jest ważne — zależy od tego, co chcesz) — jeden do zarządzania, drugi do ruchu (zapisywanie na dysku VM, odczytywanie z dysku itd.).

Dowiedzieliśmy się, co mamy na nodach w braku jakichkolwiek usług. Teraz uruchomić 4 maszyny wirtualne i zobaczmy, jak zmieni się opisany wyżej schemat — powinny pojawić się porty, wirtualne routery itd.

Na razie nasza sieć wygląda tak:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Mamy po dwie maszyny wirtualne na każdej nodze obliczeniowej. Na przykładzie compute-0 zobaczymy, jak wszystko jest podłączone.


[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh list 
 Id    Name                           State
----------------------------------------------------
 1     instance-00000001              running
 3     instance-00000003              running

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

Maszyna ma tylko jeden wirtualny interfejs — 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 ~]$ 

Ten interfejs patrzy w mostek linuxowy:

[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 ~]$ 

Jak widać z outputu, w mostku są tylko dwa interfejsy — tap95d96a75-a0 i qvb95d96a75-a0.

Tu warto się chwilę zatrzymać nad typami wirtualnych urządzeń sieciowych w OpenStack:
vtap — wirtualny interfejs, podłączony do instancji (VM)
qbr — mostek Linuxa
qvb i qvo — para vEth, podłączona do mostka Linuxa i mostka Open vSwitch
br-int, br-tun, br-vlan — mostki Open vSwitch
patch-, int-br-, phy-br- — interfejsy patch Open vSwitch, łączące mostki
qg, qr, ha, fg, sg — porty Open vSwitch, używane przez wirtualne urządzenia do łączenia z OVS

Jak rozumiesz, jeśli w mostku mamy port qvb95d96a75-a0, który jest parą vEth, to gdzieś musi być jego strona odpowiadająca, która logicznie powinna nazywać się qvo95d96a75-a0. Sprawdźmy, jakie porty są na OVS.


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

Jak widzimy, port znajduje się w br-int. Br-int pełni rolę przełącznika, który kończy porty maszyn wirtualnych. Oprócz qvo95d96a75-a0 w wyjściu widać port qvo5bd37136-47. To port w drugiej maszynie wirtualnej. W rezultacie nasza schemat wygląda teraz tak:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Pytanie, które powinno od razu zainteresować uważnego czytelnika — po co linuksowy mostek między portem maszyny wirtualnej a portem OVS? Faktem jest, że dla ochrony maszyny wykorzystywane są grupy zabezpieczeń, które są niczym innym jak iptables. OVS nie działa z iptables, dlatego wymyślono taki "hack". Jednak przestaje to być aktualne — w nowych wydaniach wchodzi conntrack.

Ostatecznie schemat wygląda tak:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Dwie maszyny na jednym hypervisorze w jednej sieci L2

Ponieważ dwie maszyny wirtualne znajdują się w tej samej sieci L2 i na tym samym hiperwizorze, ruch między nimi będzie logicznie przesyłany lokalnie przez br-int, ponieważ obie maszyny będą w tej samej VLAN:


[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000001
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
tap95d96a75-a0 bridge     qbr95d96a75-a0 virtio      fa:16:3e:44:98:20

[heat-admin@overcloud-novacompute-0 ~]$ 
[heat-admin@overcloud-novacompute-0 ~]$ 
[heat-admin@overcloud-novacompute-0 ~]$ sudo virsh domiflist instance-00000003
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
tap5bd37136-47 bridge     qbr5bd37136-47 virtio      fa:16:3e:83:ad:a4

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

Dwie maszyny na różnych hypervisorach w jednej sieci L2

Teraz zobaczmy, jak pójdzie ruch między dwiema maszynami w tej samej sieci L2, ale znajdującymi się na różnych hiperwizorach. Jeśli być szczerym, to nic szczególnie się nie zmieni, po prostu ruch między hiperwizorami przejdzie przez tunel vxlan. Przyjrzyjmy się temu na przykładzie.

Adresy wirtualnych maszyn, między którymi będziemy monitorować ruch:

[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
Interfejs  Typ       Źródło     Model       MAC
-------------------------------------------------------
tape7e23f1b-07 bridge     qbre7e23f1b-07 virtio      fa:16:3e:72:ad:53

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

Sprawdzamy tabelę przekazywania w br-int na 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 ~]$

Ruch powinien przejść na port 2 — sprawdzamy, co to za port:

[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 ~]$

To jest patch-tun — czyli interfejs w br-tun. Sprawdzamy, co się dzieje z pakietami na 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 ~]$ 

Pakiet jest opakowywany w VxLAN i wysyłany na port 2. Sprawdzamy, dokąd prowadzi port 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 ~]$

To jest tunel vxlan na 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 ~]$

Idziemy na compute-1 i sprawdzamy, co się dzieje dalej z pakietem:

[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 ~]$ 

MAC znajduje się w tabeli przekazywania br-int na compute-1, i jak widać z wyjścia wcześniej, widoczny jest przez port 2, który prowadzi do br-tun:

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

A teraz sprawdzamy, co znajduje się w br-int na compute-1:

[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 ~]$ 

Oznacza to, że otrzymany pakiet trafi do portu 3, za którym znajduje się wirtualna maszyna instance-00000003.

Cała uroda wdrożenia OpenStack do nauki na wirtualnej infrastrukturze polega na tym, że możemy bez problemów przechwycić ruch między hypervisorami i zobaczyć, co się z nim dzieje. To właśnie teraz zrobimy, uruchamiając tcpdump na porcie vnet w kierunku compute-0:


[root@hp-gen9 bormoglotx]# tcpdump -vvv -i vnet3
tcpdump: słuchanie na vnet3, typ linku EN10MB (Ethernet), rozmiar przechwytywania 262144 bajtów

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

04:39:04.583459 IP (tos 0x0, ttl 64, id 16868, offset 0, flags [DF], proto UDP (17), długość 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), długość 84)
    10.0.1.85 > 10.0.1.88: ICMP echo request, id 5634, seq 16, długość 64
04:39:04.584449 IP (tos 0x0, ttl 64, id 35181, offset 0, flags [DF], proto UDP (17), długość 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), długość 84)
    10.0.1.88 > 10.0.1.85: ICMP echo reply, id 5634, seq 16, długość 64
	
*****************omitted*******************

Pierwsza linia pokazuje, że pakiet z adresu 10.0.1.85 idzie do adresu 10.0.1.88 (ruch ICMP), a jest on opakowany w pakiet VxLAN z vni 22 i pakiet pochodzi z hosta 192.168.255.19 (compute-0) do hosta 192.168.255.26 (compute-1). Możemy sprawdzić, że VNI odpowiada temu, który jest wskazany w ovs.

Wróćmy do tej linii actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:2. 0x16 — to wni w systemie szesnastkowym. Przekształćmy tę liczbę na system dziesiętny:


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

To znaczy, że wni odpowiada rzeczywistości.

Druga linia pokazuje ruch zwrotny, nie ma potrzeby tego wyjaśniać, tam i tak wszystko jest jasne.

Dwie maszyny w różnych sieciach (rutowanie między sieciami)

Ostatni przypadek na dzisiaj — to rutowanie między sieciami w ramach jednego projektu z wykorzystaniem wirtualnego routera. Rozważamy przypadek bez DVR (ten omówimy w innym artykule), dlatego rutowanie odbywa się na węźle sieciowym. W naszym przypadku węzeł sieciowy nie jest wydzielony jako osobna jednostka i znajduje się na węźle kontrolnym.

Na początek sprawdźmy, czy rutowanie działa:

$ ping 10.0.2.8
PING 10.0.2.8 (10.0.2.8): 56 bajtów danych
64 bajty z 10.0.2.8: seq=0 ttl=63 czas=7.727 ms
64 bajty z 10.0.2.8: seq=1 ttl=63 czas=3.832 ms
^C
--- statystyki ping dla 10.0.2.8 ---
2 pakiety wysłane, 2 pakiety odebrane, 0% utraty pakietów
minimalny/średni/maksymalny czas w obie strony = 3.832/5.779/7.727 ms

Ponieważ w tym przypadku pakiet powinien udać się do bramy i tam zostać zrouterowany, musimy poznać adres MAC bramy, aby to zrobić, sprawdzimy tabelę ARP w instancji:

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

Teraz zobaczmy, gdzie powinien być wysyłany ruch z adresem docelowym (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 ~]$ 

Sprawdzamy, dokąd prowadzi port 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 ~]$ 

Wszystko jest logiczne, ruch kieruje się do br-tun. Zobaczmy, w jaki tunel vxlan zostanie zapakowany:

[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 ~]$ 

Trzeci port to tunel 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 ~]$ 

Który patrzy na węzeł kontrolny:

[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 ~]$ 

Ruch dotarł do węzła kontrolnego, dlatego musimy się na niego przesiąść i zobaczyć, jak będzie odbywać się routowanie.

Jak pamiętacie, węzeł kontrolny wyglądał dokładnie tak samo jak węzeł obliczeniowy — te same trzy mosty, tylko że br-ex miał fizyczny port, przez który węzeł mógł wysyłać ruch na zewnątrz. Tworzenie instancji zmieniło konfigurację na węzłach obliczeniowych — dodano linux bridge, iptables i interfejsy w węzłach. Tworzenie sieci i wirtualnego routera również wpłynęło na konfigurację węzła kontrolnego.

Oczywiście adres MAC bramy powinien być w tabeli przekazywania br-int na węźle kontrolnym. Sprawdźmy, czy tam jest i na co patrzy:

[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 ~]$ 

MAC jest widoczny z portu qr-0c52b15f-8f. Jeśli wrócić do listy wirtualnych portów w Openstack, to ten typ portu jest używany do podłączenia do OVS różnych wirtualnych urządzeń. Dokładniej mówiąc, qr to port skierowany do wirtualnego routera, który jest przedstawiony jako namespace.

Zobaczmy, jakie namespace istnieją na serwerze:

[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 ~]$ 

Trzy instancje. Ale, sądząc po nazwach, można się domyślić ich przeznaczenia. Do instancji z ID 0 i 1 wrócimy później, teraz interesuje nas przestrzeń nazw 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 ~]$ 

W tej przestrzeni nazw znalazły się dwie wewnętrzne, które zostały wcześniej utworzone. Oba wirtualne porty zostały dodane do br-int. Sprawdźmy adres MAC portu qr-0c52b15f-8f, ponieważ ruch, sądząc po adresie MAC docelowym, był kierowany właśnie do tego interfejsu.

[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 ~]$ 

Oznacza to, że w tym przypadku wszystko działa zgodnie z zasadami standardowego routingu. Ponieważ ruch jest przeznaczony dla hosta 10.0.2.8, powinien być wysłany przez drugi interfejs qr-92fa49b5-54 i przejść przez tunel vxlan do węzła compute:


[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 ~]$ 

Wszystko logiczne, żadnych niespodzianek. Sprawdźmy, skąd widoczny jest adres MAC hosta 10.0.2.8 w 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 ~]$ 

Jak przystało, ruch trafia do br-tun, sprawdźmy, do jakiego tunelu nastąpi dalszy przepływ ruchu:

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

Ruch danych przechodzi przez tunel do compute-1. A na compute-1 wszystko jest proste – z br-tun pakiet trafia do br-int, a stamtąd do interfejsu maszyny wirtualnej:

[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 ~]$ 

Sprawdźmy, czy to rzeczywiście poprawny interfejs:

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

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

Właściwie przeszliśmy przez całą drogę pakietu. Myślę, że zauważyliście, że ruch przeszedł przez różne tuneli vxlan i wychodził na różnych VNI. Zobaczmy, jakie to są VNI, a następnie zróbmy zrzut na porcie węzła sterującego i upewnijmy się, że ruch przebiega dokładnie tak, jak opisano wcześniej.
Zatem tunel do compute-0 ma następne actions=load:0->NXM_OF_VLAN_TCI[],load:0x16->NXM_NX_TUN_ID[],output:3. Przekładając 0x16 na system dziesiętny:


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

Tunel do compute-1 ma następujący VNI:actions=load:0->NXM_OF_VLAN_TCI[],load:0x63->NXM_NX_TUN_ID[],output:2. Przekładając 0x63 na system dziesiętny:


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

A teraz zobaczmy zrzut:

[root@hp-gen9 bormoglotx]# tcpdump -vvv -i vnet4 
tcpdump: listening on vnet4, link-type EN10MB (Ethernet), capture size 262144 bytes

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

04:35:18.709949 IP (tos 0x0, ttl 64, id 48650, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.19.41591 > 192.168.255.15.4789: [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: ICMP echo request, id 5378, seq 9, length 64
04:35:18.710159 IP (tos 0x0, ttl 64, id 23360, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.15.38983 > 192.168.255.26.4789: [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: ICMP echo request, id 5378, seq 9, length 64
04:35:18.711292 IP (tos 0x0, ttl 64, id 43596, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.26.42588 > 192.168.255.15.4789: [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: ICMP echo reply, id 5378, seq 9, length 64
04:35:18.711531 IP (tos 0x0, ttl 64, id 8555, offset 0, flags [DF], proto UDP (17), length 134)
    192.168.255.15.38983 > 192.168.255.19.4789: [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: ICMP echo reply, id 5378, seq 9, length 64
	
*****************omitted*******************

Pierwsza paczka to paczka vxlan z hosta 192.168.255.19 (compute-0) do hosta 192.168.255.15 (control-1) z vni 22, w której znajduje się pakiet ICMP z hosta 10.0.1.85 do hosta 10.0.2.8. Jak obliczyliśmy wcześniej, vni odpowiada temu, co widzieliśmy w wynikach.

Druga paczka to paczka vxlan z hosta 192.168.255.15 (control-1) do hosta 192.168.255.26 (compute-1) z vni 99, w której znajduje się pakiet ICMP z hosta 10.0.1.85 do hosta 10.0.2.8. Jak obliczyliśmy wcześniej, vni odpowiada temu, co widzieliśmy w wynikach.

Dwie następne paczki to ruch zwrotny z 10.0.2.8 do 10.0.1.85.

Ostatecznie otrzymaliśmy taką schematykę węzła kontrolnego:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Czyli właściwie wszystko? Zapomnieliśmy o dwóch przestrzeniach nazw:

[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 ~]$ 

Jak mówiliśmy o architekturze platformy chmurowej — dobrze by było, aby maszyny automatycznie otrzymywały adresy od serwera DHCP. To są dwa serwery DHCP dla naszych dwóch sieci 10.0.1.0/24 i 10.0.2.0/24.

Sprawdźmy, czy tak jest. W tej przestrzeni nazw jest tylko jeden adres — 10.0.1.1 — adres samego serwera DHCP, który również jest włączony w br-int:

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

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

Zobaczmy, jakie procesy zawierają w swojej nazwie qdhcp-67a3798c-32c0-4c18-8502-2531247e3cc2 na węźle kontrolnym:


[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 ~]$ 

Istnieje taki proces i na podstawie informacji przedstawionej w powyższym wyjściu możemy na przykład sprawdzić, co obecnie mamy w dzierżawie:

[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 ~]$

W rezultacie otrzymujemy taki zestaw usług na węźle kontrolnym:

Wprowadzenie do sieciowej części infrastruktury chmurowej

Pamiętaj, że to tylko cztery maszyny, dwie sieci wewnętrzne i jeden wirtualny router... Obecnie nie mamy zewnętrznych sieci, ani wielu różnych projektów, z których każdy ma swoje własne (przecinające się) sieci, a nasz rozproszony router jest wyłączony. W końcu w testowym środowisku była tylko jedna węzeł kontrolny (dla zapewnienia ciągłości działania potrzebny jest quorum z trzech węzłów). Logicznym jest, że w handlu wszystko jest "nieco" bardziej skomplikowane, ale na tym prostym przykładzie rozumiemy, jak to powinno działać — bez względu na to, czy masz trzy, czy trzysta przestrzeni nazw, dla działania całej konstrukcji nie powinno się wiele zmienić... o ile nie wprowadzisz jakiegoś vendorowego SDN. Ale to już zupełnie inna historia.

Mam nadzieję, że było interesująco. Jeśli masz uwagi lub uzupełnienia, albo jeśli gdzieś szczerze przesadziłem (jestem człowiekiem i moja opinia zawsze będzie subiektywna) — pisz, co trzeba poprawić lub dodać — wszystko poprawimy/dodamy.

Na zakończenie chciałbym powiedzieć kilka słów na temat porównania OpenStack (zarówno w wersji podstawowej, jak i vendorowej) z rozwiązaniem chmurowym od firmy VMWare — pytano mnie o to pytanie przez ostatnie dwa lata i szczerze mówiąc, już się tym zmęczyłem, ale jednak. Uważam, że porównanie tych dwóch rozwiązań jest bardzo trudne, ale można jednoznacznie stwierdzić, że w obu rozwiązaniach są wady, a wybierając jedno z nich, należy dokładnie rozważyć wszystkie za i przeciw.

Jeśli OpenStack jest rozwiązaniem opartym na społeczności, to VMWare ma prawo robić tylko to, co chce (czytaj — to, co jest dla niej opłacalne) i to jest logiczne — bo to firma komercyjna, która przyzwyczaiła się zarabiać pieniądze na swoich klientach. Ale jest jedno duże i tłuste ALE — możesz zrezygnować z OpenStacka np. od Nokii i z niewielkimi trudnościami przejść na rozwiązanie od Junipera (Contrail Cloud), ale przejście z VMWare raczej ci się nie uda. Dla mnie te dwa rozwiązania wyglądają tak — OpenStack (vendorowy) to prosta klatka, w którą cię zamykają, ale masz klucz i możesz wyjść w każdej chwili. VMWare — to złota klatka, klucz do klatki należy do właściciela i będzie cię kosztował bardzo dużo.

Nie namawiam ani do pierwszego, ani do drugiego produktu — wybierasz to, co jest potrzebne. Ale gdybym miał taki wybór, wybrałbym oba rozwiązania: VMWare do chmury IT (małe obciążenia, łatwe zarządzanie), OpenStack od jakiegoś dostawcy (Nokia i Juniper oferują naprawdę dobre rozwiązania pod klucz) — dla chmury Telekom. Nie używałbym OpenStack do czystego IT — to jak strzelanie z armaty do wróbli, ale nie widzę przeciwwskazań do jego używania, poza nadmiarem. Z drugiej strony używanie VMWare w telekomunikacji — to jak transportowanie żwiru Fordem Raptor — ładnie wygląda, ale kierowca musi zrobić 10 kursów zamiast jednego.

Moim zdaniem największą wadą VMWare jest jej całkowita zamkniętość — firma nie udostępnia żadnych informacji na temat tego, jak działa na przykład vSAN lub co dzieje się w jądrze hypervisora — nie jest to dla niej opłacalne — to znaczy nigdy nie staniesz się ekspertem w VMWare — bez wsparcia dostawcy jesteś skazany (bardzo często spotykam ekspertów od VMWare, którzy mają problemy z banalnymi pytaniami). Dla mnie VMWare to zakup samochodu z zamkniętą na klucz maską — tak, może masz specjalistów, którzy mogą wymienić pasek rozrządu, ale tylko ten, kto sprzedał ci to rozwiązanie, może otworzyć maskę. Osobiście nie lubię rozwiązań, do których nie mogę zajrzeć. Powiesz, że być może nie będziesz musiał zaglądać pod maskę. To prawda, ale zobaczę cię, gdy trzeba będzie zbudować dużą funkcję w chmurze z 20-30 maszyn wirtualnych, 40-50 sieci, z których połowa chce wyjść na zewnątrz, a druga połowa prosi o przyspieszenie SR-IOV, w przeciwnym razie potrzeba będzie jeszcze kilka dziesiątków takich maszyn, bo inaczej nie wystarczy wydajności.

Istnieją także inne punkty widzenia, więc tylko ty decydujesz, co wybrać i co najważniejsze — to ty będziesz odpowiedzialny za swój wybór. To tylko moja opinia — człowieka, który widział i dotknął przynajmniej 4 produktów — Nokia, Juniper, Red Hat i VMWare. Mam więc z czym porównywać.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster