Wprowadzenie do konteneryzacji #3

Maciej Lelusz
29. maja 2018
Reading time: 1 min
Wprowadzenie do konteneryzacji #3

Przyszedł czas na ostatnią już część serii artykułów o konteneryzacji. Tutaj znajdziecie część: pierwszą oraz drugą. Tymczasem nieważne gdzie będziemy budować nasz klaster, wypadałby wiedzieć coś o tym, jak używając platformy Docker zachowa się sieć. Wymagania aplikacji i realia sieci to bardzo często dwa zupełnie różne światy. Najczęściej jedno nie do końca rozumie drugie, a czasami… rzekłbym prawie zawsze, trudno jest uzyskać wymagania względem środowiska sieciowego, jakie ma być dostarczone przez dział IT dla produktów budowanych przez dział developerski.

Tak jak w świecie poza konteneryzacyjnym, tak i tutaj zderzymy się z tym problemem, tyle tylko, że potencjalny developer ma zdecydowanie mniejszy wybór rozwiązań. Platforma Docker udostępnia trzy modele konfiguracji sieci tzw. Container Network Model (CNM). Rzeczony CNM jest swoistym brokerem połączeń poprzez sterowniki sieciowe dostępne w platformie. Są to moduły dołączane do Docker Engine, Swarm lub UCP (Płatny Universal Control Plane), standardowo mamy pięć – host, bridge, overlay, MACVLAN i none. Ogólna architektura przedstawia się następująco:

 class=

Mamy tutaj wspomniane sterowniki, oczywiście poza standardowymi można dołączać inne, dostarczane przez różnych producentów, w formie plug-in. Oraz tzw. IPAM Driver, czyli sterowniki odpowiedzialne za zarządzanie adresacją IP. Zajmijmy się tymi pięcioma głównymi sterownikami sieciowymi (Network Drivers), a dokładnie trzema z nich (bridge, overlay, MACVLAN), gdyż potrafią one udźwignąć naprawdę dużą ilość scenariuszy:

  • Bridge – sterownik ten tworzy linuxowy bridge na hoście, gdzie działa Docker Engine do interfejsu kontenera, który jest na nim uruchomiony. Domyślnie kontenery w obrębie hosta mogą się ze sobą komunikować, można tym zarządzać, jak również i dostępem na zewnątrz, wszystko za pomocą sterownika bridge.
  • Overlay – przy użyciu tego sterownika tworzona jest sieć overlay (nakładkowa), która z pudełka wspiera połączenia pomiędzy różnymi hostami z zainstalowanym Docker Engine I kontenerami działającymi na nich. Metoda ta do działania opiera się na użyciu kombinacji Linux Bridge i VXLAN, aby obsłużyć komunikację między kontenerami przy użyciu fizycznej sieci.
  • MACVLAN – używając go, ustawiany jest tzw. MACVLAN bridge mode, który pozwala na ustanowienie połączenia z interfejsem (lub sub-interfejsem) hosta, na którym znajduje się Docker Engine i uruchomiony jest kontener. Pozwala to na nadanie dla adresu IP kontenerowi, który jest routowalny do sieci fizycznej. Dzięki sterownikowi MACVLAN możliwe jest również przekazanie VLAN do samego kontenera co umożliwia segmentacje na warstwie drugiej modelu OSI.
https://evoila.com/pl/wprowadzenie-do-konteneryzacji-1/

