JavaRush /Blogue Java /Random-PT /Implementamos implantação de aplicativos - "Projeto Java ...
Roman Beekeeper
Nível 35

Implementamos implantação de aplicativos - "Projeto Java de A a Z"

Publicado no grupo Random-PT
Olá a todos. Continuamos a série de artigos sobre como escrever seu projeto. “Projeto Java de A a Z”: Implementando implantação de aplicativos - 1

Classifique os galhos

Da importância, para não me perder nas ramificações e sua ordem no repositório, resolvi renomeá-las adicionando o prefixo STEP_{number} . Por exemplo, temos três filiais além da principal:
  • JRTB-0
  • JRTB-2
  • JRTB-3
Você não entenderá imediatamente qual deve seguir. Então, vou renomeá-los da seguinte forma:
  • STEP_1_JRTB-0 - primeira etapa
  • STEP_2_JRTB-2 - segunda etapa
  • STEP_3_JRTB-3 - terceira etapa
E assim por diante para os próximos artigos. Para renomear ramificações, vá para a página do repositório , encontre a caixa de ramificações , siga-a: “Projeto Java de A a Z”: Implementando implantação de aplicativos - 2Abaixo de cada ramificação, clique no lápis e renomeie a ramificação: “Projeto Java de A a Z”: Implementando implantação de aplicativos - 3E como resultado obtemos: “Projeto Java de A a Z”: Implementando implantação de aplicativos - 4A propósito, todos que se inscreveram no meu canal de telegrama encontraram descobri imediatamente que renomeei as filiais.

Um pouco sobre Docker

O que é Docker? Resumindo, é uma ferramenta com a qual você pode implantar (implantar) aplicações de forma rápida e segura, criando para elas uma infraestrutura fechada que só é necessária para elas. Ainda é difícil, eu entendo. Em geral, Docker pode ser entendido como uma plataforma de desenvolvimento onde você pode trabalhar de forma rápida e eficiente. Docker pode ser entendido como um programa executado em um servidor. Este programa tem a capacidade de armazenar contêineres com aplicativos. O que é um contêiner? Esta é uma infraestrutura separada na qual você pode adicionar tudo o que precisa. Por exemplo, para uma aplicação Java precisamos de um JRE para executar a aplicação, o contêiner terá isso, precisaremos de algum outro software - podemos adicionar isso. Ou talvez precisemos de Linux e de um contêiner de servlet Tomcat. Isso também pode ser feito. Os contêineres são criados com base em uma imagem: ou seja, este é um modelo específico que contém tudo o que é necessário para criar um contêiner Docker. Como criar esta imagem? No nosso caso, precisaremos criar um Dockerfile na raiz do projeto descrevendo o que deve estar no container. Como não queremos expor o token do bot em lugar nenhum, teremos que repassá-lo sempre que quisermos implantar o aplicativo. Você pode ler mais sobre este assunto aqui e aqui .

Escrevemos JRTB-13

Precisamos configurar um processo de implantação rápido e fácil de nosso aplicativo no servidor. Ou seja, para uma máquina que funciona 24 horas por dia, 7 dias por semana. Vamos tomar o Docker como base. Mas não há nenhuma tarefa em nossa lista que seja responsável por adicionar essa funcionalidade. De alguma forma, eu perdi isso ao criá-lo. Não tem problema, vamos criá-lo agora. Vá para a aba de criação de problemas no GitHub e selecione Solicitação de recurso: “Projeto Java de A a Z”: Implementando implantação de aplicativos - 5Adicione uma descrição da tarefa, critérios para sua aceitação, defina a qual projeto este problema pertence e você pode criar um novo problema: “Projeto Java de A a Z”: Implementando implantação de aplicativos - 6Agora, para mostrar que a tarefa foi aceita para o trabalho, altere o status da tarefa de A fazer para Em andamento: “Projeto Java de A a Z”: Implementando implantação de aplicativos - 7este será um artigo difícil. Se você tiver algum problema, escreva nos comentários: irei monitorar e responder da melhor maneira possível. Este será um pequeno Apoio ao Cliente :D

