Wprowadzenie do konteneryzacji #2

Porozmawialiśmy sobie o tym, jak w bardzo ogólnym ujęciu działają kontenery, ale platforma to nie tylko Docker Engine. Oczywiście jest on niezbędny, bo wszystko wybudowane jest dookoła niego, ale jest tam parę innych ciekawych rzeczy, np. Rejestr. Docker Registry, bo o nim mowa może występować w dwóch odmianach – Publiczny i Prywatny. Można go tendencyjnie przyrównać do bazy danych, ale to nuda. Pomyślmy o Docker Registry jako bibliotece podzielonej na szafki, które w kontekście Dockera będą repozytoriami, na których układane są książki, czyli nasze obrazy kontenerów Docker. Biblioteka może być publiczna i zawierać strefę publiczną z książkami dostępnymi dla każdego. Możesz wypożyczyć książkę, możesz też jakąś napisać i wysłać ją do biblioteki – będzie dostępna dla wszystkich, ale Ty będziesz autorem i tylko Ty będziesz ją mógł zmienić, a wszyscy będą mieli do niej dostęp. Biblioteka ta może mieć również strefy prywatne, gdzie tylko Ty lub wyznaczeni przez ciebie ludzie będą mieli dostęp, będą mogli czytać i pisać książki.

Analogicznie jest z publicznym Docker Registry, nazywa się on Docker Hub, w 2016 roku w jego bazie znajdowało się prawie pół miliona obrazów kontenerów i dokonano ponad 6 miliardów ich ściągnięć, mówimy tutaj o repozytoriach publicznych, a są dostępne również prywatne… Docker Hub dostępny jest z chmury, jeżeli istnieje potrzeba zainstalowania Rejestru lokalnie w swoim Datacenter taka możliwość również istnieje, nazywa się to w wersji komercyjnej (płatnej) Docker Trusted Registry lub wersja społeczności (darmowa) Docker Untrusted Registry. Różnią się one kilkoma szczegółami, ale najważniejszym jest fakt wsparcia przez Docker Inc. dla wersji komercyjnej, natomiast jego brak dla opensource. Nieważne, którą wersję wybierzecie, aby uruchomić obraz Dockera będziecie musieli użyć komendy `docker pull`. Oznacza ona ni mniej, ni więcej ściągniecie z rejestru z wybranego repozytorium obrazu kontenera na nasz Hardware Land i udostępnienie go do Docker Engine w celu uruchomienia. Można również tworząc swój własny kontener za pomocą komendy `docker push` wrzucić go do rejestru wybranego repozytorium. Zatem traktujcie Docker Registry jako bazę, w której znajdują się gotowe do użycia kontenery, zarówno Wasze, jak i przygotowane przez społeczność. Warto w tym miejscu nadmienić, że Docker Registry nie jest jedyną opcją rejestru dla kontenerów, w zasadzie to jest ich dostępnych całkiem sporo – GitLab Container Registry czy też Artifactory to tylko flagowe przykłady. To ważne, bo może już macie rejestr kontenerów w organizacji, w oprogramowaniu takim jak np. GitLab, które używane zazwyczaj jako repozytorium kodu, a pozwala również na uruchomienie rejestru. Warto się rozejrzeć niż powoływać kolejne być może nie do końca potrzebne byty. Bo mistrz Miyagi przypomina, że najlepszą drogą do sukcesu jest prostota architektury i wykorzystanie już działających, znanych nam narzędzi.

Mamy silnik, mamy rejestr warto by w tym miejscu, zanim przejdziemy dalej wspomnieć odrobinkę o mechanizmie Docker Content Trust. Jest to, ogólnie rzecz ujmując, mechanizm weryfikacji pochodzenia kontenerów i sprawdzania ich zgodności. Zanim potencjalny autor wyśle do rejestru Dockera, weźmy dla przykładu Docker Hub, stworzony przez siebie kontener, jest on podpisywany kluczem prywatnym twórcy. Kiedy potencjalny konsument obrazu po raz pierwszy wykonuje pull kontenera, nawiązywana jest relacja zaufania i sprawdzenie jest, czy kontener ma prawidłowy podpis i czy jest tym, za co się podaje. Można to przyrównać do modelu relacji zaufania uzyskiwanej przy połączeniu SSH z tą tylko różnicą, że inicjacja bezpiecznego połączenia następuje przez SSH i użyciu kluczy PKI. Mechanizm ten zabezpiecza nas przede wszystkim przed atakiem typu man-in-the-middle, gdzie kontener wymieniany jest w locie i zamiast dostać to, o co prosiliśmy, dostajemy bombę. Tak dla porządku poza Docker Content Trust platforma daje nam możliwość dostępu definiowanego w formie roli (RBAC) integrację z AD/LDAP i SSO.

Skoro możecie sobie wyobrazić jak działa już uruchamianie kontenerów przy pomocy Docker Engine, jak działa mechanizm Docker Content Trust, który zabezpiecza nas przed ściągnięciem bubla z Docker Registry to czas odpowiedzieć sobie na pytanie, co się dzieje, gdy mamy więcej niż jeden serwer fizyczny/wirtualny z silnikiem Dockera na pokładzie… To ten moment, gdy środowisko Dockerowe wychodzi z naszego laptopa i ma się stać produkcją! Cóż, trzeba by się zastanowić jak sprawić, aby można było odpalać kontenery nie tylko na jednym węźle, nie? Trzeba pomyśleć o klastrze, o zestawie serwerów, które zapewnią nam swoistą nadmiarowość, pozwolą na skalowanie zasobów i uruchomienie dziesiątek, setek czy też tysięcy kontenerów. Tutaj z pomocą przychodzi nam Docker Swarm. Jest to system, który można przyrównać do serwera VMware vCenter (bez GUI, tylko konsola) zarządzającego grupą serwerów ESX, czyli w naszym przypadku Docker Engine. Oczywiście różnic jest więcej niż cech wspólnych, ale chodzi tutaj tylko i wyłącznie o idee działania. Docker Swarm daje nam:

  • Zarządzanie klastrem zintegrowane z Docker Engine – wiele silników Dockerowych staje się dostępne z jednego miejsca jako pula zasobów i umożliwia w sposób zautomatyzowany rozmieszczanie nowych kontenerów na węzłach klastra – czyli nie musimy mówić, że kontener A ma się znaleźć na hoście 1 a kontener B na hoście 2.
  • Zdecentralizowana architektura – Nie ma różnych modeli wdrażania, instalacje węzłów typu Manager czy też Worker wykonuje się z tego samego zestawu binarek, więc można stosować do tego jeden obraz systemu operacyjnego z jednym rodzajem zainstalowanego Docker Engine.
  • Deklaratywny model działania – Docker używa deklaratywnego podejścia w definiowaniu stosu aplikacji i ich stanu oraz roli. Znaczy to nie mniej ni więcej, iż możemy opisać aplikację złożoną z usługi front end z usługami kolejkowania wiadomości i backend bazy danych i uruchomić ją w tak zdefiniowanej formie na klastrze.
  • Skalowanie – Możliwe jest automatyczne dodawanie kolejnych serwisów reprezentowanych przez kontenery, jak również ich usuwanie.
  • Ustalenie pożądanego stanu aplikacji – Swarm nieprzerwanie monitoruje stan klastra i jeżeli stwierdzi, że np. serwis złożony z 10 zdefiniowanych przez nas replik kontenerów aktualnie działa na 8 to automatycznie uruchomi 2 brakujące, lub zrestartuje aktualnie niedziałające kontenery zgodnie ze zdefiniowanymi przez nas zasadami.
  • Sieć między węzłami klastra – Jeden, według mnie, najciekawszy mechanizm w Docker Swarm jest związany z obsługą sieci, a dokładnie z możliwością powołania automatycznej sieci overlay pomiędzy węzłami klastra. Działa ona na podstawie VXLAN więc nie jest to nic autorskiego a standard w aktualnych sieciach nakładkowych. Dzięki temu możemy osiągnąć mikrosegmentację pomiędzy serwisami a co najważniejsze dba o to Docker Swarm w sposób automatyczny. Należy mu tylko w sposób odpowiedni przygotować sieć transportową.
  • Service discovery – Węzły klastra SWARM przydzielają każdemu serwisowi unikalną nazwę DNS, dzięki temu możesz w każdej chwili odpytać za pomocą DNS o dowolny kontener.
  • Load balancing – Swarm oferuje ci wewnętrzny mechanizm Load Balancingu, możesz również korzystać z zewnętrznego Load Balancera.
  • Security by default – Każdy węzeł klastra wymusza w komunikacji autentykację i szyfrowanie przy pomocy TLS. Masz możliwość używanie certyfikatów self-signed lub skorzystać z zewnętrznego bądź firmowego root CA.
  • Cykliczne aktualizacje – możliwość aktualizowania klastra w sposób częściowy, odczekanie jakiegoś czasu i aktualizacji kolejnych węzłów. Pozwala to na szybkie wykrycie problemów na niewielkiej części klastra i odpowiedniej reakcji bez narażania całego środowiska.

Wysokopoziomowa architektura rozwiązania widoczna jest na schemacie poniżej:

Jak widzicie mamy tutaj trzy rodzaje bytów. Pierwszy to Manager jest to węzeł klastra odpowiedzialny za przydzielenie zadań dla węzłów typu Worker, ogólne zarządzanie klastrem i orkiestrację zadań, udostępniają one również endpoint dla API klastra. Klaster wymaga min. 3 węzłów typu Master, gdzie może paść maksymalnie jeden, a klaster będzie wciąż działał, lub 5 i wtedy uzyskujemy odporność na awarię dwóch węzłów naraz. Awaria klastra sprawi, że nie będzie on zarządzalny, ale serwisy uruchomione na nim będą dalej działać. Drugim typem węzłów są nody typu Worker, są to również instancję Docker Engine, których główną rolą jest uruchamianie kontenerów. Węzły typu Worker potrzebują minimum jednego noda typu Manager, aby działać. Kolejnym bytem jest Service czy nasz polski serwis… umożliwia on uruchamianie kontenerów na klastrze Swarm. Typ serwisu określamy sami, może to być dla przykładu web Frontend, baza danych itd. Definicja serwisu może zawierać informacje, jaki obraz kontenera ma być użyty, jak również i komendy, jakie mają zostać użyte wewnątrz już działającego klastra, możemy wybierać z następujących elementów i akcji:

  • Service options – Podczas tworzenia serwisu można określić port usługi, jaki ma być zmapowany do sieci zewnętrznej, określić sieć overlay, do jakiej ma przynależeć serwis, ograniczenia RAM i CPU, politykę aktualizacji, oraz ilość replik kontenerów działających w obrębie serwisu.
  • Replicated vs. global services – Replika w kontekście serwisu oznacza ilość identycznych zadań (task), czyli kontenerów uruchomionych w celu świadczenia serwisu. Weźmy na tapetę sytuację, gdy chcemy uruchomić 4 repliki API Gateway dla Twojej aplikacji. Możemy to zrobić w dwóch trybach – global service, będzie polegał na uruchomieniu na każdym węźle klastra to znaczy tyle ile masz Docker Enginów tyle będziesz miał replik kontenera działających w klastrze, gdy dodasz kolejny host z zainstalowanym DE, zostanie powołana również kolejna replika. Możesz również określić ilość replik np. na wspomniane 4 i pozwolić menadżerom klastra powołać dokładnie taką ilość kontenerów.
  • Ustalenie pożądanego stanu aplikacji – kiedy uruchamiasz serwis w trybie Docker Swarm musisz stworzyć definicję, jaki stan serwisu oczekujesz, aby był utrzymany przez klaster. Przykładowo, tak jak powyżej, zdefiniowałeś, że chcesz, aby serwis miał uruchomione 4 instancje API Gateway dla Twojej aplikacji wraz z Load Balancingiem pomiędzy nimi. Swarm Manager uruchamia serwis złożony z 4 replik kontenerów na 4 dostępnych Docker Engine w klastrze. W przypadku, gdy jedna z instancji padnie, nieważne z jakich przyczyn, menadżer klastra rozpozna, że stan serwisu się zmienił. O ile jest to wymagane wyłączy uszkodzony kontener (replikę) i uruchomi kolejny z przypisanego obrazu tak, aby powrócić do zdefiniowanego przez nas stanu aplikacji.
  • Działanie podczas awarii kontenera – Docker Swarm, gdy wykryje, że kontener ma jakiś problem z działaniem, nie wykonuje restartu czy też próby naprawy kontenera. Orkiestrator zaszyty na węzłach klastra po prostu usuwa uszkodzony kontener i zastępuje go nowym.
  • Serwisy oczekujące – Podczas definicji serwisu można założyć pewne wymagania związane z Hardware Land i jego konfiguracją niezbędną do jego działania aplikacji. Przykładowo zdefiniowaliśmy, że serwis nie może się uruchomić na czymś słabszym niż Docker Engine wyposażony w 128GB RAM, i póki taki węzeł nie zostanie dodany do klastra Swarm serwis będzie pozostawał w stanie oczekiwania (Pending).

Reasumując Docker Swarm jest trybem działania, w którym może działać wiele Docker Engine umożliwiającym powoływanie serwisów złożonych z replik, czyli zadań (tasków) reprezentowanych przez kontenery. Warto tutaj zauważyć, że kontener jest równy jednemu zadaniu. To bardzo ważna rzecz! Aktualnie przyzwyczajeni jesteśmy, że serwery świadczą więcej niż jedno zadanie – np. serwer www i baza danych na jednej VM/hoście fizycznym. Docker odchodzi od tego modelu… nie jest to zakazane, ale generalnie się tak nie robi. Jeden kontener, jedno zadanie. Oczywiście na jednym kontenerze może być obsługiwanych wielu użytkowników, ale z reguły jeden kontener realizuje tylko jedną funkcję.

Wydaje mi się, że istotną rzeczą w tym miejscu jest wspomnienie o tym, że Docker Swarm to nie jedyna opcja jako narzędzie do klastrowania i orkiestracji. Jesienią 2017 roku podczas DockerCon ogłoszono, że Docker Inc. będzie również oficjalnie wspierał dodatkowo, obok Swarma rozwiązanie nazywane Kubernetes… ale to już temat na zupełnie inną opowieść. Dla porządku nadmienię, że istnieją poza Swarmem i Kubernetesem jeszcze inne silniki do orkiestracji i klastrowania kontenerów takie jak np. Mesosphere czy też CoreOS Fleet. Skupmy się jednak na Docker Swarm, gdyż jest on dostępny od razu, w paczce wraz z Docker Engine – nic nie trzeba odinstalowywać, tylko uruchomić i zacząć używać. Na początek to i tak dużo, a z biegiem czasu można swobodnie zmienić orkiestrator lub skorzystać z PaaS takich jak Google Container Engine czy Amazon Elastic Container Service.

Artykuł został opublikowany na łamach IT Professional.