📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados em Cap. 09 (Nginx) do Guia de Redes. Recomendado revisar antes de começar.
🚀 Projeto: Nginx com Balanceamento de Carga (Java 21 / Spring Boot)`
Criar um ambiente que simula um sistema web real, demonstrando visualmente como o Nginx atua como um Reverse Proxy e distribui a carga (Load Balancing) entre duas instâncias idênticas de uma API Spring Boot.
Este projeto é a versão em Java/Spring Boot do mesmo experimento feito com Node.js em infra_nginx_01_nodejs — a diferença central é que aqui as duas instâncias de backend rodam a partir do mesmo .jar, diferenciadas apenas por uma variável de ambiente (SERVER_ID), em vez de serem dois projetos separados.`
graph TD
subgraph "Cliente"
User["Navegador (Browser)"]
end
subgraph "Docker Compose Network"
Nginx["Nginx (Load Balancer & Proxy Reverso)"]
API_01["api-01 (Spring Boot, SERVER_ID=API-01)"]
API_02["api-02 (Spring Boot, SERVER_ID=API-02)"]
Visualizer["Visualizador (Static Files)"]
end
User -->|":80 /"| Nginx
Nginx -->|"/api (Load Balancing)"| API_01
Nginx -->|"/api (Load Balancing)"| API_02
Nginx -->|"Server Files"| Visualizer
Visualizer -->|"fetch('/api')"| Nginx
spring-boot-starter-web).—`
infra_nginx_02_spring/
├── src/main/java/br/com/tarefas/load_balancing_01/
│ ├── ApiController.java
│ └── LoadBalancing01Application.java
├── src/main/resources/application.properties
├── pom.xml
├── Dockerfile
├── nginx/
│ ├── nginx.conf
│ └── Dockerfile
├── visualizer/
│ └── index.html
└── docker-compose.yml
—`
Ao contrário da versão Node.js (dois projetos api-01/api-02), aqui existe um único projeto Spring Boot. As duas “instâncias” no Docker Compose sobem a mesma imagem, cada uma com um valor diferente de SERVER_ID injetado via variável de ambiente.
pom.xml — dependências principais: spring-boot-starter-web (Java 21).src/main/java/.../ApiController.java:
package br.com.tarefas.load_balancing_01;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Date;
@RestController
public class ApiController {
// Injeta o valor da variável de ambiente 'SERVER_ID'
// Se não for definida, usará 'API-DEFAULT'
@Value("${SERVER_ID:API-DEFAULT}")
private String serverId;
@GetMapping("/api")
public Map<String, Object> getApiData() {
System.out.println("[" + serverId + "] Recebeu requisição");
return Map.of(
"servidor", serverId,
"timestamp", new Date().toString()
);
}
}
src/main/resources/application.properties:
spring.application.name=load_balancing_01
—`
# Estágio 1: Build (Compilação)
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
# Estágio 2: Run (Execução)
FROM eclipse-temurin:21-jre-jammy
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
# A variável SERVER_ID será injetada pelo Docker Compose
ENTRYPOINT ["java", "-jar", "app.jar"]
—`
nginx/nginx.conf:
upstream backend_servers {
# O padrão é round-robin (alterna entre eles)
# Note a porta 8080, padrão do Spring Boot
server api-01:8080;
server api-02:8080;
}
events { }
http {
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /api {
rewrite /api(.*) /$1 break;
proxy_pass http://backend_servers;
proxy_set_header Host $host; proxy_set_header X-Real-IP$remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto$scheme;
}
}
}
nginx/Dockerfile:
FROM nginx:1.23-alpine
# Copia nossa configuração personalizada (relativo ao 'context')
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
# Copia os arquivos do visualizer (relativo ao 'context')
COPY ./visualizer /usr/share/nginx/html
—`
visualizer/index.html consome fetch('/api') a cada 200ms e monta um gráfico de pizza (Chart.js via CDN) com a contagem de respostas de cada SERVER_ID, igual ao dashboard de infra_nginx_01_nodejs — o payload JSON (servidor/timestamp) é o mesmo formato, então o mesmo dashboard funciona sem alteração.
—`
services:
api-01:
build:
context: .
dockerfile: ./Dockerfile
environment:
- SERVER_ID=API-01
api-02:
build:
context: .
dockerfile: ./Dockerfile
environment:
- SERVER_ID=API-02
nginx:
build:
context: .
dockerfile: ./nginx/Dockerfile
ports:
- "80:80"
depends_on:
- api-01
- api-02
Note que api-01 e api-02 usam o mesmo Dockerfile/contexto — a diferença entre eles é só a variável de ambiente SERVER_ID.
—`
1. Suba os serviços:
docker-compose up --build
Isso constrói a imagem Spring Boot (usada duas vezes, para api-01 e api-02) e a imagem do Nginx.
2. Acesse o Visualizador:
Abra http://localhost. O dashboard começa a fazer requisições automaticamente e o gráfico de pizza deve convergir para ~50%/50% entre API-01 e API-02.
3. (Opcional) Teste de carga com k6:
Reaproveite o load-test.js de infra_nginx_01_nodejs apontando para http://localhost/api — a rota é idêntica.
4. Para desligar:
docker-compose down
—`
No seu editor/IDE, abra a pasta deste projeto (File > Open Folder) ou navegue via terminal:
cd infra_nginx_02_spring
terraform init && terraform plan
# ou docker-compose up -d
[!TIP] Dica para execução a partir da raiz do repositório: Se você abriu o repositório completo no VS Code, basta navegar até a pasta antes de executar: cd proj_aplicacoes_full_stack/projetos/infra_nginx_02_spring