JavaRush /Blog Java /Random-PL /Realizujemy wdrożenia aplikacji - „Projekt Java od A do Z...
Roman Beekeeper
Poziom 35

Realizujemy wdrożenia aplikacji - „Projekt Java od A do Z”

Opublikowano w grupie Random-PL
Cześć wszystkim. Kontynuujemy cykl artykułów na temat pisania Twojego projektu. „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 1

Sortuj gałęzie

Co ważne, aby nie zgubić się w gałęziach i ich kolejności w repozytorium, zdecydowałem się zmienić ich nazwy, dodając przedrostek STEP_{number} . Na przykład oprócz głównego mamy trzy gałęzie:
  • JRTB-0
  • JRTB-2
  • JRTB-3
Nie od razu zrozumiesz, który z nich powinien zostać wykonany. Zmienię więc ich nazwy w następujący sposób:
  • STEP_1_JRTB-0 - pierwszy krok
  • STEP_2_JRTB-2 - krok drugi
  • STEP_3_JRTB-3 - krok trzeci
I tak w kolejnych artykułach. Aby zmienić nazwę gałęzi, przejdź do strony repozytorium , znajdź pole gałęzi , podążaj za nią: „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 2Pod każdą gałęzią kliknij ołówek i zmień nazwę gałęzi: „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 3W rezultacie otrzymamy: Przy okazji „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 4, wszyscy, którzy subskrybowali mój kanał telegramu, znaleźli natychmiast dowiedziałem się, że zmieniłem nazwy oddziałów.

Trochę o Dockerze

Co to jest Docker? Krótko mówiąc, jest to narzędzie, za pomocą którego można szybko i bezpiecznie wdrażać (wdrażać) aplikacje, tworząc dla nich zamkniętą infrastrukturę, która jest im tylko niezbędna. Rozumiem, że to nadal trudne. Ogólnie Docker można rozumieć jako platformę programistyczną, na której można pracować szybko i efektywnie. Dockera można rozumieć jako program działający na serwerze. Program ten posiada możliwość przechowywania kontenerów z aplikacjami. Co to jest kontener? To osobna infrastruktura, do której możesz dodać wszystko, czego potrzebujesz. Na przykład dla aplikacji Java potrzebujemy środowiska JRE do uruchomienia aplikacji, kontener będzie to miał, będziemy potrzebować innego oprogramowania - możemy to dodać. A może potrzebujemy Linuksa i kontenera serwletów Tomcat. Można to również zrobić. Kontenery tworzone są na podstawie obrazu: czyli jest to konkretny szablon, który zawiera wszystko co niezbędne do stworzenia kontenera Docker. Jak stworzyć taki obraz? W naszym przypadku będziemy musieli utworzyć plik Dockerfile w katalogu głównym projektu opisujący, co powinno znajdować się w kontenerze. Ponieważ nie chcemy nigdzie ujawniać tokena bota, będziemy musieli uciekać się do przekazywania go za każdym razem, gdy będziemy chcieli wdrożyć aplikację. Więcej na ten temat można przeczytać tutaj i tutaj .

Piszemy JRTB-13

Musimy skonfigurować szybki i łatwy proces wdrażania naszej aplikacji na serwer. To znaczy dla maszyny, która pracuje 24 godziny na dobę, 7 dni w tygodniu. Za podstawę weźmy Dockera. Ale na naszej liście nie ma zadania, które byłoby odpowiedzialne za dodanie tej funkcjonalności. Jakoś mi tego umknęło podczas tworzenia. Nie ma problemu, stworzymy to teraz. Przejdź do zakładki tworzenia zgłoszenia w GitHubie i wybierz Prośbę o funkcję: „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 5Dodaj opis zadania, kryteria jego akceptacji, ustal, do jakiego projektu należy to zgłoszenie i możesz utworzyć nowe zgłoszenie: „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 6Teraz, aby pokazać, że zadanie zostało zaakceptowane do pracy, zmień status zadania z Do zrobienia na W toku: „Projekt Java od A do Z”: Implementacja wdrożenia aplikacji - 7To będzie trudny artykuł. Jeśli masz jakieś problemy, napisz w komentarzach: Będę je monitorować i odpowiadać na nie najlepiej jak potrafię. To będzie mała obsługa klienta :D

Tworzenie pliku Dockerfile