Celem bardziej szczegółowego zobrazowania sobie działania modeli CNM weźmy na tapetę hipotetyczny scenariusz, gdzie w kontenerze mamy serwer HTTP działający na porcie 8080. Chcemy go udostępnić na świat poprzez mapowanie portu 8080 z kontenera na 8080 w Docker Engine (DE). Najprostszą drogą będzie użycie scenariusza, gdzie używamy CNM w modelu Bridge i mostkujemy wewnętrzy interfejs kontenera z interfejsem DE, następnie mapujemy port z wewnętrznego do zewnętrznego interfejsu. Overlay będzie nam pomocny, gdy chcemy np. komunikować się w dokładnie zdefiniowany sposób pomiędzy rzeczonym serwerem HTTP a bazą danych, która ma się znaleźć na innym DE w innym kontenerze. Tworzymy interfejs przy użyciu sterownika Overlay pomiędzy bazą a serwerem HTTP, pakiety zaczynają płynąć pomiędzy hostami fizycznymi/VM, gdzie znajdują się kontenery. MACVLAN użyjemy, gdy będziemy chcieli widzieć w naszej sieci fizycznej MAC-ki, każdego z kontenerów. Ważne jest, aby wspomnieć o tym, że przy użyciu sieci Overlay informacje, jej Control Plane, dot. zarządzania działają po tzw. sieci Gossip, która pakuje dane w otoczkę TLS, czyli poprzez szyfrowany kanał przy pomocy mechanizmu AES. Dzieje się to automatycznie i nie mamy na to wpływu. Klucz przetrzymywany jest przez węzły Manager klastra i wymieniany są co 12h. Ruch pomiędzy kontenerami, Data Plane, może być również zaszyfrowany na nasze życzenie za pomocą jednego przełącznika, nie jest to natomiast domyślne zachowanie.

Komunikacja to jedna rzecz, ale istotne jest również, jak przechowujemy dane w świecie kontenerów. Kwestia storage w kontekście Dockera opiera się o idee warstw. Wiecie już, że obraz kontenera jest ściągany z repozytorium znajdującym się w Rejestrze np. Docker Hub. Mamy nasz obraz, przede wszystkim warto wiedzieć,  że jest on ściągany na dysk lokalny hosta, na którym uruchomiony jest Docker Engine i on właśnie jest naszą pierwszą warstwą, która pozostaje w trybie tylko do odczytu. Gdy już mamy obraz ściągnięty na dysk pewnie chcielibyśmy dodać do niego naszą aplikację. Gdy to wykonamy to, zostanie stworzona cienka warstwa z możliwością zapisu i w niej dodane zostaną pliki, natomiast obraz bazowy nie zostanie ruszony.

Korzystając z analogii do wirtualizacji można to przyrównać to do Snapshota, co więcej snapshota wykonanego w metodzie CoW. Copy-on-write, bo o tym mowa jest hybrydą współdzielenia i kopiowania… wyobraźmy sobie, że system chce uzyskać dostęp do danych, ale tylko aby je odczytać. Operacja taka nie stworzy niezależnej instancji danych do tego żądania – dostęp zostanie uzyskany na zasadzie wskaźnika do już istniejących danych. Natomiast, gdy kontener będzie chciał coś zmienić w danych, to zostaną one skopiowane i na tych konkretnych danych zostanie wykonana zmiana. Natomiast wszystkie inne kontenery korzystające z pierwotnych danych będą miały do nich dostęp. Docker używa CoW zarówno w kontekście obrazów, jak i danych samych kontenerów, dzięki czemu zoptymalizowane jest użycie przestrzeni dyskowej, jak również, wydajność, a najważniejsze to szybkość uruchamiania. Wróćmy jednak na chwilę jeszcze do warstw. Bo podejrzewam, że zaczynasz się zastawiać nad tym, co się stanie z danymi w tej cienkiej warstwie, którą tworzy kontener, gdy go się wyłączy. No cóż… dane zostaną utracone. Zrobiło się gorąco nieprawdaż? Ten atak pytań, a co z systemami i danymi, które muszą być trwałe co np. z bazami danych? Zacznijmy od początku, od aplikacji, bo w końcu wszystko dla nich! Otóż aplikacje można podzielić na wiele różnych sposobów, my z tej meandry kategoryzacyjnej skupimy się na aplikacjach stanowych (statefull) oraz bezstanowych (stateless). Te pierwsze, czyli aplikacje stanowe w bardzo dużym uproszczeniu coś przetrzymują lokalnie na systemie, na którym działają – mogą to być pliki sesji użytkowników, tworzą jakieś tymczasowe dane i inne tego typu rzeczy. Po utracie tych plików może się zdarzyć, że użytkownik straci swoje dane lub zostanie nagle wylogowany. Aplikacje bezstanowe nic nie utrzymują na maszynie, na której działają, są swego rodzaju międzymordziem, które łączy użytkownika i bazę danych lub inny system, który przetrzymuje dane. Strata plików z systemu, na którym działają, nie są dla nich istotne, więc aplikacja przy stracie jednego z np. kontenerów ją utrzymujących nie będzie uszkodzona, a użytkownik nie straci danych, czy nawet w pewnych sytuacjach nie zauważy, że coś się wydarzyło. Jak zapewne się już domyślacie, konteneryzacja pokazuje swoją siłę w pełnej krasie w kontekście tych drugich, natomiast nie ma co panikować, są sposoby przechowania danych, które mają być nieulotne. Aplikacje stanowe można utrzymywać w klastrze, wymagane są do tego sterowniki dyskowe, które pozwolą na podłączenie zewnętrznego wolumenu, na którym dane owe będą przechowywane, a w przypadku awarii kontenera przekazane do nowego, który stanie w jego miejscu. Platforma Dockera posiada taki mechanizm już wbudowany w Docker Engine nazywa się to po prostu Volumes. Pozwala on na podłączenie któregoś z dysków lub katalogów znajdujących się w hoście, na którym zainstalowany jest Docker Engine. Dalsze scenariusze można sobie już wyobrazić – jest to na przykład udział NFS/DFS lub system plików ZFS współdzielony przez wiele silników Docker. Platforma umożliwia również wykorzystanie sterowników firm trzecich np. Flocker, HPE, NetApp, VMware itd., które pozwalają na zautomatyzowanie tworzenia i podłączenia do konkretnego kontenera dedykowanych LUN-ów, bądź plików z danymi za pomocą API specyficznego dla konkretnego dostawcy.

https://evoila.com/pl/wprowadzenie-do-konteneryzacji-2/

Dobra, rozumiemy tę platformę kontenryzacyjną, ale co to nam daje? Nie siląc się na razie, na gigantyczne liczenie ROI i TCO – bo każdy projekt jest inny, popatrzmy na oba obrazki architektury i dodajemy jeden do jednego. W zasadzie od razu można stwierdzić, że mamy mniej warstw, czyli mniej skomplikowane środowisko. Często taka sytuacja w IT oznacza, że wymagane jest mniej licencji choćby na system operacyjny, bo nie mamy już w każdej VM systemu operacyjnego, a jedną per fizyczną maszynę. Oczywiście nie zajmie długo graczom takim jak Microsoft, RedHat, SUSE itp. aby zauważyć trend konteneryzacyjny w IT i dodać go do modelu licencyjnego i zgolić nas na grubą kasę. Natomiast na razie jest to nieco szara strefa. Kolejnym elementem jest brak hypervisora, a to może okazać się kolosalną oszczędnością… może, ale nie musi, ponieważ środowisko wirtualizacyjne może być obecne w ekosystemie konteneryzacyjny i być de facto formą dostarczania Hardware Land – nie instalujemy systemu operacyjnego bezpośrednio na sprzęcie fizycznym a w VM. Praktycznie oznacza to, że nie musimy wyrzucać wszystkiego, co posiadamy, aby wdrożyć konteneryzacje, a wręcz przeciwnie możemy to sprytnie wykorzystać. Wróćmy jednak do oszczędności, bo w sumie nie powiedzieliśmy o dwóch największych – zasoby i czas. Pierwsza jest w miarę oczywista, w środowisku 4 maszyn wirtualnych, mamy 4 systemy operacyjne, zjadające każda podobną ilość zasobów (Czas procesora, RAM, IOPS i miejsce na dysku) tylko po to, aby istnieć. Środowisko konteneryzacyjne zdejmuje z nas ten podatek – jeden system równa się zasobom skonsumowany tylko raz. Daje nam to więcej miejsca na uruchamianie aplikacji, a nie czapy administracyjnej w postaci maszyn wirtualnych i systemów operacyjnych. Element drugi największych oszczędności wynikających z konteneryzacji to czas i można go zdefiniować na wielu płaszczyznach. Zacznijmy od oszczędności czasu w kontekście zasobów, wiem, że to trochę dziwny wymiar, ale za chwile wszystko będzie jasne. Otóż tak jak wspomniałem utrzymanie wielu VM jest kosztowne ze względu na zasoby, demon uruchamiający kontenery jest leciutki. Maszyny wirtualne startują kilka chwil, zależnie od systemu operacyjnego, który jest w nich uruchomiony, następnie dopiero po tym, jak się uruchomią, podnoszone są aplikacje i to zazwyczaj trwa kilka sekund. Obraz Dockera to w zasadzie sama aplikacja i klika, niezbędnych do jej działania bibliotek. Przez to, że silnik Dockera jest lekki to podatek zapłacony, aby uruchomić aplikację, jest niewielki, natomiast uruchomienie aplikacji konsumuje tyle zasobów, ile tylko sama aplikacja wymaga – czyli zdecydowanie mniej niż pakiet aplikacja plus system operacyjny. Fizyki nie oszukasz. Mało zasobów do zapakowania do RAM, odczytania z dysku itd. daje znaczącą oszczędność w czasie podczas uruchomienia, usuwania czy też zmiany w kontenerze. Kolejną płaszczyzną oszczędności czasu jest fakt, że nie musimy dbać o system operacyjny w wielu instancjach, tak jak to ma miejsce przy wielu maszynach wirtualnych. Mamy jeden, hostujący jakąś skończoną ilość kontenerów i dbamy tylko o jego konfigurację, zgodność, bezpieczeństwo i inne tego typu wątpliwe przyjemności. Przyjmując, że kontener przychodzi do nas już ze skonfigurowaną aplikacją w środku, nie musimy się martwić o zmiany konfiguracyjne w systemie, których mogłaby wymagać aplikacja. Sprawia to, że jesteśmy w stanie zunifikować środowisko nie tylko na warstwie hypervisorów jak to jest teraz, ale i na warstwie systemów operacyjnych… Dla przykładu – mamy jeden szablon prekonfigurowanego systemu operacyjnego zawierającego skonfigurowany i gotowy do działania silnik Docker i instalujemy go na maszynach fizycznych lub wirtualnych w obrębie całej infrastruktury odpowiedzialnej za utrzymanie aplikacji. Natomiast aplikacje dostarczane dla nas przez programistów są zamknięte w kontenerze z całą konfiguracją i wszystkim, co im niezbędne do życia i nie mają wpływu na nasz Hardware Land. Widzicie to? Nareszcie można będzie postawić faktyczną granicę odpowiedzialności – gdzie kończy się praca administratorów/operatorów infrastruktury IT a gdzie developerów, kto gdzie ma dostęp, co jest czyje i który zespół ma sobie radzić z jakimi problemami. Sytuacja ta ma również niebagatelny wpływ na skalowalność infrastruktury – jeden obraz systemu operacyjnego instalowany na kilku lub kilkuset maszynach fizycznych, lub wirtualnych używający jednego (!) szablonu, jednego workflow, aby go uruchomić w systemie automatyzacji, jednego zestawu polityk bezpieczeństwa, jednego audytu… wszystko to aby dostarczyć różnorodne aplikacje, oparte nawet o kompletnie inne frameworki, języki programowania czy też finalnie platformy. Czy nie brzmi to dobrze?