Criando um Dockerfile

O que é um arquivo docker? Para Docker, este é um script (instruções passo a passo) sobre como criar uma imagem para um contêiner Docker. Para que nosso aplicativo funcione, precisamos do JDK, versão 11. Ou seja, precisamos encontrar a imagem docker JDK 11 e adicioná-la à nossa imagem. Isso é algo semelhante a como adicionamos uma dependência a uma memória. Docker possui DockerHub para essa finalidade . Para baixar imagens localmente, você precisa se registrar lá. Após o registro, vamos procurar o JDK11. Pelo que descobri, este é o contêiner: adoptopenjdk/openjdk11 . A descrição deste contêiner contém o que é necessário para o dockerfile:
FROM adoptopenjdk/openjdk11:ubi
RUN mkdir /opt/app
COPY japp.jar /opt/app
CMD ["java", "-jar", "/opt/app/japp.jar"]
Vamos consertar a pasta da qual retiramos o arquivo jar. Nós o colocamos na pasta de destino depois de executarmos a tarefa maven do pacote mvn. Antes de fazer tudo isso, com base no branch principal atualizado, criamos um novo para nossa tarefa: STEP_4_JRTB-13 . Agora você pode trabalhar. Na raiz do projeto, crie um arquivo sem a extensão Dockerfile e adicione o seguinte dentro:
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
A primeira linha é onde a imagem será baseada - adoptopenjdk/openjdk11. A segunda linha serve para adicionar um argumento à imagem chamada JAR_FILE, que está localizada na pasta de destino. Além disso, a pasta atual é determinada pela localização do Dockerfile. Terceira linha - copie o jar do nosso projeto para a imagem do docker. A última linha contém essencialmente um array criado a partir do comando no terminal, que foi separado por espaço. Ou seja, no final será executado o seguinte: “java -jar /app.jar” Para manter o token do bot em segredo, ao iniciar o container precisaremos passar duas variáveis ​​– o nome do bot e seu token. Para fazer isso, escreveremos uma consulta que deverá lançar nosso projeto com variáveis. E como fazer isso? Você precisa pesquisar no Google: aqui está o primeiro link com uma descrição normal. O que nós queremos fazer? Temos duas variáveis ​​no arquivo application.properties que definimos lá:
  • bot.nome de usuário
  • bot.token
Quero executar um contêiner docker e passar meu valor sempre para que ninguém possa ver esses valores. Eu sei que no SpringBoot, as variáveis ​​de ambiente definidas quando o projeto jar é iniciado terão precedência sobre aquelas no arquivo application.properties. Para passar uma variável em uma solicitação, você precisa adicionar a seguinte construção: -D{variable name}=”{variable value}” . Não adicionamos chaves ;) Receberemos uma solicitação que iniciará nosso aplicativo com valores predefinidos - o nome e token do bot: java -jar -Dbot.username=”test.javarush.community_bot” -Dbot. token=”dfgkdjfglkdjfglkdjfgk” *.jar Agora precisamos passar essas variáveis ​​​​dentro do contêiner docker. Esta é uma variável de ambiente. Para garantir que no futuro nosso banco de dados funcione perfeitamente e sem problemas com nossa aplicação, usaremos o docker-compose. Esta é uma ferramenta separada na qual você pode organizar o trabalho, a inicialização e as dependências entre contêineres. Em outras palavras, é um complemento do Docker para gerenciar contêineres de uma infraestrutura. Além disso, antes de executar o docker-compose, precisamos ter certeza de que extraímos todas as alterações de código do servidor, construímos o aplicativo e interrompemos a versão antiga. Para isso usaremos um script bash. Uau... Tudo parece difícil, eu concordo. Mas trabalhar na configuração da implantação de aplicativos é sempre um processo tedioso e complexo. Portanto, temos um esquema muito bom:
  1. Vamos executar o script bash.
  2. O script bash executa o docker-compose.
  3. Docker-compose lança um contêiner docker com nosso aplicativo.
  4. O contêiner Docker executa nosso aplicativo.
