Amazon Elastic Beanstalk Parte 2: múltiplos containers e NGINX | Alura Cursos Online
Primeiras aulas do curso Amazon Elastic Beanstalk Parte 2: múltiplos containers e NGINX
Configurando NGINX - Introdução
Olá, pessoal. Tudo bem? Eu sou o Rafael Nercessian e eu vou dar uma introdução sobre o que a gente vai ver nessa segunda parte do curso, onde faremos a publicação do projeto da Casa do Código, uma plataforma de venda de livros de tecnologia na Amazon, através do serviço do Elastic Beanstalk.
Para seguir nessa segunda parte é importante que você já tenha feito a primeira parte do curso. Se você ainda não fez, dá uma olhadinha lá primeiro, depois a gente se encontra aqui. Porque nós vamos seguir exatamente do ponto onde paramos lá na primeira parte do curso.
Na primeira parte nós havíamos feito a configuração no Elastic Beanstalk desse ambiente pra trabalhar aqui com o Docker, e a gente passou pra esse nosso ambiente as configurações necessárias lá pra podermos acessar a nossa aplicação da Casa do Código.
Então, se a gente clica aqui, consegue acessar a aplicação da Casa do Código, cadastra os livros, vai ver que tudo está funcionando.
Só que a gente vai discutir um pouco sobre a questão da performance desse acesso, que vai ter a nossa aplicação, e nós vamos realizar algumas customizações. Vamos trabalhar também com o Nginx.
A ideia é que a gente tenha um container aqui com a aplicação da Casa do Código, e o outro container que vai trabalhar com o Nginx. A gente vai fazer a configuração do Nginx pra realizar o cacheamento dos dados da nossa aplicação da Casa do Código.
Vamos montar esse arquivo que nós estamos vendo aqui na tela. E uma vez que nós montamos esse arquivo de configuração do Nginx, a gente vai fazer o quê?
A gente vai montar o arquivo docker compose, que nós já começamos a trabalhar com ele na primeira parte do curso, para agora trabalhar também com esse container que vai ter o Nginx com essa parte de configuração de cacheamento.
Nós vamos fazer o teste local aqui no nosso computador da gravação. A ideia, depois, é que a gente possa vir aqui nesse teste local, e colocamos o endereço IP do Docker Machine e vamos ser capaz de visualizar a nossa aplicação.
E nesse arquivo de configuração do Nginx, se eu clicar aqui no inspecionar elemento, vamos ver um cabeçalho que vamos adicionar aqui no Nginx pra saber se a gente está pegando o conteúdo cacheado, ou não, que a gente consegue visualizar por esse cabeçalho que a gente vai estar configurando lá no container do Nginx.
Agora com isso, temos o quê? Vamos ter um container com a aplicação da Casa do Código, outro container lá com o Nginx. E temos que levar para a Amazon, através do serviço do Elastic Beanstalk.
Vamos configurar aqui o arquivo necessário com as configurações pra que a gente trabalhe na Amazon, agora, com esses dois containers, o container com a nossa aplicação e o outro container com o Nginx.
Vamos, depois, voltar no painel de console da Amazon e vamos configurar aqui um outro ambiente pra poder trabalhar com o quê? Com múltiplos containers aqui do Docker.
Só que essa configuração, desse ambiente que vamos fazer agora, vai ser pela linha de comando, pelo terminal. Para comparar como é o processo de criação pelo painel de console e pelo terminal. E vamos fazer, também, a publicação desse arquivo de configuração tudo pelo terminal.
E uma vez que fizermos isso, vamos ser capaz de visualizar, também, a nossa aplicação trabalhando aqui, se a gente voltar pra cá, vamos ver que essa publicação foi feita.
E se nós formos aqui no inspecionar elemento, na aba Network, vamos ser capazes de ver aquele cabeçalho que vamos adicionar aqui no NGIX, pra dizer se estamos acessando o conteúdo cacheado, ou não, da nossa aplicação.
Uma vez que terminarmos essa etapa, vamos discutir sobre a questão de uma alta demanda de acessos que a nossa aplicação poderá vir a ter.
Com isso, vamos verificar aqui no Elastic Beanstalk como é que a gente faz a configuração, aqui nessa parte, vamos fazer a configuração pra realizar o escalonamento dessa nossa aplicação, pra poder atender essa grande demanda de acessos que podem ocorrer em um determinado período de tempo.
Vamos configurar aqui no Elastic Beanstalk pra nós trabalharmos com até dois servidores, pra poder atender essa grande demanda de acessos, e vamos comparar, e vamos verificar se de fato esse escalonamento vai ser realizado pelo Elastic Beanstalk.
E aí, pra finalizar essa segunda parte, nós vamos verificar aqui na Amazon como conseguimos trabalhar com diferentes versões da nossa aplicação. Então, vamos ter aqui essas duas versões.
Os usuários da internet momentaneamente vão estar acessando essa aplicação aqui, sem nenhuma customização, que vai ter.
E aí, depois a gente vai fazer uma customização dessa imagem com a imagem da Black Friday, que vai estar na semana da Black Friday. E a gente vai fazer a publicação dessa outra versão aqui, que vai ter essa imagem da Black Friday.
Vamos ver como que podemos, aqui no Elastic Beanstalk, redirecionar os acessos dos usuários pra essa segunda versão, essa versão da Black Friday, com o menor impacto possível, pra ser praticamente transparente aí pro nosso usuário final.
É isso que vamos ver aqui nesse curso. Então, eu aguardo vocês. Eu agradeço muito por terem visto aqui a introdução, e eu espero que o curso ajude no crescimento profissional de vocês. Até breve.
Configurando NGINX - Analisando logs de acesso
Nós conseguimos agora acessar a aplicação da Casa do Código, que está rodando no container do Docker, que nós fizemos a configuração através do Elastic Beanstalk.
Só que existem ainda algumas configurações que podemos fazer pra melhorar um pouco essa performance da nossa aplicação para os usuários finais.
Vamos fazer essa análise agora, nesse nosso computador local da gravação, no ambiente de desenvolvimento. Então, vamos voltar pro arquivo do Docker Compose, que tínhamos feito a configuração nas aulas anteriores.
Vamos abrir o nosso arquivo do Docker Compose. E esse arquivo era composto pelo nosso container do banco de dados, e aqui também pelo container da nossa aplicação da Casa do Código, com aquela imagem customizada que fizemos tanto do Tomcat na versão 9 com a nossa aplicação.
Só que esses containers por padrão não estão considerando o horário aqui de São Paulo, que é onde eu estou localizado. E pra nós, vamos precisar analisar alguns resultados dos logs pra compararmos as mudanças que vamos fazer.
Pra poder fazer essa análise dos resultados de logs, é mais fácil se a gente manter esse horário de onde eu estou localizado, aqui de São Paulo, pra que facilite a nossa leitura.
Então pra isso, nessa parte das variáveis de ambiente desse container da Casa do Código, que tem lá o nosso Tomcat com a aplicação, eu vou colocar aqui uma outra variável que seria pra configurar, pra esse container utilizar a zona horária aqui de São Paulo.
Pra poder colocar isso, basta eu vir aqui depois dessa chave referente à conexão com o banco de dados e eu vou passar essa variável de ambiente, que seria referente à zona horária, em inglês, time zone.
Coloco aqui "TZ", de time zone, zona horária. E eu vou pedir pra esse container utilizar a zona horária de São Paulo. Então, eu coloco aqui: TZ: America/São_Paulo.
E com isso, todos os resultados de logs que vamos analisar pra comparar os resultados, vão estar com a zona horária de São Paulo, vão estar exatamente com o mesmo horário aqui do meu computador da gravação e vai facilitar a nossa leitura.
Uma vez que já fizemos essa alteração, nós podemos inicializar os containers e começar a discutir alguns pontos. Vamos voltar aqui pro Docker Quickstart Terminal. E aí, nós vamos lá, só certificamos que nós estamos na pasta de desenvolvimento, e uma vez que a gente está aqui, nós podemos inicializar o arquivo do Docker Compose pra subir esses containers.
Colocamos aqui o comando: docker-compose.exe. Pra subir "up", e pra que eles rodem no modo desatachado, em plano de fundo, a gente coloca opção "-d". Então, a gente coloca esse comando: docker-compose.exe up -d. E já vai ter aqui os nossos dois containers rodando.
Se colocar: docker ps, pra listas os containers, nós temos novamente os nossos dois containers, da aplicação da Casa do Código com o banco de dados do MySQL. Pra podermos fazer essa análise, vamos entrar nesse container da aplicação da Casa do Código e analisar os resultados de logs.
Pra podermos acessar esse container, temos que colocar o comando aqui "docker" e pra executar um comando a gente coloca "exec", e eu quero pegar o terminal desse container e mostrar pra mim.
Então, a gente tem lá aquela opção "-it", que nós já vimos no curso do Docker. E aí, eu tenho que falar que eu quero pegar o terminal de qual container? Eu tenho que passar o nome desse container que eu quero pegar o terminal.
Eu tenho nome aqui do container com a aplicação da Casa do Código e o Tomcat, eu o copio aqui. E eu quero executar o comando do "bash", pra pegar o terminal aqui e a gente analisar os resultados. Vamos lá: docker exec -it beanstalkdev_container_casadocodigo_1 bash.
Agora eu já estou dentro desse terminal do container da aplicação da Casa do Código com o Tomcat. Então, eu tenho aqui já no diretório Tomcat, e eu quero entrar agora no diretório de logs, pra que a gente possa fazer uma análise dos resultados.
Vou colocar aqui "cd" entre um diretório logs: cd logs/. E se eu listo aqui os arquivos presentes, temos aqui alguns arquivos de logs.
Vamos nos preocupar agora em analisar a quantidade de acessos que foram feitos pra esse container, com a aplicação da Casa do Código. Então, vamos analisar aqui esse arquivo que seja referente à parte de acessos.
Se eu colocar aqui "cat" - pra mostrar aqui no terminal - "localhost_acess_log". Olha só, ele não me mostra nada ainda, porque nós não fizemos o acesso ainda pra essa nossa aplicação da Casa do Código que está rodando nesse container do ambiente de desenvolvimento.
Vamos abrir uma nova janela no browser, e vamos acessar a nossa aplicação da Casa do Código desse ambiente de desenvolvimento. Como nós vimos, como eu estou rodando aqui no sistema operacional Windows, o Docker funciona num ambiente virtualizado, numa máquina virtual que tem o endereço IP 192.168.99.100.
Então, quando a gente coloca aqui "enter", a gente deve ser capaz de visualizar a nossa aplicação da Casa do Código funcionando no nosso ambiente desenvolvimento.
Agora eu fiz uma requisição pro container com a aplicação da Casa do Código, então se eu voltar pro arquivo de logs, e eu voltar o comando anterior aqui. Olha só, a gente teve aqui listado que foi no horário 09:51:32 que o nosso container respondeu aqui essa requisição da home.
O que acontece? Vamos voltar pra nossa aplicação, se eu fizer uma nova requisição aqui o que a gente espera? A gente espera que o container com a nossa aplicação da Casa do Código com o Tomcat tenha respondido essa requisição. Vamos só voltar pra cá, colocar o comando anterior, olha só.
Agora, nós temos o quê? Temos que o container respondeu essas duas requisições. Uma no horário 09:51:32. E o outro aqui 09:52:11. Ou seja, a home da Casa do Código está respondendo a todas essas requisições. Mas, vamos ver como está estruturado a home desse nosso projeto? Olha lá.
Vamos voltar aqui pro projeto do Eclipse e vamos no pacote aqui controllers e nós vamos na nossa home. Então, eu vou clicar aqui na home. Olha só, quando a gente vem na home, repare que tem um acesso ao banco de dados pra listar todos os livros que foram cadastrados na nossa aplicação.
Mas aí é que tá, será que eu vou ficar atualizando? Eu vou ficar cadastrando um livro a todo momento, que tem que estar sendo mostrado pro usuário a todo instante? Não é uma coisa que a gente vai ficar cadastrando toda hora esses livros, não é mesmo? Então, o que está acontecendo?
A gente está toda hora executando uma query pro banco de dados que não necessariamente precisa ser realizada. Nós não vamos cadastrar um livro a toda hora, todo dia, por exemplo. A cada maior quantidade de acessos que for ter da nossa aplicação, nós estamos toda hora executando uma query pro banco de dados.
Só pra ilustrar isso que estamos conversando. Olha só, o que está acontecendo? Eu tenho esse container com a aplicação da Casa do Código e o Tomcat, e eu tenho o container com o banco de dados do MySQL.
Quando um usuário faz um acesso pra esse container, pra home, está acontecendo o quê? Uma query pro banco de dados. E quanto mais requisições eu fizer pra esse container com a aplicação da Casa do Código ou pra home, mais queries eu vou ter pra esse meu banco de dados e isso pode degradar a performance da nossa aplicação pro usuário final.
Qual é uma forma que a gente pode resolver isso pra evitar justamente de ter essa quantidade exagerada de queries que pode comprometer a performance da nossa aplicação? Qual é uma das formas que a gente pode resolver? É justamente trabalhar com a parte de cacheamento das informações.
Pra gente poder fazer isso, a gente vai trabalhar agora com outro container, que vai ser o container no Nginx. Qual que vai ser a ideia? A ideia é que o Nginx guarde, cacheie as informações dessa nossa aplicação. Então quando um usuário fizer o acesso da nossa aplicação, primeiro ele vai passar pro Nginx.
O Nginx, pelo fato de ter sido feita a primeira requisição, ele ainda não tem nenhuma informação cacheada. Ele vai consultar o container do Tomcat com a aplicação da Casa do Código. E aí, a aplicação da Casa do Código vai fazer a query pro banco de dados. E uma vez que essa informação é retornada pro container do Nginx, ele vai cachear essa informação por um determinado período de tempo.
E durante esse determinado período de tempo, mesmo que outros usuários façam várias requisições pra nossa aplicação, que agora está sendo intermediada pelo Nginx, o Nginx é que vai ficar respondendo essa aplicação para os nossos usuários, e com isso não vou ficar fazendo mais queries pro nosso container com o Tomcat e a aplicação da Casa do Código.
E, consequentemente, também não faremos mais essas queries pra esse banco de dados. E com isso a gente evita de ocasionar uma sobrecarga de queries, de degradar a performance da nossa aplicação.
A nossa tarefa agora vai ser o quê? Configurar esse container do Nginx pra poder trabalhar com a parte de cacheamento dos dados e evitar ter várias queries sendo executadas, o que pode vir a comprometer a performance da nossa aplicação. Vamos fazer isso na próxima etapa. Vamos lá.
Configurando NGINX - Configurando Nginx
Nós devemos agora fazer a configuração do Nginx, pra que ele seja um intermediário nesse processo de comunicação com a nossa aplicação da Casa do Código.
E que o Nginx atue com a parte de armazenamento, o cacheamento dos dados da nossa aplicação. Evitando que sejam feitas várias queries pro nosso banco de dados, o que pode vir a degradar a performance da nossa aplicação.
Vamos abrir o Atom, para fazer essa etapa de configuração do Nginx. O primeiro passo que eu tenho que fazer aqui é especificar pro Nginx qual é a quantidade de núcleos de CPU que vamos estar alocando pro Nginx, pra ele tratar as várias requisições dos usuários.
E a gente faz isso através do comando "worker_processes". E eu passo essa quantidade de núcleos de CPU que vai estar alocando pro Nginx.
Vou colocar aqui, por exemplo, o número 1. Então, vou colocar um núcleo de CPU alocado pro Nginx e coloco ponto e vírgula: "worker_processes 1;". Uma vez que a gente faz isso, precisa especificar pro Nginx quantas requisições ele consegue estar trabalhando simultaneamente.
E a gente consegue fazer essa especificação através do contexto de eventos, eu coloco aqui "events", abre as chaves aqui e dentro desse contexto de eventos passa essas conexões que o Nginx consegue trabalhar simultaneamente. Vou colocar aqui o comando "worker_connections 1024;" e coloca um valor aqui, por exemplo, de 1024 conexões.
Uma vez que nós fizemos isso, nós devemos agora configurar o Nginx pra que ele armazene os dados da nossa aplicação, que realize o cacheamento. E também, pra que quando uma requisição for passada pelo Nginx, que essa requisição seja redirecionada posteriormente para o container que a gente vai ter, com a aplicação da Casa do Código mais o Tomcat na versão 9.
E tudo isso é feito através do contexto aqui http. Então, coloca "http{", abrimos a chave e vamos começar a trabalhar na parte do cacheamento das informações. O primeiro passo que eu tenho que passar pro Nginx é onde que esses dados deverão ser cacheados, deverão ser armazenados no Nginx. É o caminho que eu tenho que especificar, onde esses dados serão armazenados.
Nós colocamos o comando "proxy_cache_path", caminho em inglês é path. E eu dou um diretório aqui do Nging pra armazenar esses dados cacheados. Então, vou colocar aqui o diretório, por exemplo, "var/lib/nginx/cache". Então, esse diretório ainda não existe, gente vai ter que criá-lo posteriormente, só que esse diretório vai ser responsável por armazenar esses dados cacheados.
Legal, só que pro Nginx ter uma melhor performance, o que acontece? O Nginx consegue ter uma melhor performance se esses dados cacheados, forem divididos em subdiretórios. Então dentro desse diretório cache eu vou falar para o Nginx criar diferentes subdiretórios pra dividir esses vários arquivos, e para o Nginx conseguir entregar depois esses arquivos cacheados mais rapidamente para o nosso usuário final.
Vou criar esses níveis de subdiretórios dentro do cache. Vou colocar aqui "levels", que é níveis em inglês. E eu vou colocar que podem variar de um até dois subdiretórios dentro do cache para que o Nginx consiga assim dividir os arquivos e consiga ter uma melhor performance pra entregar esses arquivos cacheados para os nossos usuários finais.
Agora que a gente já especificou isso, eu tenho que passar, também, para o Nginx a informação pra que o Nginx saiba se quando um usuário fizer uma requisição, se esse dado está ou não cacheado.
E isso é feito através das verificações das chaves que o Nginx utiliza. Eu tenho que vir aqui e especificar essa zona dessas chaves que serão analisadas pelo Nginx pra determinar se um dado está cacheado ou não.
A gente coloca aqui "keys_zone" e eu dou um nome pra essa zona, por exemplo, aqui "=casadocodigo". E aqui eu dou um tamanho que vai ser alocado pra essa zona. Eu coloco dois pontos e vou colocar um tamanho aqui, por exemplo, de 8 Megabytes ":8m".
Agora, pra finalizar essa linha de comando do proxy_cache_path, eu posso especificar para o Nginx qual é o tamanho máximo, a quantidade máxima de dados, que serão armazenados aqui como cache pelo Nginx. Quantidade máxima em inglês é max size, então a gente coloca aqui "max_size" e coloca o tamanho. Por exemplo, vou colocar 50 Megabytes, então vou colocar "=50m;".
Agora que a gente já fez essa parte de configuração de onde os dados deverão ser cacheados, precisamos especificar para o Nginx o que é um dado que deve ser cacheado, e o que não deve ser cacheado. Então, tem que falar pro Nginx o que deve e o que não deve ser cacheado.
Pra nós é importante que o Nginx só faça o armazenamento dos dados que de fato estão ok, ou seja, o usuário fez a requisição e teve o retorno com o status http 200 de ok. Então, eu vou falar que somente esse status http 200 é que deve ser armazenado aqui pelo Nginx como sendo um cache de informação pra depois ser retornada para o usuário final.
Vou colocar que o que deve ser armazenado pelo Nginx, o cache válido. Então, vou colocar aqui, "proxy_cache_valid" deve ser somente o que tiver retorno com o status http 200 de ok e eu vou armazenar aqui. Eu tenho que falar pro Nginx por quanto tempo que esses dados deverão ser cacheados. Aí pode ser o tempo que a gente achar mais conveniente.
Pra não ter que ficar esperando muito aqui, na nossa análise, eu vou colocar um tempo, por exemplo, de três minutos. Então vou colocar "3m;", de três minutos e ponto e vírgula.
Isso quer dizer o quê? Que durante três minutos, quando eu for acessar a aplicação da Casa do Código, quem vai retornar os dados pra mim será o conteúdo cacheado pelo Nginx. Depois desses três minutos, o cache vai ter sido expirado e o Nginx vai ter que consultar o nosso container com a aplicação da Casa do Código, pra pegar a última atualização.
Uma vez que nós fizemos essa parte de configuração do cacheamento, tem que configurar o servidor do Nginx, pra que quando uma requisição for passar aqui pro Nginx, que seja redirecionado essa requisição para o container com a aplicação da Casa do Código. Então, vamos subir esse servidor.
A gente coloca aqui o contexto do servidor, "server", abrimos e fechamos as chaves aqui. E a gente vai falar pra esse servidor ficar escutando a porta de comunicação 80, que é a porta utilizada pelo protocolo http. Então eu coloco aqui "listen 80;" pra ficar escutando a porta 80. E aí, agora o que vai acontecer?
Quando o usuário fizer uma requisição para o Nginx, para a raiz, eu quero redirecionar esse acesso pra nossa aplicação da Casa do Código. Então, quando vier a requisição pra localização raiz do Nginx, eu quero redirecionar isso para o nosso container com a aplicação da Casa do Código, "location / {".
Então, eu tenho que colocar o comando "proxy_pass". Eu quero passar essa requisição para o container da Casa do Código. Eu tenho que pegar exatamente agora o nome do container da nossa aplicação. Vamos voltar para o docker compose.
O nome do nosso container com a aplicação da Casa do Código é esse aqui, "container_casadocodigo". Deixa eu copiar pra não ter nenhum erro de digitação, eu o colo aqui e a porta de comunicação utilizada pelo Tomcat é 8080, então eu coloco aqui dois pontos, 8080, ponto e vírgula, "proxy_pass http: //container_casadocodigo: 8080;". Agora o que acontece?
O Nginx está sendo um intermediário nesse processo de comunicação, então quando essa requisição for passada para o container da aplicação da Casa do Código, eu quero passar pra essa aplicação do container com a Casa do Código quem foi o usuário original dessa requisição. Que no caso, vai ser o usuário que vai acessar a aplicação da Casa do Código. Quando o Nginx redirecionar esse tráfego pro container da Casa do Código, eu quero passar os cabeçalhos de quem de fato fez essa requisição.
Pra isso eu tenho que vir aqui e colocar um cabeçalho, "proxy_set_header". Para considerar o host original que fez a requisição. Então, deixa eu colocar aqui "Host $host;" pra considerar todas as informações do host original que fez essa requisição pra aplicação da Casa do Código.
Agora, eu quero falar que quando um usuário fizer essa requisição pra raiz do Nginx, que seja considerado esse cache aqui. Pra isso eu coloco o comando "proxy_cache" pra ser considerado o cache que nós demos o nome Casa do Código "proxy_cache casadocodigo;".
Pra saber se a gente está acessando o conteúdo cacheado, ou não, o que eu vou fazer? Eu vou pedir pro Nginx retornar pra gente uma informação no nosso browser, pra que a gente possa analisar, pra que a gente consiga definir se a gente está conseguindo acessar o conteúdo cacheado do Nginx, ou se a gente está acessando a aplicação da Casa do Código, a última informação que foi feita na nossa aplicação de fato.
Pra ter essa informação: se a gente está acessando o conteúdo cacheado, ou não, eu vou adicionar aqui um cabeçalho, vou colocar o comando "add_header", de cabeçalho. E eu tenho que colocar aqui o comando "X- Proxy-Cache" e eu vou passar esse status que o Nginx vai passar pra gente, pra que essa informação esteja no nosso browser. Então, eu tenho que colocar aqui "$upstream_cache_status;".
Agora, com isso nós terminamos a configuração do nosso Nginx. Vamos salvá-lo aqui, Ctrl + S, e vamos aproveitar e até colocar uma nova pasta aqui, deixa eu colocar a pasta Nginx. E vamos salvar esse arquivo dentro dessa pasta Nginx, da nossa pasta de desenvolvimento do Beanstalk. Esse arquivo de configuração do Nginx vai receber o nome de "nginx.conf", que é um arquivo de configuração que vai ser buscado pelo Nginx.
Agora na próxima etapa, nós vamos pegar a imagem do Nginx, passar esse arquivo de configuração que nós acabamos de criar, e a gente vai ver o resultado que a gente vai ter. Se a gente vai acessar o conteúdo cacheado, se a gente vai ter uma melhoria na nossa aplicação. Vamos lá na sequência.
Sobre o curso Amazon Elastic Beanstalk Parte 2: múltiplos containers e NGINX
O curso Amazon Elastic Beanstalk Parte 2: múltiplos containers e NGINX possui 155 minutos de vídeos, em um total de 55 atividades. Gostou? Conheça nossos outros cursos de AWS em DevOps, ou leia nossos artigos de DevOps.