Za dobrze, można by nawet powiedzieć… nauczony latami katastrof spowodowanych rewolucyjnymi technologiami szukałem, pewnie tak jak i pewnie Ty drogi czytelniku jakichś wad, problemów, czy też wyzwań podczas wdrażania tej jakby nie patrzeć nowej technologii. Niema bowiem rzeczy doskonałych, jak również i idealnych do każdego zastosowania. Czy Docker ma wady? Jasne. Dla niektórych pewnie nie do przeskoczenia, dla innych warte ryzyka względem tego, co powyżej wymieniłem jako zalety. Natomiast trzeba stwierdzić z pełną odpowiedzialnością, że jest on gotowy na produkcję. Nie mówię tego ja, skromny autor tego drobnego podsumowania a jedynie powtarzam, za firmą Docker Inc. która udowodniała to poprzez wypuszczenie wersji 1.0 Dockera i publiczne oświadczenie, że jest „Production Ready”. Trudno dyskutować z producentem, ale nie da się negować tego, że oprogramowanie, które oferuje, dostarczane jest z możliwością wsparcia… Nikt nie podjąłby takiego ryzyka, aby oferować wsparcie dla rozwiązania, gdy nie jest ono gotowe do faktycznego utrzymania aplikacji produkcyjnych, bardzo często będących rdzeniem biznesu firmy, która się na to decyduje. Dodatkowo warto nadmienić, że firma Docker nie pochodzi z kraju trzeciego świata, gdzie prawa autorskie, dochowanie warunków umowy czy też SLA to czary-mary, ale z kraju gdzie firmy, w których rozwiązanie tego producenta zostałoby wdrożone i nie spełniałoby założeń bez mrugnięcia okiem armia prawników rozerwałyby na strzępy Docker Inc.

Myślę jednak, że meritum nie jest dyskusja o tym, czy platforma Docker jest sexy, jazzy, funky tylko czy działa. Otóż działa, ale ma pewne założenia, które trzeba spełnić, aby nie tylko działała, ale działała również dobrze. Zasady te są dosyć uniwersalne i wdrożenie ich w organizacji sprawi, że tworzone aplikacje będą po prostu lepsze i to nie ważne, czy na końcu zostaną uruchomione w modelu konteneryzacyjnym, czy też nie. Pierwszą zasadą jest zrozumienie aplikacji – czy jest stanowa, czy nie, jak działa, dlaczego tak, dlaczego nie inaczej, czemu ten framework, czemu taka baza itd. Kluczem nie jest przyjmowanie na ślepo jednej drogi, a wątpienie technologiczne połączone z otwartą dyskusją działów deweloperskich i IT. Zaadoptowanie kultury DevOps w organizacji. Nie mówię tutaj o sztucznej hipsterówie z tym związanej, ale o podejściu do infrastruktury jako nośnika aplikacji. Rozpoczęciu myślenia o IT przez pryzmat dostarczanych serwisów, a nie na odwrót z perspektywy serwerów, hypervisorów, sieci… bo one de facto są wtórne, ważne bowiem jest to, co chcemy osiągnąć. Może na pierwszy rzut oka brzmi to głupio, ale gdy popatrzymy na infrastrukturę IT jako bytu istniejącego tylko i wyłącznie dla aplikacji, a nie na odwrót to wiele rozwiązań, które aktualnie posiadamy może okazać się mega nienaturalnymi i wymagającymi zmiany. Kontenery wówczas przyjdą na scenę same, niewymuszone. Zmiana wykona się naturalnie. Trzeba jednak rozpocząć od spojrzenia, gdzie można je wdrożyć, co można na nich uruchomić i jakie korzyści przyniosą, a nie bezmyślnie się na nie rzucać. Pospolite ruszenie nigdy nie przynosi nic dobrego, a tak jak wspomniałem, kontenery nie są panaceum na wszystkie bolączki IT, ale na pewno mogą rozwiązać wiele problemów. Myślmy o nich czule przy niemonolitycznych aplikacjach, przy nowych wdrożeniach, przy systemach posiadających infrastrukturę mikro serwisów, przy projektach mających na celu przepisanie na nową platformę starej zbutwiałej aplikacji. Uciekajmy natomiast gdy ktoś proponuje nam migracje z VM 1:1 w kontenery – to samobójstwo. Nie bójmy się tworzyć nowej wyspy technologicznej w naszej infrastrukturze, nie pozwólmy natomiast na jej spontaniczne stworzenie – nie ma nic bowiem gorszego niż nagła nieogarnięta produkcja… i najważniejsze, choć gorzko to przechodzi przez gardło, rozmawiajmy z naszymi deweloperami i starajmy się współgrać, a nie walczyć.

Artykuł został opublikowany na łamach IT Professional.