E agora precisamos ter certeza de que duas variáveis ​​- o nome do bot e seu token - vão do ponto 1 ao ponto 4. E para que essas duas variáveis ​​sejam usadas ao iniciar nosso aplicativo Java. Vamos do fim ao começo. Já sabemos qual comando precisa ser executado para iniciar o jarnik. Portanto, configuraremos o Dockerfile para que ele aprenda a aceitar duas variáveis ​​e passe-as para a requisição. Para fazer isso, vamos reduzir o Dockerfile para o seguinte formato:
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"]
Você pode ver que adicionamos duas linhas e atualizamos o ENTRYPOINT. Linhas:
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
declare variáveis ​​​​dentro do arquivo do codificador. Por padrão, eles têm um valor especificado. Se, ao criar uma imagem a partir deste dockerfile, forem passadas variáveis ​​de ambiente com tais nomes, os valores serão diferentes. E no ENTRYPOINT adicionamos mais alguns elementos que irão ler estas variáveis ​​de ambiente:
"-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}"
Aqui você pode ver que dentro da linha, usando a construção ${}, os valores de BOT_NAME e BOT_TOKEN serão passados. A seguir, precisamos ensinar como receber e passar essas variáveis ​​para o docker-compose.

Crie docker-compose.yml

Seria bom que você lesse sobre o formato YAML separadamente, caso contrário o artigo já está crescendo aos trancos e barrancos. Para nós, esta é apenas mais uma descrição de variáveis ​​do tipo .properties. Somente nas propriedades é escrito através de um ponto, mas no YAML isso é feito de maneira um pouco mais bonita. Por exemplo, assim. Duas variáveis ​​em .properties: javarush.telegram.bot.name=ivan javarush.telegram.bot.token=pupkin Mas em .yaml (o mesmo que .yml) será assim:
javarush:
	telegram:
		bot:
		  name: ivan
		  token: pupkin
A segunda opção é mais bonita e compreensível. Os espaços devem ser exatamente como indicados acima. Vamos traduzir nosso application.properties e application.yml de alguma forma. Primeiro você precisa criá-lo. Na raiz do projeto, crie um arquivo docker-compose.yml e escreva o seguinte:
version: '3.1'

services:
 jrtb:
   build:
     context: .
   environment:
     - BOT_NAME=${BOT_NAME}
     - BOT_TOKEN=${BOT_TOKEN}
   restart: always
A primeira linha é a versão docker-compose. services: diz que todas as linhas seguintes (serão deslocadas) referem-se aos serviços que estamos configurando. Temos apenas um deles até agora - um aplicativo Java chamado jrtb . E já abaixo dele estarão todas as suas configurações. Por exemplo, construir: contexto: . diz que procuraremos o Dockerfile no mesmo diretório que docker-compose.yml. Mas a seção Environment: será responsável por garantir que passaremos as variáveis ​​de ambiente necessárias para o Dockerfile. Exatamente o que precisamos. Portanto, passamos variáveis ​​​​abaixo. O Docker-compose irá procurá-los nas variáveis ​​do ambiente operacional do servidor. Vamos adicioná-los ao script bash.

Criando scripts bash

A última etapa é criar um script bash. Crie um arquivo chamado start.sh na raiz do projeto e escreva o seguinte lá:
#!/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
A primeira linha é necessária para todos os scripts bash: não funcionará sem ela. E então - apenas um conjunto de comandos no terminal que precisam ser executados. Adicionei comentários em cada comando para que fique claro. A única coisa que quero explicar é o que significam $1 e $2. Estas são duas variáveis ​​que serão passadas quando o script bash for iniciado. Usando o comando export, eles serão adicionados às variáveis ​​do servidor e lidos no docker-compose. Isso funciona para o Ubuntu, provavelmente não para o Windows, mas não tenho certeza. Agora você precisa adicionar o script stop.sh, que interromperá o trabalho. Ele conterá várias linhas:
#!/bin/bash

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

# Ensure, that the old application won't be deployed again.
mvn clean
Aqui paramos o docker-compose e limpamos o jarnik do projeto, que está disponível desde a última compilação. Fazemos isso para garantir que nosso projeto seja reconstruído com precisão. Houve precedentes, por isso estou acrescentando) Como resultado, acabamos com 4 novos arquivos:
  • Dockerfile - um arquivo para criar uma imagem da nossa aplicação;
  • docker-compose.yml - um arquivo com configurações de como iniciaremos nossos contêineres;
  • start.sh - script bash para implantar nosso aplicativo;
  • stop.sh é um script bash para interromper nosso aplicativo.
Também atualizaremos a versão do nosso aplicativo de 0.2.0-SNAPSHOT para 0.3.0-SNAPSHOT. Vamos adicionar uma descrição da nova versão ao RELEASE_NOTES e refatorar um pouco o que estava lá:
# Notas de versão ## 0.3.0-SNAPSHOT * JRTB-13: processo de implantação adicionado ao projeto ## 0.2.0-SNAPSHOT * JRTB-3: padrão de comando implementado para lidar com comandos do Telegram Bot ## 0.1.0-SNAPSHOT * JRTB -2: adicionado bot de telegrama stub * JRTB-0: adicionado projeto de esqueleto SpringBoot
E no README adicionaremos um novo parágrafo descrevendo como implantar nossa aplicação:
## Implantação Processo de implantação o mais fácil possível: Software necessário: - terminal para executar scripts bash - docker - docker-compose para implantar o aplicativo, mudar para o branch necessário e executar o script bash: $ bash start.sh ${bot_username} ${bot_token } Isso é tudo.
Claro, tudo está escrito em inglês. Como de costume, em nosso branch recém-criado STEP_4_JRTB-13 criamos um novo commit com o nome: JRTB-13: implemente o processo de implantação via docker e faça push dele. Deixo de me alongar em coisas que já descrevi em artigos anteriores. Não vejo sentido em repetir a mesma coisa. Além disso, quem descobriu e fez sozinho não terá dúvidas. Sou eu falando sobre como criar um novo branch, como criar um commit, como enviar um commit para o repositório.

Resultado final

Hoje mostrei uma tonelada de informações novas que precisam ser cuidadosamente consideradas e ampliadas com leituras adicionais. O mais importante: com a ajuda de UM (!!!) comando, tudo o que for necessário para implantar nossa aplicação será feito. Isso é tão legal que nem consigo te contar. Sim, tive que gastar bastante tempo na documentação do Docker para entender como encaminhar variáveis ​​​​corretamente. A partir de agora, o bot do Telegram funcionará sempre na versão mais recente do branch principal. Link para o bot do telegrama. Hoje não haverá links para materiais que seriam bons de ler: a responsabilidade é sua. Você precisa aprender a buscar informações. Todos que se inscreveram no meu canal de telegramas ficaram sabendo da implantação do bot quase imediatamente. Amigos, vocês gostaram do projeto? Dê a ele uma estrela ! Dessa forma, ele se tornará mais popular e mais pessoas poderão aprender sobre ele e aprender com ele. Como de costume, sugiro se cadastrar no GitHub e seguir minha conta para acompanhar esta série e meus outros projetos que trabalho por lá. Agora estamos prontos para conectar o banco de dados. O próximo artigo será mais longo e nele faremos todo o necessário para trabalhar com o banco de dados. Todas as descrições estão em JRTB-1 .

Uma lista de todos os materiais da série está no início deste artigo.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION