JavaRush /Java Blog /Random-IT /Realizziamo il deploy di applicazioni - "Progetto Java da...
Roman Beekeeper
Livello 35

Realizziamo il deploy di applicazioni - "Progetto Java dalla A alla Z"

Pubblicato nel gruppo Random-IT
Ciao a tutti. Continuiamo la serie di articoli sulla scrittura del tuo progetto. “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 1

Ordina i rami

Dell'importanza, per non perdermi nei rami e nel loro ordine nel repository, ho deciso di rinominarli aggiungendo il prefisso STEP_{numero} . Ad esempio abbiamo tre rami oltre a quello principale:
  • JRTB-0
  • JRTB-2
  • JRTB-3
Non capirai immediatamente quale dovrebbe andare e dopo quale. Quindi li rinominerò come segue:
  • STEP_1_JRTB-0 - primo passo
  • STEP_2_JRTB-2 - secondo passaggio
  • STEP_3_JRTB-3 - terzo passaggio
E così via per i prossimi articoli. Per rinominare i rami, vai alla pagina del repository , trova la casella dei rami , seguila: “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 2Sotto ogni ramo, fai clic sulla matita e rinomina il ramo: “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 3E come risultato otteniamo: “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 4A proposito, tutti coloro che si sono iscritti al mio canale Telegram hanno trovato fuori subito che ho rinominato i rami.

Un po' di Docker

Cos'è Docker? In breve, è uno strumento con cui è possibile distribuire (deploy) applicazioni in modo rapido e sicuro, creando per loro un'infrastruttura chiusa, necessaria solo a loro. È ancora difficile, lo capisco. In generale, Docker può essere inteso come una piattaforma di sviluppo in cui è possibile lavorare in modo rapido ed efficiente. Docker può essere inteso come un programma che viene eseguito su un server. Questo programma ha la capacità di archiviare contenitori con applicazioni. Cos'è un contenitore? Questa è un'infrastruttura separata in cui puoi aggiungere tutto ciò di cui hai bisogno. Ad esempio, per un'applicazione Java abbiamo bisogno di un JRE per eseguire l'applicazione, il contenitore avrà questo, avremo bisogno di altro software: possiamo aggiungere questo. O forse abbiamo bisogno di Linux e di un contenitore servlet Tomcat. Anche questo può essere fatto. I contenitori vengono creati in base all'immagine: si tratta cioè di un template specifico in cui è scritto tutto il necessario per creare un contenitore Docker. Come creare questa immagine? Nel nostro caso, dovremo creare un Dockerfile alla radice del progetto che descriva cosa dovrebbe esserci nel contenitore. Dato che non vogliamo esporre il token del bot da nessuna parte, dovremo ricorrere a passarlo ogni volta che vogliamo distribuire l'applicazione. Puoi leggere di più su questo argomento qui e qui .

Scriviamo JRTB-13

Dobbiamo impostare un processo di distribuzione rapido e semplice per la nostra applicazione sul server. Cioè, per una macchina che funziona 24 ore su 24, 7 giorni su 7. Prendiamo Docker come base. Ma nel nostro elenco non è presente alcuna attività responsabile dell'aggiunta di questa funzionalità. In qualche modo mi è mancato durante la creazione. Nessun problema, lo creeremo ora. Vai alla scheda di creazione del problema su GitHub e seleziona Richiesta di funzionalità: “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 5aggiungi una descrizione dell'attività, i criteri per la sua accettazione, imposta a quale progetto appartiene questo problema e puoi creare un nuovo problema: “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 6Ora, per mostrare che l'attività è stata accettata per lavoro, modifica lo stato dell'attività da Da fare a In corso: “Progetto Java dalla A alla Z”: implementazione della distribuzione dell'applicazione - 7questo sarà un articolo difficile. Se hai problemi, scrivi nei commenti: li monitorerò e risponderò al meglio delle mie capacità. Questa sarà una piccola Assistenza Clienti :D

Creazione di un Dockerfile

Cos'è un dockerfile? Per Docker, si tratta di uno script (istruzioni dettagliate) su come creare un'immagine per un contenitore Docker. Affinché la nostra applicazione funzioni, abbiamo bisogno del JDK, versione 11. Cioè, dobbiamo trovare l'immagine docker JDK 11 e aggiungerla alla nostra immagine. Questo è qualcosa di simile al modo in cui aggiungiamo una dipendenza a un ricordo. Docker dispone di DockerHub per questo scopo . Per scaricare le immagini localmente, è necessario registrarsi lì. Dopo la registrazione andiamo a cercare JDK11. Da quello che ho trovato, questo è il contenitore: adoptopenjdk/openjdk11 . La descrizione di questo contenitore contiene ciò che è necessario per il dockerfile:
FROM adoptopenjdk/openjdk11:ubi
RUN mkdir /opt/app
COPY japp.jar /opt/app
CMD ["java", "-jar", "/opt/app/japp.jar"]
Sistemiamo la cartella da cui prendiamo il file jar. Lo abbiamo nella cartella di destinazione dopo aver eseguito l'attività maven del pacchetto mvn. Prima di fare tutto questo, in base al ramo principale aggiornato, ne creiamo uno nuovo per il nostro compito: STEP_4_JRTB-13 . Ora puoi lavorare. Nella root del progetto, crea un file senza l' estensione Dockerfile e aggiungi quanto segue al suo interno:
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
La prima riga indica su cosa si baserà l'immagine: adoptopenjdk/openjdk11. La seconda riga consiste nell'aggiungere un argomento all'immagine denominata JAR_FILE, che si trova nella cartella di destinazione. Inoltre, la cartella corrente è determinata dalla posizione del Dockerfile. Terza riga: copia il jar del nostro progetto nell'immagine della finestra mobile. L'ultima riga contiene essenzialmente un array creato dal comando nel terminale, separato da uno spazio. Cioè, alla fine verrà eseguito quanto segue: "java -jar /app.jar" Per mantenere segreto il token del bot, all'avvio del contenitore dovremo passare due variabili: il nome del bot e il suo token. Per fare ciò, scriveremo una query che dovrebbe avviare il nostro progetto con variabili. E come si fa? Bisogna cercarlo su Google: ecco il primo link con una descrizione normale. Cosa vogliamo fare? Abbiamo due variabili nel file application.properties che definiamo lì:
  • bot.nomeutente
  • bot.token
Voglio eseguire un contenitore docker e passare lì il mio valore ogni volta in modo che nessuno possa vedere questi valori. So che in SpringBoot, le variabili di ambiente impostate all'avvio del progetto jar avranno la precedenza su quelle nel file application.properties. Per passare una variabile in una richiesta, è necessario aggiungere la seguente costruzione: -D{nome variabile}="{valore variabile}" . Non aggiungiamo parentesi graffe ;) Riceveremo una richiesta che avvierà la nostra applicazione con valori predefiniti - il nome e il token del bot: java -jar -Dbot.username=”test.javarush.community_bot” -Dbot. token=”dfgkdjfglkdjfglkdjfgk” *.jar Ora dobbiamo passare queste variabili all'interno del contenitore docker. Questa è una variabile d'ambiente. Per garantire che in futuro il nostro database funzioni senza intoppi e senza problemi con la nostra applicazione, utilizzeremo docker-compose. Si tratta di uno strumento separato in cui è possibile organizzare il lavoro, l'avvio e le dipendenze tra i contenitori. In altre parole, è un componente aggiuntivo di Docker per gestire i contenitori di un'infrastruttura. Inoltre, prima di eseguire docker-compose, dobbiamo essere sicuri di aver effettuato tutte le modifiche al codice dal server, creato l'applicazione e interrotto la vecchia versione. Per questo utilizzeremo uno script bash. Wow... Sembra tutto difficile, sono d'accordo. Ma lavorare con la configurazione della distribuzione delle applicazioni è sempre un processo noioso e complesso. Pertanto, abbiamo uno schema abbastanza buono:
  1. Eseguiamo lo script bash.
  2. Lo script bash esegue docker-compose.
  3. Docker-compose avvia un contenitore docker con la nostra applicazione.
  4. Il contenitore Docker esegue la nostra applicazione.
E ora dobbiamo assicurarci che due variabili - il nome del bot e il suo token - vadano dal punto 1 al punto 4. E in modo che queste due variabili vengano utilizzate quando si avvia la nostra applicazione Java. Andiamo dalla fine all'inizio. Sappiamo già quale comando deve essere eseguito per avviare jarnik. Pertanto configureremo il Dockerfile in modo che impari ad accettare due variabili e a passarle alla richiesta. Per fare ciò riduciamo il Dockerfile alla seguente forma:
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"]
Puoi vedere che abbiamo aggiunto due righe e aggiornato ENTRYPOINT. Linee:
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
dichiarare variabili all'interno del file del codificatore. Per impostazione predefinita hanno un valore specificato. Se, durante la creazione di un'immagine da questo dockerfile, vengono passate variabili di ambiente con tali nomi, i valori saranno diversi. E in ENTRYPOINT abbiamo aggiunto alcuni altri elementi che leggeranno queste variabili d'ambiente:
"-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}"
Qui puoi vedere che all'interno della riga, utilizzando il costrutto ${}, verranno passati i valori di BOT_NAME e BOT_TOKEN. Successivamente, dobbiamo insegnare come ricevere e passare queste variabili a docker-compose.

Crea docker-compose.yml

Sarebbe bene che leggessi separatamente il formato YAML, altrimenti l'articolo sta già crescendo a passi da gigante. Per noi questa è solo un'altra descrizione delle variabili del tipo .properties. Solo nelle proprietà viene scritto attraverso un punto, ma in YAML questo viene fatto in modo un po' più bello. Ad esempio, così. Due variabili in .properties: javarush.telegram.bot.name=ivan javarush.telegram.bot.token=pupkin Ma in .yaml (lo stesso di .yml) sarà così:
javarush:
	telegram:
		bot:
		  name: ivan
		  token: pupkin
La seconda opzione è più bella e comprensibile. Gli spazi dovrebbero essere esattamente come indicato sopra. Traduciamo in qualche modo application.properties e application.yml. Per prima cosa devi crearlo. Nella root del progetto, crea un file docker-compose.yml e scrivi lì quanto segue:
version: '3.1'

services:
 jrtb:
   build:
     context: .
   environment:
     - BOT_NAME=${BOT_NAME}
     - BOT_TOKEN=${BOT_TOKEN}
   restart: always
La prima riga è la versione docker-compose. services: dice che tutte le righe successive a questa (verranno spostate) si riferiscono ai servizi che stiamo configurando. Finora ne abbiamo solo uno: un'applicazione Java chiamata jrtb . E già sotto ci saranno tutte le sue impostazioni. Ad esempio, build: contesto: . dice che cercheremo il Dockerfile nella stessa directory di docker-compose.yml. Ma la sezione Environment: sarà responsabile di garantire il passaggio delle variabili di ambiente necessarie al Dockerfile. Proprio quello di cui abbiamo bisogno. Pertanto, passiamo le variabili di seguito. Docker-compose li cercherà nelle variabili dell'ambiente operativo del server. Aggiungiamoli allo script bash.

Creazione di script bash

L'ultimo passaggio è creare uno script bash. Crea un file chiamato start.sh nella root del progetto e scrivi lì quanto segue:
#!/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
La prima riga è necessaria per tutti gli script bash: senza di essa non funzionerà. E poi - solo una serie di comandi nel terminale che devono essere eseguiti. Ho aggiunto commenti in ogni comando quindi dovrebbe essere chiaro. L’unica cosa che voglio spiegare è cosa significano $ 1 e $ 2. Queste sono due variabili che verranno passate all'avvio dello script bash. Utilizzando il comando export, verranno aggiunti alle variabili del server e letti in docker-compose. Funziona per Ubuntu, probabilmente non per Windows, ma non ne sono sicuro. Ora devi aggiungere lo script stop.sh, che interromperà il lavoro. Conterrà diverse righe:
#!/bin/bash

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

# Ensure, that the old application won't be deployed again.
mvn clean
Qui interrompiamo la composizione docker e puliamo il progetto jarnik, che è rimasto in giro dall'ultima build. Lo facciamo per garantire che il nostro progetto venga ricostruito accuratamente. C'erano dei precedenti, ecco perché aggiungo) Di conseguenza, ci ritroviamo con 4 nuovi file:
  • Dockerfile: un file per creare un'immagine della nostra applicazione;
  • docker-compose.yml - un file con le impostazioni su come lanceremo i nostri contenitori;
  • start.sh - script bash per la distribuzione della nostra applicazione;
  • stop.sh è uno script bash per arrestare la nostra applicazione.
Aggiorneremo anche la versione della nostra applicazione da 0.2.0-SNAPSHOT a 0.3.0-SNAPSHOT. Aggiungiamo una descrizione della nuova versione a RELEASE_NOTES e rifaciamo leggermente ciò che c'era:
# Note di rilascio ## 0.3.0-SNAPSHOT * JRTB-13: aggiunto processo di distribuzione al progetto ## 0.2.0-SNAPSHOT * JRTB-3: implementato modello di comando per la gestione dei comandi del Bot di Telegram ## 0.1.0-SNAPSHOT * JRTB -2: aggiunto stub telegram bot * JRTB-0: aggiunto progetto skeleton SpringBoot
E nel README aggiungeremo un nuovo paragrafo che descrive come distribuire la nostra applicazione:
## Distribuzione Processo di distribuzione il più semplice possibile: Software richiesto: - terminale per l'esecuzione degli script bash - docker - docker-compose per distribuire l'applicazione, passare al ramo necessario ed eseguire lo script bash: $ bash start.sh ${bot_username} ${bot_token } È tutto.
Ovviamente tutto è scritto in inglese. Come al solito, nel nostro ramo appena creato STEP_4_JRTB-13 creiamo un nuovo commit con il nome: JRTB-13: implementa il processo di distribuzione tramite docker e invialo. Mi fermo a soffermarmi nel dettaglio su cose che ho già descritto negli articoli precedenti. Non vedo il motivo di ripetere la stessa cosa. Inoltre, coloro che l'hanno capito e lo hanno fatto da soli non avranno domande. Sto parlando di come creare un nuovo ramo, come creare un commit, come inviare un commit al repository.

Linea di fondo

Oggi ho mostrato tantissime nuove informazioni che devono essere attentamente considerate e ampliate con letture aggiuntive. La cosa più importante: con l'aiuto di UN (!!!) comando, verrà fatto tutto il necessario per distribuire la nostra applicazione. È così bello che non posso nemmeno dirtelo. Sì, ho dovuto dedicare una discreta quantità di tempo alla documentazione di Docker per capire come inoltrare correttamente le variabili. D'ora in poi il bot di Telegram funzionerà sempre sull'ultima versione del ramo principale. Collegamento al bot di Telegram. Oggi non ci saranno link a materiali che sarebbe bene leggere: la responsabilità è vostra. Devi imparare a cercare informazioni. Tutti coloro che si sono iscritti al mio canale Telegram sono venuti a conoscenza dell'implementazione del bot quasi immediatamente. Amici, vi piace il progetto? Dategli una stella ! In questo modo diventerà più popolare e più persone potranno conoscerlo e imparare da esso. Come al solito, suggerisco di registrarsi su GitHub e di seguire il mio account per seguire questa serie e gli altri progetti su cui lavoro lì. Ora siamo pronti per connettere il database. Il prossimo articolo sarà più lungo e in esso faremo tutto il necessario per lavorare con il database. Tutte le descrizioni sono in JRTB-1 .

Un elenco di tutti i materiali della serie si trova all'inizio di questo articolo.

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