A nosso pedido, a Habr criou o hub Kubernetes e temos o prazer de publicar a primeira publicação nele. Inscreva-se!
Kubernetes é fácil. Por que os bancos me pagam muito dinheiro por trabalhar nesta área, enquanto alguém pode dominar essa tecnologia em apenas algumas horas?

Se você duvida que o Kubernetes possa ser aprendido tão rapidamente, sugiro que tente fazer isso sozinho. Ou seja, depois de dominar este material, você poderá executar o aplicativo com base em microsserviços no cluster Kubernetes. Eu posso garantir isso, porque é exatamente pela metodologia usada aqui que eu treino o Kubernetes para trabalhar com nossos clientes. O que distingue este manual dos outros? De fato - muitas coisas. Portanto, a maioria desses materiais começa com uma explicação de coisas simples - conceitos do Kubernetes e recursos da equipe do kubectl. Os autores desses materiais acreditam que seus leitores estão familiarizados com o desenvolvimento de aplicativos, microsserviços e contêineres do Docker. Vamos para o outro lado. Primeiro, vamos falar sobre como executar um aplicativo com base em microsserviços em um computador. Em seguida, considere a montagem de imagens de contêiner para cada microsserviço. Depois disso, conheceremos o Kubernetes e analisaremos a implantação de um aplicativo baseado em microsserviço em um cluster gerenciado pelo Kubernetes.
Essa abordagem, com uma abordagem gradual ao Kubernetes, fornecerá a profundidade do entendimento que está acontecendo com uma pessoa comum, a fim de entender como tudo é organizado de maneira simples no Kubernetes. O Kubernetes é, é claro, uma tecnologia simples, desde que quem queira aprender saiba onde e como é usado.
Agora, sem mais delongas, vamos trabalhar e falar sobre o aplicativo com o qual iremos trabalhar.
Aplicação experimental
Nossa aplicação executará apenas uma função. Ele aceita, como entrada, uma sentença e, usando os meios de análise de texto, realiza uma análise de sentimentos dessa sentença, recebendo uma estimativa da atitude emocional do autor da sentença em relação a um determinado objeto.
É assim que a janela principal deste aplicativo se parece.
Aplicativo da Web para análise de sentimentos de textoDo ponto de vista técnico, o aplicativo consiste em três microsserviços, cada um dos quais resolve um determinado conjunto de tarefas:
- O SA-Frontend é um servidor da web Nginx que serve arquivos estáticos do React.
- O SA-WebApp é um aplicativo da web baseado em Java que processa solicitações do front-end.
- O SA-Logic é um aplicativo Python que executa análise de sentimentos de texto.
É importante observar que os microsserviços não existem isoladamente. Eles implementam a idéia de "separação de tarefas", mas, no entanto, precisam interagir entre si.
Fluxos de dados do aplicativoNo diagrama acima, você pode ver os estágios numerados do sistema, ilustrando os fluxos de dados no aplicativo. Vamos analisá-los:
- O navegador solicita o arquivo
index.html
do servidor (que, por sua vez, baixa o pacote do aplicativo React). - O usuário interage com o aplicativo, isso causa uma chamada para um aplicativo Web baseado no Spring.
- O aplicativo da Web redireciona a solicitação de análise de texto para o aplicativo Python.
- O aplicativo Python analisa a tonalidade do texto e retorna o resultado como uma resposta à solicitação.
- O aplicativo Spring envia uma resposta ao aplicativo React (e, por sua vez, mostra o resultado da análise de texto ao usuário).
O código para todos esses aplicativos pode ser encontrado
aqui . Eu recomendo que você agora copie esse repositório para si mesmo, pois há muitas experiências interessantes à sua frente.
Iniciando um aplicativo baseado em microsserviço em um computador local
Para que o aplicativo funcione, precisamos executar todos os três microsserviços. Vamos começar com o mais bonito deles - com o aplicativo front-end.
ReaConfigurando o React para o desenvolvimento local
Para executar o aplicativo React, você precisa instalar as plataformas Node.js e NPM no seu computador. Depois de instalar tudo isso, passe pelo terminal até a pasta do projeto
sa-frontend
e execute o seguinte comando:
npm install
Graças à execução deste comando, as dependências do aplicativo React, entradas sobre as quais estão no arquivo
package.json
, serão carregadas na pasta
node_modules
. Após o download das dependências na mesma pasta, execute o seguinte comando:
npm start
Isso é tudo. Agora, o aplicativo React está em execução. O acesso a ele pode ser obtido acessando o endereço
localhost:3000
no navegador. Você pode mudar algo no código dele. Você verá imediatamente o efeito dessas alterações no navegador. Isso é possível graças à chamada substituição "quente" de módulos. Graças a isso, o desenvolvimento do front-end se torna uma tarefa simples e agradável.
▍ Preparação de um aplicativo React para saída para produção
Para o uso real do aplicativo React, precisamos convertê-lo em um conjunto de arquivos estáticos e entregá-los aos clientes usando um servidor da web.
Para criar o aplicativo React, novamente, usando o terminal, vá para a pasta
sa-frontend
e execute o seguinte comando:
npm run build
Isso criará um diretório de
build
na pasta do projeto. Ele conterá todos os arquivos estáticos necessários para o aplicativo React funcionar.
ErvServindo arquivos estáticos usando as ferramentas Nginx
Primeiro, você precisa instalar e executar o servidor da web Nginx.
Aqui você pode baixá-lo e encontrar instruções de instalação e inicialização. Em seguida, você precisa copiar o conteúdo da pasta
sa-frontend/build
para a pasta
[your_nginx_installation_dir]/html
.
Com essa abordagem, o arquivo
index.html
gerado durante a compilação do aplicativo React estará disponível em
[your_nginx_installation_dir]/html/index.html
. Esse é o arquivo que, por padrão, o servidor Nginx emite ao acessá-lo. O servidor está configurado para escutar na porta
80
, mas você pode configurá-lo conforme necessário editando o arquivo
[your_nginx_installation_dir]/conf/nginx.conf
.
Agora abra seu navegador e vá para
localhost:80
. Você verá a página do aplicativo React.
React Application Served by Nginx ServerSe você digitar algo no campo
Type your sentence
agora e clicar no botão
Send
, nada acontecerá. Mas, se você olhar para o console, poderá ver mensagens de erro lá. Para entender exatamente onde esses erros ocorrem, vamos analisar o código do aplicativo.
▍Análise do código do aplicativo front-end
App.js
analisado o código do arquivo
App.js
, podemos ver que clicar no botão
Send
chama o método
analyzeSentence()
. O código para este método é fornecido abaixo. Ao mesmo tempo, preste atenção ao fato de que, para cada linha para a qual há um comentário no formulário
#
, há uma explicação fornecida abaixo do código. Da mesma forma, analisaremos outras partes do código.
analyzeSentence() { fetch('http://localhost:8080/sentiment', { // #1 method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sentence: this.textField.getValue()})// #2 }) .then(response => response.json()) .then(data => this.setState(data)); // #3 }
1. URL em que a solicitação POST é executada. Entende-se que este endereço contém um aplicativo que está aguardando tais solicitações.
2. O corpo da solicitação enviado ao aplicativo. Aqui está um exemplo de corpo de solicitação:
{ sentence: "I like yogobella!" }
3. Após o recebimento de uma resposta à solicitação, o estado do componente é atualizado. Isso faz com que o componente seja renderizado novamente. Se recebermos dados (ou seja, um objeto JSON contendo os dados inseridos e a pontuação calculada do texto), produziremos o componente
Polarity
, pois as condições correspondentes serão atendidas. É assim que descrevemos o componente:
const polarityComponent = this.state.polarity !== undefined ? <Polarity sentence={this.state.sentence} polarity={this.state.polarity}/> : null;
O código parece estar funcionando muito bem. O que há de errado aqui, afinal? Se você presumir que no endereço em que o aplicativo está tentando enviar uma solicitação POST, até o momento não há nada que possa aceitar e processar essa solicitação, você estará absolutamente certo. Ou seja, para processar solicitações que chegam ao endereço
http://localhost:8080/sentiment
, precisamos executar um aplicativo Web baseado no Spring.
Precisamos de um aplicativo Spring que possa aceitar uma solicitação POST.ApplicationConfigurar o aplicativo Web baseado em Spring
Para implantar o aplicativo Spring, você precisará de JDK8 e Maven e variáveis de ambiente adequadamente configuradas. Depois de instalar tudo isso, você pode continuar trabalhando no nosso projeto.
AckEmbalando o aplicativo em um arquivo jar
Vá, usando o terminal, para a pasta
sa-webapp
e digite o seguinte comando:
mvn install
Após executar este comando, o diretório de
target
será criado na pasta
sa-webapp
. Haverá um aplicativo Java empacotado em um arquivo jar representado por
sentiment-analysis-web-0.0.1-SNAPSHOT.jar
.
▍Inicie o aplicativo Java
Vá para a pasta de
target
e inicie o aplicativo com o seguinte comando:
java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar
Ocorrerá um erro durante a execução deste comando. Para começar a corrigi-lo, podemos analisar as informações de exceção nos dados de rastreamento da pilha:
Error creating bean with name 'sentimentController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'sa.logic.api.url' in value "${sa.logic.api.url}"
Para nós, o mais importante aqui é a menção da impossibilidade de determinar o significado de
sa.logic.api.url
. Vamos analisar o código no qual o erro ocorre.
Analysis Análise de código de aplicativo Java
Aqui está o trecho de código em que o erro ocorre.
@CrossOrigin(origins = "*") @RestController public class SentimentController { @Value("${sa.logic.api.url}") // #1 private String saLogicApiUrl; @PostMapping("/sentiment") public SentimentDto sentimentAnalysis( @RequestBody SentenceDto sentenceDto) { RestTemplate restTemplate = new RestTemplate(); return restTemplate.postForEntity( saLogicApiUrl + "/analyse/sentiment", // #2 sentenceDto, SentimentDto.class) .getBody(); } }
- S
entimentController
possui um campo saLogicApiUrl
. Seu valor é definido pela propriedade sa.logic.api.url
. - A cadeia
saLogicApiUrl
concatenada com o valor /analyse/sentiment
. Juntos, eles formam um endereço para acessar um microsserviço que executa análise de texto.
Definir valor da propriedade
No Spring, a fonte padrão de valores de propriedade é o arquivo
application.properties
, que pode ser encontrado em
sa-webapp/src/main/resources
. Mas seu uso não é a única maneira de definir valores de propriedade. Você pode fazer isso com um comando como o seguinte:
java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=WHAT.IS.THE.SA.LOGIC.API.URL
O valor dessa propriedade deve apontar para o endereço do nosso aplicativo Python.
Ao configurá-lo, informamos ao aplicativo da Web Spring para onde ele deve ir para executar solicitações de análise de texto.
Para não complicar nossas vidas, decidimos que o aplicativo Python estará disponível no
localhost:5000
e tentamos não esquecê-lo. Como resultado, o comando para iniciar o aplicativo Spring ficará assim:
java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=http://localhost:5000
Nosso sistema não possui um aplicativo PythonAgora basta iniciar o aplicativo Python e o sistema funcionará conforme o esperado.
▍Configurando um aplicativo Python
Para executar um aplicativo Python, você deve ter o Python 3 e o Pip instalados e definir as variáveis de ambiente apropriadas corretamente.
Instalação de dependências
Vá para a pasta do projeto
sa-logic/sa
e execute os seguintes comandos:
python -m pip install -r requirements.txt python -m textblob.download_corpora
▍Iniciar aplicação
Depois de instalar as dependências, estamos prontos para iniciar o aplicativo:
python sentiment_analysis.py
Após executar este comando, seremos informados do seguinte:
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Isso significa que o aplicativo está em execução e aguarda solicitações no
localhost:5000/
▍ Pesquisa de código
Considere o código do aplicativo Python para entender como ele responde às solicitações:
from textblob import TextBlob from flask import Flask, request, jsonify app = Flask(__name__) #1 @app.route("/analyse/sentiment", methods=['POST']) #2 def analyse_sentiment(): sentence = request.get_json()['sentence'] #3 polarity = TextBlob(sentence).sentences[0].polarity #4 return jsonify( #5 sentence=sentence, polarity=polarity ) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) #6
- Inicializando um objeto
Flask
. - Configurando o endereço para executar solicitações POST.
- Recuperando a propriedade da
sentence
do corpo da solicitação. - Inicializando o objeto
TextBlob
anônimo e obtendo o valor de polarity
para a primeira sentença no corpo da solicitação (no nosso caso, esta é a única sentença passada para análise). - O retorno da resposta, no corpo da qual contém o texto da proposta e o índice de
polarity
calculado para ela. - Ativando o aplicativo Flask, que estará disponível em
0.0.0.0:5000
(você também pode acessá-lo usando uma construção localhost:5000
).
Agora, os microsserviços que compõem o aplicativo estão em execução. Eles estão configurados para interagir entre si. É assim que o diagrama do aplicativo se parece nesta fase do trabalho.
Todos os microsserviços que compõem o aplicativo são trazidos para um estado íntegro.Agora, antes de continuar, abra o aplicativo React em um navegador e tente analisar algumas sugestões usando-o. Se tudo for feito corretamente, depois de clicar no botão
Send
, você verá os resultados da análise na caixa de texto.
Na próxima seção, falaremos sobre como executar nossos microsserviços em contêineres do Docker. Isso é necessário para preparar o aplicativo para o lançamento no cluster Kubernetes.
Docker Containers
O Kubernetes é um sistema para automatizar a implantação, dimensionamento e gerenciamento de aplicativos em contêiner. É também chamado de "orquestrador de contêineres". Se o Kubernetes trabalha com contêineres, primeiro precisamos adquiri-los antes de usar este sistema. Mas primeiro, vamos falar sobre o que são contêineres. Talvez a melhor resposta para a pergunta sobre o que é possa ser encontrada na
documentação do Docker:
Uma imagem de contêiner é um pacote executável leve, independente, contendo algum tipo de aplicativo que inclui tudo o que você precisa para executá-lo: código do aplicativo, tempo de execução, ferramentas e bibliotecas do sistema, configurações. Programas em contêineres podem ser usados em ambientes Linux e Windows e sempre funcionarão da mesma maneira, independentemente da infraestrutura.Isso significa que os contêineres podem ser executados em qualquer computador, incluindo servidores de produção, e em qualquer ambiente que os aplicativos contidos neles funcionem da mesma maneira.
Para explorar os recursos dos contêineres e compará-los com outras maneiras de iniciar aplicativos, considere um exemplo de veiculação de um aplicativo React usando uma máquina virtual e um contêiner.
ErvServindo Arquivos estáticos do aplicativo React usando máquina virtual
Tentando organizar a manutenção de arquivos estáticos por meio de máquinas virtuais, encontraremos as seguintes desvantagens:
- Uso ineficiente de recursos, pois cada máquina virtual é um sistema operacional completo.
- Depende da plataforma. O que funciona em um determinado computador local pode não funcionar em um servidor de produção.
- Escala lenta e com muitos recursos de uma solução baseada em máquina virtual.
Servidor da Web do servidor estático Nginx em execução em uma máquina virtualSe os contêineres são usados para resolver um problema semelhante, então, em comparação com as máquinas virtuais, podem ser observados os seguintes pontos fortes:
- Uso eficiente de recursos: trabalhando com o sistema operacional usando o Docker.
- Independência da plataforma. Um contêiner que um desenvolvedor possa executar em seu computador funcionará em qualquer lugar.
- Implantação leve através do uso de camadas de imagem.
Servidor da Web do servidor estático Nginx em execução em um contêinerComparamos máquinas virtuais e contêineres em apenas alguns pontos, mas mesmo isso é suficiente para sentir a força dos contêineres. Saiba mais sobre os contêineres do Docker aqui.
▍ Montando uma imagem de contêiner para um aplicativo React
O principal
Dockerfile
do contêiner do Docker é o
Dockerfile
. No início deste arquivo, faça um registro da imagem básica do contêiner e, em seguida, inclua uma sequência de instruções que indica a ordem em que o contêiner será criado para atender às necessidades de um determinado aplicativo.
Antes de começarmos a trabalhar com o arquivo
Dockerfile
, lembremos o que fizemos para preparar os arquivos do aplicativo React para upload no servidor Nginx:
- Crie um pacote de aplicativos React (
npm run build
). - Iniciando o servidor Nginx.
- Copie o conteúdo do diretório de
build
da pasta do projeto sa-frontend
para a pasta do servidor nginx/html
.
Abaixo, você pode ver os paralelos entre a criação do contêiner e as ações acima, executadas no computador local.
RePreparando um Dockerfile para SA-Frontend
As instruções que estarão contidas no
Dockerfile
para o aplicativo
SA-Frontend
consistem em apenas dois comandos. O fato é que a equipe de desenvolvimento do Nginx preparou uma
imagem básica para o Nginx, que usaremos para criar nossa imagem. Aqui estão as duas etapas que precisamos descrever:
- A base da imagem que você precisa para criar uma imagem Nginx.
- O conteúdo da pasta
sa-frontend/build
deve ser copiado para a pasta de imagem nginx/html
.
Se passarmos desta descrição para o
Dockerfile
, será semelhante a este:
FROM nginx COPY build /usr/share/nginx/html
Como você pode ver, tudo aqui é muito simples, enquanto o conteúdo do arquivo acaba sendo bastante legível e compreensível. Esse arquivo informa ao sistema para levar a imagem
nginx
com tudo o que já possui e copiar o conteúdo do diretório de
build
para o diretório
nginx/html
.
Aqui você pode ter uma pergunta sobre onde eu sei exatamente onde eu preciso copiar arquivos da pasta de
build
, ou seja, de onde veio o caminho
/usr/share/nginx/html
. De fato, e não há nada complicado. O fato é que as informações relevantes podem ser encontradas na
descrição da imagem.
UildConstruindo uma imagem e enviando-a para o repositório
Antes de podermos trabalhar com a imagem final, precisamos enviá-la para o repositório de imagens. Para fazer isso, usaremos a plataforma de nuvem gratuita para hospedar imagens do Docker Hub. Nesta fase do trabalho, você precisa fazer o seguinte:
- Instale o Docker .
- Registre-se no site do Docker Hub.
- Efetue login na conta executando o seguinte comando no terminal:
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
Agora você precisa usar o terminal para acessar o diretório
sa-frontend
e executar o seguinte comando:
docker build -f Dockerfile -t $DOCKER_USER_ID/sentiment-analysis-frontend .
A seguir, em comandos semelhantes,
$DOCKER_USER_ID
precisa ser substituído pelo seu nome de usuário no Docker Hub. Por exemplo, esta parte do comando pode ser assim:
rinormaloku/sentiment-analysis-frontend
.
Ao mesmo tempo, esse comando pode ser abreviado removendo
-f Dockerfile
, pois esse arquivo já existe na pasta em que executamos esse comando.
Para enviar a imagem finalizada para o repositório, precisamos do seguinte comando:
docker push $DOCKER_USER_ID/sentiment-analysis-frontend
Após sua execução, verifique a lista de seus repositórios no Docker Hub para entender se a imagem foi enviada para a nuvem com sucesso.
ContainerIniciar o contêiner
Agora qualquer pessoa pode baixar e executar uma imagem conhecida como
$DOCKER_USER_ID/sentiment-analysis-frontend
. Para fazer isso, você precisa executar a seguinte sequência de comandos:
docker pull $DOCKER_USER_ID/sentiment-analysis-frontend docker run -d -p 80:80 $DOCKER_USER_ID/sentiment-analysis-frontend
Agora o contêiner foi lançado e podemos continuar trabalhando, criando as outras imagens de que precisamos. Mas, antes de continuar, vejamos
80:80
construção
80:80
, encontrada no comando de inicialização da imagem e pode parecer incompreensível.
- O primeiro número
80
é o número da porta do host (ou seja, o computador local). - O segundo número
80
é a porta do contêiner para o qual a solicitação deve ser redirecionada.
Considere a seguinte ilustração.
Encaminhamento de portaO sistema redireciona solicitações da porta
<hostPort>
para a porta
<containerPort>
. Ou seja, o acesso à porta
80
computador é redirecionado para a porta
80
contêiner.
Como a porta
80
aberta no computador local, você pode acessar o aplicativo neste computador em
localhost:80
. Se o seu sistema não suportar o Docker, você poderá executar o aplicativo na máquina virtual do Docker, cujo endereço será semelhante a
<docker-machine ip>:80
. Para descobrir o endereço IP da máquina virtual do Docker, você pode usar o
docker-machine ip
.
Nesse estágio, após iniciar com êxito o contêiner do aplicativo frontend, você poderá abrir sua página em um navegador.
▍ arquivo .dockerignore
Coletando a imagem do aplicativo
SA-Frontend
, podemos observar que esse processo é extremamente lento. Isso acontece devido ao fato de que o contexto de construção da imagem deve ser enviado ao daemon do Docker. O diretório que representa o contexto de construção é especificado pelo último argumento para o
docker build
. No nosso caso, no final deste comando, há um período. Isso resulta na inclusão da seguinte estrutura no contexto da montagem:
sa-frontend: | .dockerignore | Dockerfile | package.json | README.md +---build +---node_modules +---public \---src
Mas de todas as pastas presentes aqui, precisamos apenas da pasta de
build
. Baixar qualquer outra coisa é uma perda de tempo. As compilações podem ser aceleradas, informando ao Docker quais diretórios devem ser ignorados. É para fazer isso que precisamos de um arquivo
.dockerignore
. Se você estiver familiarizado com o arquivo
.gitignore
, a estrutura desse arquivo certamente parecerá familiar. Ele lista os diretórios que o sistema de montagem de imagens pode ignorar. No nosso caso, o conteúdo deste arquivo se parece com o seguinte:
node_modules src public
O arquivo
.dockerignore
deve estar na mesma pasta que o
Dockerfile
. Agora, a montagem da imagem levará alguns segundos.
Agora vamos dar uma olhada no aplicativo Java.
UildConstruindo uma imagem de contêiner para um aplicativo Java
Você sabe o que, mas você já aprendeu tudo o que precisa para criar imagens de contêiner. É por isso que esta seção será muito curta.Abra o arquivo Dockerfile
localizado na pasta do projeto sa-webapp
. Se você ler o texto deste arquivo, nele encontrará apenas duas novas construções começando com palavras-chave ENV
e EXPOSE
: ENV SA_LOGIC_API_URL http://localhost:5000 … EXPOSE 8080
ENV
Docker. , URL API , .
EXPOSE
Docker , . . ,
Dockerfile
SA-Frontend
. , , ,
Dockerfile
.
, . —
README.md
sa-webapp
.
▍ Python-
Dockerfile
sa-logic
, . , , ,
README.md
sa-logic
.
▍
- , ? . .
sa-logic
5050
:
docker run -d -p 5050:5000 $DOCKER_USER_ID/sentiment-analysis-logic
sa-webapp
8080
. , , Python- Java-, SA_LOGIC_API_URL
:
$ docker run -d -p 8080:8080 -e SA_LOGIC_API_URL='http://<container_ip or docker machine ip>:5000' $DOCKER_USER_ID/sentiment-analysis-web-app
, IP- Docker —
README .
sa-frontend
:
docker run -d -p 80:80 $DOCKER_USER_ID/sentiment-analysis-frontend
,
localhost:80
.
,
sa-webapp
, Docker,
App.js
sa-frontend
, IP-
analyzeSentence()
, . .
.
: Kubernetes?
Dockerfile
, , Docker. , ,
.dockerignore
. Docker. , Kubernetes. . :
, - . . ,
sa-webapp
sa-logic
. , ?
