https://github.com/isaacalves7/scaling-services
⚖️📦➕ It's a repository of scaling services.
https://github.com/isaacalves7/scaling-services
cluster docke-swarm docker docker-compose express kubernetes load-balancing marko mongodb mongoose monolith mvc-architecture nginx nodejs services
Last synced: 2 months ago
JSON representation
⚖️📦➕ It's a repository of scaling services.
- Host: GitHub
- URL: https://github.com/isaacalves7/scaling-services
- Owner: IsaacAlves7
- Created: 2023-04-10T12:25:37.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2023-05-18T04:03:30.000Z (about 3 years ago)
- Last Synced: 2025-03-27T15:52:57.311Z (about 1 year ago)
- Topics: cluster, docke-swarm, docker, docker-compose, express, kubernetes, load-balancing, marko, mongodb, mongoose, monolith, mvc-architecture, nginx, nodejs, services
- Language: JavaScript
- Homepage:
- Size: 322 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# ⚖️ [Docker] Scaling services
> ⚖️📦➕ **Arquitetura da aplicação**: Essa é uma aplicação criada para o modelo cliente-servidor usando o Marko para front-end e Node.js para o back-end, e possui uma estrutura monolítica atuando com a arquitetura MVC (Model View Controller) e ODM (Object Document Model) com Mongoose e MongoDB como banco de dados NoSQL.
Na vida real, sabemos que a aplicação é maior que somente dois containers, geralmente temos dois, três ou mais containers para segurar o tráfego da aplicação, distribuindo a carga. Além disso, temos que colocar todos esses containers para se comunicar com o banco de dados em um outro container, mas quanto maior a aplicação, devemos ter mais de um container para o banco também.
E claro, se temos três aplicações rodando, não podemos ter três endereços diferentes, então nesses casos utilizamos um Load Balancer em um outro container, para fazer a distribuição de carga quando tivermos muitos acessos. Ele recebe as requisições e distribui para uma das aplicações, e ele também é muito utilizado para servir os arquivos estáticos, como imagens, arquivos CSS e JavaScript.
Assim, a nossa aplicação controla somente a lógica, as regras de negócio, com os arquivos estáticos ficando a cargo do Load Balancer.
[](#)
```yaml
version: '3'
services:
nginx:
build:
dockerfile: ./docker/nginx.dockerfile
context: .
image: douglasq/nginx
container_name: nginx
ports:
- "80:80"
networks:
- production-network
depends_on:
- "node1"
- "node2"
- "node3"
mongodb:
image: mongo
container_name: mongodb
networks:
- production-network
node1:
build:
dockerfile: ./docker/alura-books.dockerfile
context: .
image: douglasq/alura-books
container_name: alura-books-1
ports:
- "3000"
networks:
- production-network
depends_on:
- "mongodb"
node2:
build:
dockerfile: ./docker/alura-books.dockerfile
context: .
image: douglasq/alura-books
container_name: alura-books-2
ports:
- "3000"
networks:
- production-network
depends_on:
- "mongodb"
node3:
build:
dockerfile: ./docker/alura-books.dockerfile
context: .
image: douglasq/alura-books
container_name: alura-books-3
ports:
- "3000"
networks:
- production-network
depends_on:
- "mongodb"
networks:
production-network:
driver: bridge
```
Então, para isso foi criada uma ferramenta no Docker chamada **Docker Compose**, que ele executa e auxilia na build ou criação de vários (múltiplos) containers simultaneamente. Ele funciona seguindo um arquivo de texto, chamado `docker-compose.yaml`.
Esse arquivo serve para dar um conjunto de passos ao Docker e com ele podemos controlar quais containers sobem primeiro, ou seja, funciona como um processo de BIOS ou um automatizador de containers. O **Docker Compose** cria uma rede padrão, também é possível criar uma nova rede usando o comando `docker network`.
Essa aplicação possui servidor, rotas e banco de dados. De novidade, é que agora precisamos criar o **NGINX**, que é mais um container que devemos subir.
Então, ao utilizarmos a **imagem nginx**, ou criamos a nossa própria. Como vamos configurar o NGINX para algumas coisas específicas, como lidar com os **arquivos estáticos**, vamos criar a nossa própria imagem, por isso que na aplicação há o `nginx.dockerfile`:
[](#)
```dockerfile
FROM nginx:latest
MAINTAINER isaacalves7
COPY /public /var/www/public
COPY /docker/config/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80 443
ENTRYPOINT ["nginx"]
# Parametros extras para o entrypoint
CMD ["-g", "daemon off;"]
```
Nesse arquivo, nós utilizamos a última versão disponível da imagem do nginx como base, e copiamos o conteúdo da pasta `public`, que contém os arquivos estáticos, e um arquivo de configuração do NGINX para dentro do container. Além disso, abrimos as portas `80` e `443` e executa o NGINX através do comando nginx, passando os parâmetros extras `-g` e `daemon off`.
Por fim, vamos ver um pouco sobre o *arquivo de configuração do NGINX*, para entendermos um pouco como o **load balancer** está funcionando.
[](#)
No arquivo `nginx.conf`, dentro server, está a parte que trata de servir os *arquivos estáticos*. Na `porta 80`, no localhost, em `/var/www/public`, ele será responsável por servir as pastas `css`, `img` e `js`. E todo resto, que não for esses três locais, ele irá jogar para o `node_upstream`.
No **node_upstream**, é onde ficam as configurações para o NGINX redirecionar as conexões que ele receber para um dos três containers da nossa aplicação. O redirecionamento acontecerá de forma circular (fila circular - estrutura de dados), ou seja:
1. A primeira conexão irá para o primeiro container;
2. A segunda irá para o segundo container;
3. A terceira irá para o terceiro container;
4. Na quarta, começa tudo de novo, e ela vai para o primeiro container e assim por diante.
Agora, começamos a descrever os nossos **serviços** (services):
> Um serviço é uma parte da nossa aplicação dockerizada, lembrando do diagrama acima.
Temos um nó com NGINX, três nós com Node.js, e um nó com MongoDB como serviços. Logo, se queremos construir cinco containers, vamos construir cinco serviços, cada um deles com um nome específico.
Então, vamos começar construindo o NGINX, que terá o nome `nginx`. Em cada serviço, devemos dizer como devemos construí-lo, como devemos fazer o seu build.
O serviço será construído através de um `Dockerfile`, então devemos passá-lo onde ele está. E também devemos passar um contexto, para dizermos a partir de onde o `Dockerfile` deve ser buscado. Como ele será buscado a partir da pasta atual, vamos utilizar o ponto:
Construída a imagem, devemos dar um nome para ela, por exemplo `douglasq/nginx`. E quando o Docker Compose criar um container a partir dessa imagem, vamos dizer que o seu nome será `nginx`.
Sabemos também que o NGINX trabalha com duas portas, a `80` (HTTP) e a `443`(HTTPS). Como não estamos trabalhando com HTTPS, vamos utilizar somente a porta `80`, e no próprio arquivo, podemos dizer para qual porta da nossa máquina queremos mapear a porta `80` do container. Vamos mapear para a porta de mesmo número da nossa máquina.
No YAML, toda vez que colocamos um traço, significa que a propriedade pode receber mais de um item. Agora, para os containers conseguirem se comunicar, eles devem estar na mesma rede, então vamos configurar isso também. Primeiramente, devemos criar a rede, que não é um serviço, então vamos escrever do começo do arquivo, sem as tabulações:
O nome da rede será `production-network` e utilizará o driver `bridge`: Com a rede criada, vamos utilizá-la no serviço.
Isso é para construir o **serviço do NGINX**, agora vamos construir o **serviço do MongoDB**, com o nome `mongodb`. Como ele será construído a partir da imagem `mongo`, não vamos utilizar nenhum Dockerfile, logo não utilizamos a propriedade `build`. Além disso, não podemos nos esquecer de colocá-lo na rede que criamos.
Falta agora criarmos os três serviços em que ficará a nossa aplicação: `node1`, `node2` e `node3`. Para eles, será semelhante ao NGINX, com Dockerfile `alura-books.dockerfile`, contexto da rede `production-network` e porta `3000`: Com isso, a construção dos nossos serviços está finalizada.
Por último, quando subimos os containers na mão, temos uma ordem, primeiro devemos subir o `mongodb`, depois a nossa aplicação, ou seja, `node1`, `node2` e `node3` e após tudo isso subimos o `nginx`. Mas como que fazemos isso no `docker-compose.yml`? Nós podemos dizer que os serviços da nossa aplicação dependem que um serviço suba antes deles, o serviço do `mongodb`. Da mesma forma, dizemos que o serviço do `nginx` depende dos serviços `node1`, `node2` e `node3`.
## Subindo os serviços
Com o `docker-compose.yml` pronto, podemos subir os serviços, mas antes devemos garantir que temos todas as imagens envolvidas neste arquivo na nossa máquina. Para isso, dentro da pasta do nosso projeto, executamos o seguinte comando:
Inicio/Build do Docker Compose
```sh
docker-compose build
```
Depois de buildar os serviços, eles podem ser vistos em:
```sh
docker images
```
Após isso, podemos inserir o comando:
```sh
docker-compose up # ou docker-compose up -d
```
Listando e verificando o docker-compose
```sh
docker-compose ps
```
Para e remove todos os containers do docker-compose
```sh
docker-compose down
```
Verificando que os containers estão se comunicando
```sh
docker exec -it alura-books-1 ping alura-books-2
docker exec -it alura-books-1 ping node2
```
Reinicializando containers
```sh
docker-compose restart
```