Wdróż w Google Kubernetes Engine aplikację mikronauty skonteneryzowaną przy użyciu Jib

1. Przegląd

Informacje o Micronaut

Micronaut to nowoczesna platforma typu full-stack oparta na JVM, która umożliwia tworzenie modułowych, łatwych do testowania mikroserwisów i aplikacji bezserwerowych. Micronaut ma zapewniać krótki czas uruchamiania, dużą przepustowość i minimalne wykorzystanie pamięci. Deweloperzy mogą tworzyć aplikacje za pomocą Micronaut w językach Java, Groovy lub Kotlin.

Micronaut zapewnia:

  • Krótki czas uruchamiania i niskie zużycie pamięci – platformy IoC oparte na odbiciu wczytują i buforują dane odbicia dla każdego pola, metody i konstruktora w kodzie, natomiast w przypadku Micronaut czas uruchamiania aplikacji i zużycie pamięci nie są powiązane z rozmiarem bazy kodu.
  • Deklaratywny, reaktywny klient HTTP czasu kompilacji – deklaratywne tworzenie reaktywnych klientów HTTP, którzy są implementowani w czasie kompilacji, co zmniejsza zużycie pamięci.
  • Nieblokujący serwer HTTP oparty na Netty – serwer HTTP Micronaut ma prostą krzywą uczenia się, dzięki czemu maksymalnie ułatwia udostępnianie interfejsów API, które mogą być używane przez klientów HTTP.
  • Szybkie i łatwe testowanie – łatwo uruchamiaj serwery i klientów w testach jednostkowych i przeprowadzaj je natychmiast.
  • Wydajne wstrzykiwanie zależności w czasie kompilacji i programowanie zorientowane na aspekty – Micronaut udostępnia prosty interfejs API programowania zorientowanego na aspekty w czasie kompilacji, który nie korzysta z odbicia.
  • Twórz w pełni reaktywne i nieblokujące aplikacje – Micronaut obsługuje wszystkie platformy, które implementują Reactive Streams, w tym RxJava i Reactor.

Więcej informacji znajdziesz na stronie Micronaut.

Informacje o Kubernetes

Kubernetes to projekt typu open source, który może działać w wielu różnych środowiskach, od laptopów po klastry wielowęzłowe o wysokiej dostępności, od chmur publicznych po wdrożenia lokalne, od maszyn wirtualnych po sprzęt fizyczny.

W tym module wdrożysz prosty mikroserwis Micronaut oparty na Groovy w Kubernetes działającym w Kubernetes Engine.

Celem tych ćwiczeń z programowania jest uruchomienie mikroserwisu jako replikowanej usługi działającej w Kubernetes. Kod opracowany na komputerze przekształcasz w obraz kontenera Dockera, a następnie uruchamiasz ten obraz w Kubernetes Engine.

Aby ułatwić Ci zrozumienie, jak poszczególne elementy łączą się ze sobą, przedstawiamy diagram różnych części tego laboratorium. Korzystaj z niej w trakcie wykonywania ćwiczeń. Wszystko powinno stać się jasne, gdy dotrzesz do końca (ale na razie możesz to zignorować).

Kubernetes Codelab Diagram 1 (2).png

Na potrzeby tego laboratorium użycie zarządzanego środowiska, takiego jak Kubernetes Engine (wersja Kubernetes hostowana przez Google i działająca w Compute Engine), pozwala skupić się na korzystaniu z Kubernetes, a nie na konfigurowaniu infrastruktury bazowej.

Jeśli chcesz uruchomić Kubernetes na komputerze lokalnym, np. na laptopie deweloperskim, prawdopodobnie zainteresuje Cię Minikube. Umożliwia to proste skonfigurowanie klastra Kubernetes z 1 węzłem na potrzeby programowania i testowania. Jeśli chcesz, możesz skorzystać z Minikube, aby przejść ten samouczek.

Informacje o Jib

Jib to narzędzie open source, które umożliwia tworzenie obrazów Dockera i OCI dla aplikacji Java. Jest dostępna jako wtyczka do Maven i Gradle oraz jako biblioteka Java.