Co to jest plik docker? W przypadku Dockera jest to skrypt (instrukcje krok po kroku) dotyczące tworzenia obrazu dla kontenera Docker. Aby nasza aplikacja działała potrzebujemy JDK w wersji 11. Oznacza to, że musimy znaleźć obraz okna dokowanego JDK 11 i dodać go do naszego obrazu. Przypomina to sposób dodawania zależności do pamięci. Docker ma w tym celu DockerHub . Aby pobierać obrazy lokalnie, musisz się tam zarejestrować. Po rejestracji przejdźmy do szukania JDK11. Z tego, co znalazłem, jest to kontener: adoptopenjdk/openjdk11 . Opis tego kontenera zawiera informacje potrzebne do pliku dokowanego:
FROM adoptopenjdk/openjdk11:ubi
RUN mkdir /opt/app
COPY japp.jar /opt/app
CMD ["java", "-jar", "/opt/app/japp.jar"]
Naprawmy folder, z którego bierzemy plik jar. Mamy go w folderze docelowym po uruchomieniu zadania maven pakietu mvn. Zanim to wszystko zrobimy, w oparciu o zaktualizowaną gałąź główną, tworzymy nową dla naszego zadania: STEP_4_JRTB-13 . Teraz możesz pracować. W katalogu głównym projektu utwórz plik bez rozszerzenia Dockerfile i dodaj w nim następujące elementy:
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Pierwsza linia określa, na czym będzie oparty obraz - adoptopenjdk/openjdk11. Druga linia polega na dodaniu argumentu do obrazu o nazwie JAR_FILE, który znajduje się w folderze docelowym. Co więcej, bieżący folder jest określany na podstawie lokalizacji pliku Dockerfile. Trzecia linia - skopiuj słoik naszego projektu do obrazu okna dokowanego. Ostatnia linia zasadniczo zawiera tablicę utworzoną na podstawie polecenia w terminalu, oddzieloną spacją. Oznacza to, że na koniec zostanie wykonane: „java -jar /app.jar” Aby zachować token bota w tajemnicy, podczas uruchamiania kontenera będziemy musieli przekazać dwie zmienne - nazwę bota i jego token. W tym celu napiszemy zapytanie, które powinno uruchomić nasz projekt ze zmiennymi. Jak to zrobić? Musisz to sprawdzić w Google: tutaj jest pierwszy link z normalnym opisem. Co chcemy zrobić? W pliku application.properties mamy dwie zmienne, które tam definiujemy:
  • bot.nazwa użytkownika
  • bot.token
Chcę uruchomić kontener dokowany i za każdym razem przekazywać tam moją wartość, aby nikt nie mógł zobaczyć tych wartości. Wiem, że w SpringBoot zmienne środowiskowe ustawione podczas uruchamiania projektu jar będą miały pierwszeństwo przed tymi w pliku application.properties. Aby przekazać zmienną w żądaniu, należy dodać następującą konstrukcję: -D{nazwa zmiennej}=”{wartość zmiennej}” . Nie dodajemy nawiasów klamrowych ;) Otrzymamy żądanie, które uruchomi naszą aplikację z predefiniowanymi wartościami - nazwą i tokenem bota: java -jar -Dbot.username=”test.javarush.community_bot” -Dbot. token=”dfgkdjfglkdjfglkdjfgk” *.jar Teraz musimy przekazać te zmienne do kontenera dokowanego. To jest zmienna środowiskowa. Aby w przyszłości nasza baza danych działała płynnie i bezproblemowo z naszą aplikacją, zastosujemy docker-compose. Jest to osobne narzędzie, w którym można organizować pracę, uruchamianie i zależności pomiędzy kontenerami. Innymi słowy, jest to dodatek do Dockera umożliwiający zarządzanie kontenerami jednej infrastruktury. Ponadto przed uruchomieniem docker-compose musimy mieć pewność, że pobraliśmy wszystkie zmiany w kodzie z serwera, zbudowaliśmy aplikację i zatrzymaliśmy starą wersję. W tym celu użyjemy skryptu bash. Wow... To wszystko brzmi trudne, zgadzam się. Jednak praca nad konfiguracją wdrożenia aplikacji jest zawsze żmudnym i złożonym procesem. Mamy zatem całkiem niezły schemat:
  1. Uruchommy skrypt bash.
  2. Skrypt bash uruchamia polecenie docker-compose.
  3. Docker-compose uruchamia kontener dokowany z naszą aplikacją.
  4. Kontener Docker uruchamia naszą aplikację.
I teraz musimy się upewnić, że dwie zmienne – nazwa bota i jego token – przejdą z punktu 1 do punktu 4. I tak, aby te dwie zmienne zostały wykorzystane podczas uruchamiania naszej aplikacji Java. Przejdźmy od końca do początku. Wiemy już, jakie polecenie należy wykonać, aby uruchomić jarnik. Dlatego skonfigurujemy plik Dockerfile tak, aby nauczył się akceptować dwie zmienne i przekazywać je do żądania. Aby to zrobić, zredukujmy plik Dockerfile do następującej postaci:
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}", "-jar", "/app.jar"]
Widać, że dodaliśmy dwie linie i zaktualizowaliśmy ENTRYPOINT. Linie:
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
zadeklaruj zmienne w pliku kodera. Domyślnie mają określoną wartość. Jeśli podczas tworzenia obrazu z tego pliku dokowanego zostaną przekazane zmienne środowiskowe o takich nazwach, wartości będą inne. W ENTRYPOINT dodaliśmy jeszcze kilka elementów, które będą czytać te zmienne środowiskowe:
"-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}"
Tutaj widać, że wewnątrz linii za pomocą konstrukcji ${} zostaną przekazane wartości BOT_NAME i BOT_TOKEN. Następnie musimy nauczyć się odbierać i przekazywać te zmienne do narzędzia docker-compose.

Utwórz plik docker-compose.yml

Dobrze byłoby, gdybyś przeczytał o formacie YAML osobno, w przeciwnym razie artykuł już rozrasta się skokowo. Dla nas jest to po prostu kolejny opis zmiennych typu .properties. Tylko we właściwościach jest to zapisane przez kropkę, ale w YAML robi się to trochę ładniej. Na przykład tak. Dwie zmienne w .properties: javarush.telegram.bot.name=ivan javarush.telegram.bot.token=pupkin Ale w .yaml (tak samo jak .yml) będzie to wyglądało tak:
javarush:
	telegram:
		bot:
		  name: ivan
		  token: pupkin
Druga opcja jest piękniejsza i zrozumiała. Odstępy powinny być dokładnie takie, jak wskazano powyżej. Przetłumaczmy jakoś nasze application.properties i application.yml. Najpierw musisz go stworzyć. W katalogu głównym projektu utwórz plik docker-compose.yml i wpisz tam:
version: '3.1'

services:
 jrtb:
   build:
     context: .
   environment:
     - BOT_NAME=${BOT_NAME}
     - BOT_TOKEN=${BOT_TOKEN}
   restart: always
Pierwsza linia to wersja docker-compose. Services: mówi, że wszystkie kolejne wiersze (zostaną przesunięte) odnoszą się do usług, które konfigurujemy. Jak dotąd mamy tylko jedną taką aplikację - aplikację Java o nazwie jrtb . I już pod nim będą wszystkie jego ustawienia. Na przykład build: kontekst: . mówi, że będziemy szukać pliku Dockerfile w tym samym katalogu co docker-compose.yml. Jednak sekcja środowiskowa: będzie odpowiedzialna za zapewnienie przekazania niezbędnych zmiennych środowiskowych do pliku Dockerfile. Tylko to, czego potrzebujemy. Dlatego poniżej przekazujemy zmienne. Docker-compose będzie ich szukać w zmiennych środowiskowych serwera operacyjnego. Dodajmy je do skryptu bash.

Tworzenie skryptów basha

Ostatnim krokiem jest utworzenie skryptu bash. Utwórz plik o nazwie start.sh w katalogu głównym projektu i wpisz tam:
#!/bin/bash

# Pull new changes
git pull

# Prepare Jar
mvn clean
mvn package

# Ensure, that docker-compose stopped
docker-compose stop

# Add environment variables
export BOT_NAME=$1
export BOT_TOKEN=$2

# Start new deployment
docker-compose up --build -d
Pierwsza linia jest potrzebna dla wszystkich skryptów basha: bez niej nie będzie działać. A potem - tylko zestaw poleceń w terminalu, które należy wykonać. Dodałem komentarze do każdego polecenia, więc powinno być jasne. Jedyne, co chcę wyjaśnić, to co oznaczają 1 dolar i 2 dolary. Są to dwie zmienne, które zostaną przekazane po uruchomieniu skryptu bash. Za pomocą polecenia eksportu zostaną one dodane do zmiennych serwera i odczytane w programie docker-compose. Działa to w przypadku Ubuntu, prawdopodobnie nie w przypadku Windows, ale nie jestem pewien. Teraz musisz dodać skrypt stop.sh, który zatrzyma pracę. Będzie zawierał kilka linii:
#!/bin/bash

# Ensure, that docker-compose stopped
docker-compose stop

# Ensure, that the old application won't be deployed again.
mvn clean
W tym miejscu zatrzymujemy tworzenie dokera i sprzątamy jarnik projektu, który leżał od ostatniej kompilacji. Robimy to po to, aby mieć pewność, że nasz projekt zostanie poprawnie odbudowany. Były precedensy, dlatego dodaję) W rezultacie otrzymujemy 4 nowe pliki:
  • Dockerfile – plik umożliwiający utworzenie obrazu naszej aplikacji;
  • docker-compose.yml - plik z ustawieniami dotyczącymi sposobu uruchamiania naszych kontenerów;
  • start.sh - skrypt bashowy do wdrożenia naszej aplikacji;
  • stop.sh to skrypt basha zatrzymujący naszą aplikację.
Zaktualizujemy także wersję naszej aplikacji z 0.2.0-SNAPSHOT na 0.3.0-SNAPSHOT. Dodajmy opis nowej wersji do RELEASE_NOTES i delikatnie zrefaktoryzujmy to, co tam było:
# Informacje o wydaniu ## 0.3.0-SNAPSHOT * JRTB-13: dodano proces wdrażania do projektu ## 0.2.0-SNAPSHOT * JRTB-3: zaimplementowano Wzorzec poleceń do obsługi poleceń Telegram Bot ## 0.1.0-SNAPSHOT * JRTB -2: dodano bota telegramowego * JRTB-0: dodano projekt szkieletu SpringBoot
A w README dodamy nowy akapit opisujący sposób wdrożenia naszej aplikacji:
## Wdrożenie Proces wdrażania tak prosty, jak to możliwe: Wymagane oprogramowanie: - terminal do uruchamiania skryptów bash - docker - docker-compose w celu wdrożenia aplikacji, przejdź do potrzebnej gałęzi i uruchom skrypt bash: $ bash start.sh ${bot_username} ${bot_token } To wszystko.
Oczywiście wszystko jest napisane w języku angielskim. Jak zwykle w naszej nowo utworzonej gałęzi STEP_4_JRTB-13 tworzymy nowy commit o nazwie: JRTB-13: zaimplementuj proces wdrażania poprzez okno dokowane i wypchnij go. Przestaję szczegółowo rozwodzić się nad rzeczami, które opisałem już w poprzednich artykułach. Nie widzę sensu powtarzania tego samego. Poza tym ci, którzy to wymyślili i sami to zrobili, nie będą mieli żadnych pytań. To ja mówię o tym, jak utworzyć nową gałąź, jak utworzyć zatwierdzenie, jak wypchnąć zatwierdzenie do repozytorium.

Konkluzja

Dzisiaj pokazałem mnóstwo nowych informacji, które należy dokładnie rozważyć i rozszerzyć o dodatkową lekturę. Najważniejsze: za pomocą JEDNEGO (!!!) polecenia wykonamy wszystko, co niezbędne do wdrożenia naszej aplikacji. To jest tak fajne, że nawet nie mogę ci tego powiedzieć. Tak, musiałem spędzić przyzwoitą ilość czasu w dokumentacji Dockera, aby zrozumieć, jak poprawnie przekazywać zmienne. Od tej chwili bot telegramu będzie zawsze działał na najnowszej wersji gałęzi głównej . Link do bota telegramu. Dziś nie będzie linków do materiałów, które warto przeczytać: odpowiedzialność spoczywa na Was. Musisz nauczyć się szukać informacji. Każdy, kto zasubskrybował mój kanał telegramowy, niemal natychmiast dowiedział się o wdrożeniu bota. Kochani, podoba Wam się projekt? Daj mu gwiazdkę ! W ten sposób stanie się ona bardziej popularna i więcej osób będzie mogło się o niej dowiedzieć i uczyć się z niej. Tradycyjnie proponuję zarejestrować się na GitHubie i obserwować moje konto , aby śledzić tę serię i inne moje projekty, nad którymi tam pracuję. Teraz jesteśmy gotowi do podłączenia bazy danych. Następny artykuł będzie dłuższy iw nim zrobimy wszystko co niezbędne do pracy z bazą danych. Wszystkie opisy znajdują się w JRTB-1 .

Lista wszystkich materiałów wchodzących w skład serii znajduje się na początku artykułu.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION