Skalowanie Scali: jak dokować za pomocą Kubernetes

Opublikowany: 2022-03-11

Kubernetes to nowy dzieciak, który obiecuje pomóc wdrażać aplikacje w chmurze i szybciej je skalować. Dzisiaj, kiedy rozwijamy architekturę mikroserwisów, dość standardem jest wybór Scali do tworzenia serwerów API.

Mikrousługi zastępują klasyczne monolityczne serwery zaplecza wieloma niezależnymi usługami, które komunikują się między sobą i mają własne procesy i zasoby.

Jeśli w Twoich planach jest aplikacja Scala i chcesz ją przeskalować do chmury, to jesteś we właściwym miejscu. W tym artykule pokażę krok po kroku, jak wziąć ogólną aplikację Scala i zaimplementować Kubernetes z Dockerem, aby uruchomić wiele instancji aplikacji. Ostatecznym rezultatem będzie pojedyncza aplikacja wdrożona jako wiele instancji i równoważona przez Kubernetes.

Wszystko to zostanie zaimplementowane po prostu przez zaimportowanie zestawu źródłowego Kubernetes do aplikacji Scala. Należy pamiętać, że zestaw kryje w sobie wiele skomplikowanych szczegółów związanych z instalacją i konfiguracją, ale jest na tyle mały, że jest czytelny i łatwy do zrozumienia, jeśli chcesz przeanalizować, co robi. Dla uproszczenia wdrożymy wszystko na Twoim lokalnym komputerze. Jednak ta sama konfiguracja jest odpowiednia dla rzeczywistego wdrożenia Kubernetes w chmurze.

Skaluj swoją aplikację Scala za pomocą Kubernetes

Bądź mądry i śpij spokojnie, skaluj swojego Dockera za pomocą Kubernetes.
Ćwierkać

Co to jest Kubernetes?

Zanim przejdziemy do krwawych szczegółów implementacji, omówmy, czym jest Kubernetes i dlaczego jest to ważne.

Być może słyszałeś już o Dockerze. W pewnym sensie jest to lekka maszyna wirtualna.

Docker daje korzyści polegające na wdrożeniu każdego serwera w odizolowanym środowisku, bardzo podobnym do autonomicznej maszyny wirtualnej, bez złożoności zarządzania pełnoprawną maszyną wirtualną.

Z tych powodów jest to już jedno z szerzej stosowanych narzędzi do wdrażania aplikacji w chmurze. Obraz Dockera jest dość łatwy i szybki do zbudowania i duplikowania, znacznie łatwiejszy niż tradycyjna maszyna wirtualna, taka jak VMWare, VirtualBox lub XEN.

Kubernetes uzupełnia platformę Docker, oferując kompletne środowisko do zarządzania zadokowanymi aplikacjami. Korzystając z Kubernetes, możesz łatwo wdrażać, konfigurować, organizować, zarządzać i monitorować setki, a nawet tysiące aplikacji platformy Docker.

Kubernetes to narzędzie typu open source opracowane przez Google i zostało przyjęte przez wielu innych dostawców. Kubernetes jest dostępny natywnie na platformie chmurowej Google, ale inni dostawcy przyjęli go również w swoich usługach chmurowych OpenShift. Można go znaleźć na Amazon AWS, Microsoft Azure, RedHat OpenShift i jeszcze innych technologiach chmurowych. Możemy powiedzieć, że jest dobrze przygotowany, aby stać się standardem wdrażania aplikacji w chmurze.

Warunki wstępne

Teraz, gdy omówiliśmy podstawy, sprawdźmy, czy masz zainstalowane całe wstępnie wymagane oprogramowanie. Przede wszystkim potrzebujesz Dockera. Jeśli używasz systemu Windows lub Mac, potrzebujesz Przybornika Docker. Jeśli używasz Linuksa, musisz zainstalować konkretny pakiet dostarczony przez Twoją dystrybucję lub po prostu postępować zgodnie z oficjalnymi wskazówkami.

Będziemy programować w Scali, która jest językiem JVM. Potrzebujesz oczywiście Java Development Kit i narzędzia scala SBT zainstalowanego i dostępnego w ścieżce globalnej. Jeśli jesteś już programistą Scala, prawdopodobnie masz już zainstalowane te narzędzia.

Jeśli używasz systemu Windows lub Mac, Docker domyślnie utworzy maszynę wirtualną o nazwie default z tylko 1 GB pamięci, co może być zbyt małe do uruchomienia Kubernetes. Z mojego doświadczenia wynika, że ​​miałem problemy z ustawieniami domyślnymi. Polecam otworzyć VirtualBox GUI, wybrać default maszynę wirtualną i zmienić pamięć na co najmniej 2048 MB.

Ustawienia pamięci VirtualBox

Aplikacja do klastrowania

Instrukcje zawarte w tym samouczku mogą dotyczyć dowolnej aplikacji lub projektu Scala. Aby ten artykuł miał trochę „mięsa” do pracy, wybrałem przykład używany bardzo często do zademonstrowania prostej mikrousługi REST w Scali o nazwie Akka HTTP. Zalecam spróbować zastosować zestaw źródłowy do sugerowanego przykładu przed próbą użycia go w swojej aplikacji. Testowałem zestaw z aplikacją demonstracyjną, ale nie mogę zagwarantować, że nie wystąpią konflikty z Twoim kodem.

Więc najpierw zaczynamy od sklonowania aplikacji demonstracyjnej:

 git clone https://github.com/theiterators/akka-http-microservice

Następnie sprawdź, czy wszystko działa poprawnie:

 cd akka-http-microservice sbt run

Następnie przejdź do http://localhost:9000/ip/8.8.8.8 i powinieneś zobaczyć coś takiego jak na poniższym obrazku:

Mikroserwis Akka HTTP jest uruchomiony

Dodawanie zestawu źródłowego

Teraz możemy dodać zestaw źródłowy z odrobiną magii Git:

 git remote add ScalaGoodies https://github.com/sciabarra/ScalaGoodies git fetch --all git merge ScalaGoodies/kubernetes

Dzięki temu masz wersję demonstracyjną zawierającą zestaw źródłowy i jesteś gotowy do wypróbowania. Możesz też skopiować i wkleić stamtąd kod do swojej aplikacji.

Po połączeniu lub skopiowaniu plików w swoich projektach możesz zacząć.

Uruchamianie Kubernetes

Po pobraniu zestawu musimy pobrać niezbędny plik binarny kubectl , uruchamiając:

 bin/install.sh

Ten instalator jest wystarczająco inteligentny (miejmy nadzieję), że pobierze poprawny plik binarny kubectl dla OSX, Linux lub Windows, w zależności od systemu. Uwaga, instalator pracował na systemach, które posiadam. Proszę zgłaszać wszelkie problemy, abym mógł naprawić zestaw.

Po zainstalowaniu pliku binarnego kubectl możesz uruchomić cały Kubernetes w lokalnym Dockerze. Po prostu biegnij:

 bin/start-local-kube.sh

Przy pierwszym uruchomieniu to polecenie pobierze obrazy całego stosu Kubernetes oraz rejestr lokalny potrzebny do przechowywania obrazów. Może to zająć trochę czasu, więc prosimy o cierpliwość. Pamiętaj również, że potrzebuje bezpośredniego dostępu do Internetu. Jeśli jesteś za proxy, będzie to problem, ponieważ zestaw nie obsługuje proxy. Aby go rozwiązać, musisz skonfigurować narzędzia takie jak Docker, curl i tak dalej, aby korzystać z proxy. Jest to na tyle skomplikowane, że polecam uzyskać tymczasowy nieograniczony dostęp.

Zakładając, że udało Ci się pobrać wszystko pomyślnie, aby sprawdzić, czy Kubernetes działa poprawnie, możesz wpisać następujące polecenie:

 bin/kubectl get nodes

Oczekiwana odpowiedź to:

 NAME STATUS AGE 127.0.0.1 Ready 2m

Pamiętaj, że wiek może się oczywiście różnić. Ponadto, ponieważ uruchomienie Kubernetes może zająć trochę czasu, być może będziesz musiał wywołać polecenie kilka razy, zanim zobaczysz odpowiedź. Jeśli nie pojawiają się tu błędy, gratulacje, masz Kubernetes na swoim lokalnym komputerze.

Dokeryzacja aplikacji Scala

Teraz, gdy masz już uruchomiony Kubernetes, możesz w nim wdrożyć swoją aplikację. W dawnych czasach, przed Dockerem, do uruchamiania aplikacji trzeba było wdrożyć cały serwer. W Kubernetes wszystko, co musisz zrobić, aby wdrożyć swoją aplikację, to:

  • Utwórz obraz Dockera.
  • Umieść go w rejestrze, z którego można go uruchomić.
  • Uruchom instancję za pomocą Kubernetesa, który pobierze obraz z rejestru.

Na szczęście jest to o wiele mniej skomplikowane, niż się wydaje, zwłaszcza jeśli używasz narzędzia do budowania SBT, jak wiele innych osób.

W zestawie dołączyłem dwa pliki zawierające wszystkie niezbędne definicje do stworzenia obrazu zdolnego do uruchomienia aplikacji Scala, a przynajmniej tego, co jest potrzebne do uruchomienia demo Akka HTTP. Nie mogę zagwarantować, że będzie działać z innymi aplikacjami Scala, ale jest to dobry punkt wyjścia i powinien działać w wielu różnych konfiguracjach. Pliki do zbudowania obrazu Dockera to:

 docker.sbt project/docker.sbt

Przyjrzyjmy się, co w nich jest. Plik project/docker.sbt zawiera polecenie importu wtyczki sbt-docker :

 addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.4.0")

Ta wtyczka zarządza budowaniem obrazu Docker za pomocą SBT. Definicja Dockera znajduje się w pliku docker.sbt i wygląda tak:

 imageNames in docker := Seq(ImageName("localhost:5000/akkahttp:latest")) dockerfile in docker := { val jarFile: File = sbt.Keys.`package`.in(Compile, packageBin).value val classpath = (managedClasspath in Compile).value val mainclass = mainClass.in(Compile, packageBin).value.getOrElse(sys.error("Expected exactly one main class")) val jarTarget = s"/app/${jarFile.getName}" val classpathString = classpath.files.map("/app/" + _.getName) .mkString(":") + ":" + jarTarget new Dockerfile { from("anapsix/alpine-java:8") add(classpath.files, "/app/") add(jarFile, jarTarget) entryPoint("java", "-cp", classpathString, mainclass) } }

Aby w pełni zrozumieć znaczenie tego pliku, musisz znać Docker na tyle dobrze, aby zrozumieć ten plik definicji. Nie będziemy jednak wchodzić w szczegóły pliku definicji Dockera, ponieważ nie trzeba go dokładnie rozumieć, aby zbudować obraz.

Piękno korzystania z SBT do budowania obrazu Dockera polega na tym
SBT zajmie się zebraniem wszystkich plików za Ciebie.

Zauważ, że ścieżka klasy jest automatycznie generowana przez następujące polecenie:

 val classpath = (managedClasspath in Compile).value

Ogólnie rzecz biorąc, zebranie wszystkich plików JAR w celu uruchomienia aplikacji jest dość skomplikowane. Używając SBT, plik Docker zostanie wygenerowany z add(classpath.files, "/app/") . W ten sposób SBT zbiera dla Ciebie wszystkie pliki JAR i tworzy plik Dockerfile do uruchamiania aplikacji.

Pozostałe polecenia zbierają brakujące elementy, aby utworzyć obraz Dockera. Obraz zostanie zbudowany przy użyciu istniejącego obrazu APT do uruchamiania programów Java ( anapsix/alpine-java:8 , dostępny w Internecie w Docker Hub). Inne instrukcje to dodawanie innych plików w celu uruchomienia aplikacji. Wreszcie, określając punkt wejścia, możemy go uruchomić. Zauważ też, że nazwa zaczyna się od localhost:5000 celowo, ponieważ localhost:5000 to miejsce, w którym zainstalowałem rejestr w skrypcie start-kube-local.sh .

Tworzenie obrazu Dockera za pomocą SBT

Aby zbudować obraz Docker, możesz zignorować wszystkie szczegóły pliku Docker. Wystarczy wpisać:

 sbt dockerBuildAndPush

Wtyczka sbt-docker zbuduje następnie obraz Dockera, pobierając z Internetu wszystkie niezbędne elementy, a następnie prześle do rejestru Docker, który został uruchomiony wcześniej, razem z aplikacją Kubernetes na localhost . Wszystko, czego potrzebujesz, to poczekać trochę dłużej, aby Twój obraz był gotowy i gotowy.

Uwaga, jeśli wystąpią problemy, najlepiej zresetować wszystko do znanego stanu, uruchamiając następujące polecenia:

 bin/stop-kube-local.sh bin/start-kube-local.sh

Te polecenia powinny zatrzymać wszystkie kontenery i poprawnie je ponownie uruchomić, aby Twój rejestr był gotowy do odbioru obrazu zbudowanego i przesłanego przez sbt .

Uruchomienie usługi w Kubernetes

Teraz, gdy aplikacja jest spakowana w kontenerze i umieszczona w rejestrze, jesteśmy gotowi do jej użycia. Kubernetes używa wiersza poleceń i plików konfiguracyjnych do zarządzania klastrem. Ponieważ wiersze poleceń mogą stać się bardzo długie, a także umożliwiać replikację kroków, używam tutaj plików konfiguracyjnych. Wszystkie próbki w zestawie źródłowym znajdują się w folderze kube .

Naszym następnym krokiem jest uruchomienie pojedynczej instancji obrazu. Uruchomiony obraz jest nazywany w języku Kubernetes pod . Stwórzmy więc pod, wywołując następujące polecenie:

 bin/kubectl create -f kube/akkahttp-pod.yml

Możesz teraz sprawdzić sytuację za pomocą polecenia:

 bin/kubectl get pods

Powinieneś zobaczyć:

 NAME READY STATUS RESTARTS AGE akkahttp 1/1 Running 0 33s k8s-etcd-127.0.0.1 1/1 Running 0 7d k8s-master-127.0.0.1 4/4 Running 0 7d k8s-proxy-127.0.0.1 1/1 Running 0 7d

W rzeczywistości status może być inny, na przykład „KontenerTworzenie”, może minąć kilka sekund, zanim stanie się „Uruchomiony”. Możesz także uzyskać inny status, taki jak „Błąd”, jeśli na przykład zapomnisz wcześniej utworzyć obraz.

Możesz również sprawdzić, czy Twój pod działa, za pomocą polecenia:

 bin/kubectl logs akkahttp

Powinieneś zobaczyć wyjście kończące się czymś takim:

 [DEBUG] [05/30/2016 12:19:53.133] [default-akka.actor.default-dispatcher-5] [akka://default/system/IO-TCP/selectors/$a/0] Successfully bound to /0:0:0:0:0:0:0:0:9000

Teraz masz już uruchomioną usługę wewnątrz kontenera. Jednak usługa nie jest jeszcze dostępna. To zachowanie jest częścią projektu Kubernetes. Twój pod działa, ale musisz go jawnie ujawnić. W przeciwnym razie usługa ma być wewnętrzna.

Tworzenie usługi

Stworzenie usługi i sprawdzenie wyniku to kwestia wykonania:

 bin/kubectl create -f kube/akkahttp-service.yaml bin/kubectl get svc

Powinieneś zobaczyć coś takiego:

 NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE akkahttp-service 10.0.0.54 9000/TCP 44s kubernetes 10.0.0.1 <none> 443/TCP 3m

Pamiętaj, że port może być inny. Kubernetes przydzielił port dla usługi i uruchomił ją. Jeśli używasz Linuksa, możesz bezpośrednio otworzyć przeglądarkę i wpisać http://10.0.0.54:9000/ip/8.8.8.8 , aby zobaczyć wynik. Jeśli używasz systemu Windows lub Mac z programem Docker Toolbox, adres IP jest lokalny dla maszyny wirtualnej, na której działa Docker, i niestety nadal jest nieosiągalny.

Chcę tutaj podkreślić, że nie jest to problem Kubernetesa, a raczej ograniczenie Docker Toolbox, które z kolei zależy od ograniczeń narzucanych przez maszyny wirtualne, takie jak VirtualBox, które działają jak komputer w innym komputerze. Aby przezwyciężyć to ograniczenie, musimy stworzyć tunel. Aby to ułatwić, dołączyłem kolejny skrypt, który otwiera tunel na dowolnym porcie, aby dotrzeć do dowolnej wdrożonej przez nas usługi. Możesz wpisać następujące polecenie:

 bin/forward-kube-local.sh akkahttp-service 9000

Zauważ, że tunel nie będzie działał w tle, musisz trzymać okno terminala otwarte tak długo, jak tego potrzebujesz i zamknąć, gdy nie potrzebujesz już tunelu. Gdy tunel jest uruchomiony, możesz otworzyć: http://localhost:9000/ip/8.8.8.8 i wreszcie zobaczyć aplikację działającą w Kubernetes.

Ostateczny dotyk: skala

Do tej pory „po prostu” umieściliśmy naszą aplikację w Kubernetes. Chociaż jest to ekscytujące osiągnięcie, nie dodaje zbyt dużej wartości do naszego wdrożenia. Uratowaliśmy się od wysiłku przesyłania i instalowania na serwerze oraz konfigurowania dla niego serwera proxy.

Tam, gdzie błyszczy Kubernetes, jest skalowanie. Możesz wdrożyć dwie, dziesięć lub sto instancji naszej aplikacji, zmieniając tylko liczbę replik w pliku konfiguracyjnym. Więc zróbmy to.

Zatrzymamy pojedynczy zasobnik i zamiast tego rozpoczniemy wdrażanie. Wykonajmy więc następujące polecenia:

 bin/kubectl delete -f kube/akkahttp-pod.yml bin/kubectl create -f kube/akkahttp-deploy.yaml

Następnie sprawdź status. Ponownie możesz spróbować kilka razy, ponieważ wdrożenie może zająć trochę czasu:

 NAME READY STATUS RESTARTS AGE akkahttp-deployment-4229989632-mjp6u 1/1 Running 0 16s akkahttp-deployment-4229989632-s822x 1/1 Running 0 16s k8s-etcd-127.0.0.1 1/1 Running 0 6d k8s-master-127.0.0.1 4/4 Running 0 6d k8s-proxy-127.0.0.1 1/1 Running 0 6d

Teraz mamy dwa kapsuły, a nie jeden. Dzieje się tak, ponieważ w podanym przeze mnie pliku konfiguracyjnym znajduje się replica: 2 , z dwoma różnymi nazwami generowanymi przez system. Nie będę wchodził w szczegóły plików konfiguracyjnych, ponieważ zakres artykułu jest po prostu wstępem dla programistów Scali do szybkiego startu w Kubernetes.

W każdym razie są teraz aktywne dwa zasobniki. Co ciekawe, usługa jest taka sama jak wcześniej. Skonfigurowaliśmy usługę tak, aby równoważyła obciążenie między wszystkimi podami oznaczonymi jako akkahttp . Oznacza to, że nie musimy ponownie wdrażać usługi, ale możemy zastąpić pojedynczą instancję repliką.

Możemy to zweryfikować, ponownie uruchamiając serwer proxy (jeśli jesteś w systemie Windows i go zamknąłeś):

 bin/forward-kube-local.sh akkahttp-service 9000

Następnie możemy spróbować otworzyć dwa okna terminala i zobaczyć logi dla każdego poda. Na przykład w pierwszym typie:

 bin/kubectl logs -f akkahttp-deployment-4229989632-mjp6u

A w drugim typie:

 bin/kubectl logs -f akkahttp-deployment-4229989632-s822x

Oczywiście edytuj wiersz poleceń zgodnie z wartościami, które masz w swoim systemie.

Teraz spróbuj uzyskać dostęp do usługi za pomocą dwóch różnych przeglądarek. Powinieneś spodziewać się, że żądania zostaną podzielone między wiele dostępnych serwerów, jak na poniższym obrazku:

Kubernety w akcji

Wniosek

Dziś ledwo zarysowaliśmy powierzchnię. Kubernetes oferuje znacznie więcej możliwości, w tym automatyczne skalowanie i ponowne uruchamianie, przyrostowe wdrożenia i woluminy. Ponadto aplikacja, której użyliśmy jako przykład, jest bardzo prosta, bezstanowa, a różne instancje nie muszą się wzajemnie znać. W prawdziwym świecie aplikacje rozproszone muszą się wzajemnie znać i zmieniać konfiguracje w zależności od dostępności innych serwerów. Rzeczywiście, Kubernetes oferuje rozproszony magazyn kluczy ( etcd ), aby umożliwić różnym aplikacjom komunikowanie się ze sobą podczas wdrażania nowych instancji. Jednak ten przykład jest celowo wystarczająco mały i uproszczony, aby pomóc Ci zacząć, skupiając się na podstawowych funkcjach. Jeśli będziesz postępować zgodnie z samouczkiem, powinieneś być w stanie uzyskać środowisko pracy dla aplikacji Scala na swoim komputerze bez pomyłki z powodu dużej liczby szczegółów i zagubienia się w złożoności.

Związane z:
  • Programowanie dla chmury w chmurze: tworzenie BigData za pomocą Dockera w AWS
  • K8s/Kubernetes: AWS vs. GCP vs. Azure
  • Porównanie sieci usług Kubernetes