Jib ma być:

  • Szybkie – szybkie wdrażanie zmian. Jib dzieli aplikację na kilka warstw, oddzielając zależności od klas. Nie musisz już czekać, aż Docker ponownie utworzy całą aplikację Java – wystarczy wdrożyć zmienione warstwy.
  • Powtarzalność – ponowne utworzenie obrazu kontenera z tą samą zawartością zawsze generuje ten sam obraz. Już nigdy nie wywołasz niepotrzebnej aktualizacji.
  • Bez demona – zmniejsz zależności interfejsu wiersza poleceń. Skompiluj obraz Dockera w Maven lub Gradle i prześlij go do dowolnego rejestru. Nie musisz już pisać plików Dockerfile ani wywoływać poleceń docker build/push.

Więcej informacji o Jib znajdziesz na stronie projektu na GitHubie.

Informacje o tym samouczku

W tym samouczku używany jest przykładowy kod z narzędzia Jib do tworzenia kontenerów dla aplikacji w Javie.

Przykładowa usługa to prosta usługa hello world, która korzysta z frameworka Micronaut i języka programowania Apache Groovy.

Czego się nauczysz

  • Jak spakować prostą aplikację w Javie jako kontener Dockera za pomocą Jib
  • Jak utworzyć klaster Kubernetes w Kubernetes Engine.
  • Jak wdrożyć usługę Micronaut w Kubernetes w Kubernetes Engine
  • Jak skalować w górę usługę i wdrażać uaktualnienia.
  • Jak uzyskać dostęp do graficznego panelu Kubernetes.

Czego potrzebujesz

  • Projekt Google Cloud Platform
  • przeglądarka, np. Chrome lub Firefox;
  • Znajomość standardowych edytorów tekstu systemu Linux, takich jak Vim, EMACS lub Nano.

Jak zamierzasz korzystać z tego samouczka?

Tylko przeczytaj Przeczytaj i wykonaj ćwiczenia

Jak oceniasz swoje doświadczenie w tworzeniu aplikacji internetowych w HTML/CSS?

Początkujący Średnio zaawansowany Zaawansowany

Jak oceniasz korzystanie z usług Google Cloud Platform?

Początkujący Średnio zaawansowany Zaawansowany

2. Konfiguracja i wymagania

Samodzielne konfigurowanie środowiska

  1. Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. (Jeśli nie masz jeszcze konta Gmail lub G Suite, musisz je utworzyć).

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Zapamiętaj identyfikator projektu, czyli unikalną nazwę we wszystkich projektach Google Cloud (podana powyżej nazwa jest już zajęta i nie będzie działać w Twoim przypadku). W dalszej części tego laboratorium będzie on nazywany PROJECT_ID.

  1. Następnie musisz włączyć rozliczenia w konsoli Cloud, aby korzystać z zasobów Google Cloud.

Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Wykonaj instrukcje z sekcji „Czyszczenie”, w której znajdziesz informacje o tym, jak wyłączyć zasoby, aby uniknąć naliczenia opłat po zakończeniu tego samouczka. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.

3. Pobieranie przykładowego kodu źródłowego Micronaut

Po uruchomieniu Cloud Shell możesz użyć wiersza poleceń, aby sklonować przykładowy kod źródłowy w katalogu głównym i przejść do katalogu zawierającego przykładową usługę:

$ git clone https://github.com/GoogleContainerTools/jib.git
$ cd jib/examples/micronaut/

4. Szybki podgląd kodu

Nasz prosty serwis Micronaut składa się z kontrolera, który wyświetla słynny komunikat Hello World:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello World"
    }
}

HelloController kontroler odpowiada na żądania w ścieżce /hello, a metoda index() akceptuje żądania HTTP GET.

Dostępna jest też klasa testowa Spock, która sprawdza, czy na wyjściu pojawia się prawidłowy komunikat.

class HelloControllerSpec extends Specification {
    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer)

    @Shared
    @AutoCleanup
    RxHttpClient client = embeddedServer.applicationContext.createBean(RxHttpClient, embeddedServer.getURL()) 

    void "test hello world response"() {
        when:
        HttpRequest request = HttpRequest.GET('/hello')
        String rsp  = client.toBlocking().retrieve(request)

        then:
        rsp == "Hello World"
    }
}

To nie jest zwykły test jednostkowy. W tym przypadku uruchamiany jest ten sam stos serwera Micronaut (oparty na platformie Netty), który jest używany w środowisku produkcyjnym. Działanie kodu w usłudze będzie takie samo jak w testach.

Aby uruchomić testy i sprawdzić, czy wszystko działa prawidłowo, możesz uruchomić to polecenie:

./gradlew test

5. Lokalne uruchamianie aplikacji

Usługę Micronaut możesz uruchomić w normalny sposób za pomocą tego polecenia Gradle:

$ ./gradlew run

Po uruchomieniu aplikacji możesz otworzyć dodatkową instancję Cloud Shell, klikając małą ikonę +, a następnie sprawdzić za pomocą polecenia curl, czy otrzymujesz oczekiwane dane wyjściowe:

$ curl localhost:8080/hello

Powinien wyświetlić się prosty komunikat „Hello World”.

6. Pakowanie aplikacji jako kontenera Dockera za pomocą Jib

Następnie przygotuj aplikację do uruchomienia w Kubernetes. W tym celu wykorzystamy Jib, który wykona za nas całą pracę, ponieważ nie będziemy musieli sami tworzyć pliku Dockerfile.

Uruchommy polecenie, aby utworzyć kontener:

$ ./gradlew jibDockerBuild

Oto dane wyjściowe, które powinny się wyświetlić:

Tagging image with generated image reference micronaut-jib:0.1. If you'd like to specify a different tag, you can set the jib.to.image parameter in your build.gradle, or use the --im
age=<MY IMAGE> commandline flag.

Containerizing application to Docker daemon as micronaut-jib:0.1...
warning: Base image 'gcr.io/distroless/java' does not use a specific image digest - build may not be reproducible
Getting base image gcr.io/distroless/java...
Building dependencies layer...
Building resources layer...
Building classes layer...
Finalizing...

Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, example.micronaut.Application]
Loading to Docker daemon...

Built image to Docker daemon as micronaut-jib:0.1

Teraz, gdy obraz został utworzony, sprawdźmy, czy widzimy nasz przyjazny komunikat powitalny. W tym celu uruchommy obraz Dockera na pierwszej karcie Cloud Shell:

$ docker run -it -p 8080:8080 micronaut-jib:0.1
16:57:20.255 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [cloud, gcp]
16:57:23.203 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 2926ms. Server Running: http://97b7d76ccf3f:8080

Usługa działa, więc w drugiej karcie Cloud Shell możemy uruchomić polecenie curl, aby sprawdzić, czy działa zgodnie z oczekiwaniami:

$ curl localhost:8080/hello
Hello World

Aby zatrzymać kontener, w Cloud Shell naciśnij Ctrl+C.

7. przekazywanie skonteneryzowanej usługi do rejestru;

Teraz, gdy obraz działa zgodnie z oczekiwaniami, możesz przesłać go do Google Container Registry, czyli prywatnego repozytorium obrazów Dockera dostępnego z każdego projektu w chmurze Google (ale też spoza Google Cloud Platform).

Zanim będzie można przesłać obraz do rejestru, upewnijmy się, że Container Registry jest włączony w naszym projekcie. W tym celu kliknij Narzędzia > Container Registry. Jeśli nie jest włączony, zobaczysz to okno. Kliknij „Włącz interfejs Container Registry API”, aby go włączyć:

ac812e6260ac7dfb.png

Gdy rejestr będzie gotowy, aby przesłać obraz do rejestru, uruchom te polecenia:

$ gcloud auth configure-docker
$ docker tag micronaut-jib:0.1 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

Powyższe polecenia umożliwiają pakietowi SDK gcloud skonfigurowanie i autoryzowanie Dockera do wypychania obrazów do instancji Container Registry, otagowanie obrazu w celu wskazania jego lokalizacji w rejestrze, a następnie wypchnięcie go do rejestru.

Jeśli wszystko przebiegnie pomyślnie, po chwili obraz kontenera powinien być widoczny w konsoli: Narzędzia > Container Registry. W tym momencie masz już dostępny obraz Dockera w całym projekcie, do którego Kubernetes może uzyskać dostęp i którym może zarządzać, co zobaczysz za kilka minut.

12224c4e42183b4e.png

8. Tworzenie klastra

Możesz już utworzyć klaster Kubernetes Engine. Zanim to zrobisz, otwórz sekcję Google Kubernetes Engine w konsoli internetowej i poczekaj, aż system się zainicjuje (powinno to zająć tylko kilka sekund).

20c0587c0108b8ba.png

Klaster składa się z serwera Kubernetes Master API zarządzanego przez Google i zestawu węzłów roboczych. Węzły robocze to maszyny wirtualne Compute Engine. Użyj interfejsu gcloud CLI w sesji Cloud Shell, aby utworzyć klaster z 2 węzłami n1-standard-1 (wykonanie tego kroku może potrwać kilka minut):

$ gcloud container clusters create hello-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

Na koniec powinien pojawić się utworzony klaster.

Creating cluster hello-cluster in us-central1-c...done.
Created [https://container.googleapis.com/v1/projects/mn-gke-test/zones/us-central1-c/clusters/hello-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-c/hello-cluster?project=mn-gke-test
kubeconfig entry generated for hello-cluster.
NAME           LOCATION       MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
hello-cluster  us-central1-c  1.9.7-gke.7     35.239.224.115  n1-standard-1  1.9.7-gke.7   2          RUNNING

Powinien być teraz dostępny w pełni funkcjonalny klaster Kubernetes obsługiwany przez Google Kubernetes Engine:

d9e1e314769753e7.png

Czas wdrożyć własną skonteneryzowaną aplikację w klastrze Kubernetes. Od teraz będziesz używać wiersza poleceń kubectl (jest on już skonfigurowany w środowisku Cloud Shell). W pozostałej części tego modułu wymagane jest, aby wersja klienta i serwera Kubernetes była co najmniej 1.2. kubectl version wyświetli aktualną wersję polecenia.

9. Wdrażanie aplikacji w Kubernetes

Wdrożenie Kubernetes może tworzyć wiele instancji aplikacji, zarządzać nimi i je skalować za pomocą utworzonego właśnie obrazu kontenera. Utwórzmy wdrożenie aplikacji w Kubernetes za pomocą polecenia kubectl create deployment:

$ kubectl create deployment hello-micronaut \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

Aby wyświetlić właśnie utworzone wdrożenie, uruchom to polecenie:

$ kubectl get deployments
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   1         1         1            1           5m

Aby wyświetlić instancje aplikacji utworzone przez wdrożenie, uruchom to polecenie:

$ kubectl get pods
NAME                               READY     STATUS    RESTARTS   AGE
hello-micronaut-5647fb98c5-lh5h7   1/1       Running   0          5m

W tym momencie kontener powinien działać pod kontrolą Kubernetes, ale nadal musisz udostępnić go do użytku publicznego.

10. Zezwalaj na ruch zewnętrzny

Domyślnie pod jest dostępny tylko przez wewnętrzny adres IP w klastrze. Aby kontener hello-micronaut był dostępny spoza wirtualnej sieci Kubernetes, musisz udostępnić poda jako usługę Kubernetes.

W Cloud Shell możesz udostępnić poda w publicznym internecie za pomocą polecenia kubectl expose w połączeniu z flagą --type=LoadBalancer. Ta flaga jest wymagana do utworzenia adresu IP dostępnego z zewnątrz :

$ kubectl expose deployment hello-micronaut --type=LoadBalancer --port=8080

Flaga użyta w tym poleceniu określa, że będziesz używać systemu równoważenia obciążenia udostępnianego przez infrastrukturę bazową (w tym przypadku systemu równoważenia obciążenia Compute Engine). Pamiętaj, że udostępniasz wdrożenie, a nie bezpośrednio poda. Spowoduje to, że usługa będzie równoważyć obciążenie we wszystkich podach zarządzanych przez wdrożenie (w tym przypadku tylko 1 pod, ale później dodasz więcej replik).

Węzeł główny Kubernetes tworzy system równoważenia obciążenia oraz powiązane reguły przekierowania Compute Engine, pule docelowe i reguły zapory, aby usługa była w pełni dostępna spoza Google Cloud Platform.

Aby znaleźć publicznie dostępny adres IP usługi, po prostu poproś kubectl o wyświetlenie listy wszystkich usług klastra:

$ kubectl get services
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
hello-micronaut   LoadBalancer   10.39.243.251   aaa.bbb.ccc.ddd 8080:30354/TCP   1m
kubernetes        ClusterIP      10.39.240.1     <none>          443/TCP          31m

Zwróć uwagę, że w przypadku Twojej usługi są wymienione 2 adresy IP, które obsługują port 8080. Jeden to wewnętrzny adres IP widoczny tylko w Twojej wirtualnej sieci w chmurze, a drugi to zewnętrzny adres IP z równoważeniem obciążenia. W tym przykładzie zewnętrzny adres IP to aaa.bbb.ccc.ddd.

Usługa powinna być teraz dostępna pod tym adresem: http://<EXTERNAL_IP>:8080/hello

11. Skalowanie w górę usługi

Jedną z najważniejszych funkcji Kubernetes jest łatwość skalowania aplikacji. Załóżmy, że nagle potrzebujesz większej mocy obliczeniowej dla aplikacji. Wystarczy, że poinformujesz kontroler replikacji, aby zarządzał nową liczbą replik instancji aplikacji:

$ kubectl scale deployment hello-micronaut --replicas=3
deployment.extensions "hello-micronaut" scaled

$ kubectl get deployment
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   3         3         3            3           16m

Zwróć uwagę na podejście deklaratywne – zamiast uruchamiać lub zatrzymywać nowe instancje deklarujesz, ile instancji powinno działać przez cały czas. Pętle uzgadniania Kubernetes po prostu sprawdzają, czy rzeczywistość jest zgodna z Twoimi żądaniami, i w razie potrzeby podejmują odpowiednie działania.

12. Wdrażanie uaktualnienia usługi

W pewnym momencie aplikacja wdrożona w środowisku produkcyjnym będzie wymagać poprawek lub dodatkowych funkcji. Kubernetes pomoże Ci wdrożyć nową wersję w środowisku produkcyjnym bez wpływu na użytkowników.

Najpierw zmodyfikujemy aplikację. Otwórz edytor kodu w Cloud Shell.

5aee8f3d1e003571.png

Otwórz /jib/examples/micronaut/src/main/groovy/example/micronaut/HelloController.groovy i zmień wartość odpowiedzi:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello Kubernetes World"
    }
}

/jib/examples/micronaut/build.gradle uaktualnimy wersję obrazu z 0.1 do 0.2, zmieniając ten wiersz:

version '0.2'

Następnie ponownie skompiluj i spakuj aplikację z najnowszymi zmianami:

$ ./gradlew jibDockerBuild

Dodaj tag do obrazu i prześlij go do rejestru obrazów kontenerów:

$ docker tag micronaut-jib:0.2 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

Kubernetes może teraz bezproblemowo zaktualizować kontroler replikacji do nowej wersji aplikacji. Aby zmienić etykietę obrazu uruchomionego kontenera, musisz edytować istniejący plik hello-micronaut deployment i zmienić obraz z gcr.io/PROJECT_ID/micronaut-jib:0.1 na gcr.io/PROJECT_ID/micronaut-jib:0.2.

Możesz użyć polecenia kubectl set image, aby poprosić Kubernetes o wdrożenie nowej wersji aplikacji w całym klastrze po jednej instancji naraz za pomocą aktualizacji kroczącej:

$ kubectl set image deployment/hello-micronaut \
          micronaut-jib=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

deployment.apps "hello-micronaut" image updated

Sprawdź ponownie adres http://EXTERNAL_IP:8080, aby upewnić się, że zwraca nową odpowiedź.

13. Wycofaj zmiany

Ups – czy w nowej wersji aplikacji wystąpił błąd? Być może nowa wersja zawiera błąd i musisz szybko przywrócić poprzednią. Dzięki Kubernetes możesz łatwo wycofać zmiany do poprzedniego stanu. Przywróćmy aplikację, uruchamiając to polecenie:

$ kubectl rollout undo deployment/hello-micronaut

Jeśli spojrzysz na wynik działania usługi, zobaczysz początkowy komunikat „Hello World”.

14. Podsumowanie

W tym kroku skonfigurowaliśmy prostą usługę Micronaut hello world opartą na Apache Groovy i uruchomiliśmy ją bezpośrednio w Cloud Shell, spakowaliśmy ją jako kontener za pomocą Jib i wdrożyliśmy w Google Kubernetes Engine.

15. Gratulacje!

Dowiedzieliśmy się, jak utworzyć i wdrożyć nowy mikroserwis internetowy Apache Groovy / Micronaut w Kubernetes w Google Kubernetes Engine.

Więcej informacji

Licencja

To zadanie jest licencjonowane na podstawie ogólnej licencji Creative Commons Attribution 2.0.