Implantação com Contêineres Docker
Docker é uma revolução na implantação — construa uma vez, execute em qualquer lugar e diga adeus à desculpa "funciona na minha máquina".
1. O Que Você Vai Aprender
- Builds multi-stage de Dockerfile: Imagem Builder + Imagem Runtime (Distroless / Eclipse Temurin)
- Otimização com
.dockerignoree Estratégias de Cache de Camadas da Imagem - Orquestração com Docker Compose: OrderFlow, MySQL e Redis — Três Servidos Trabalhando Juntos
- Injeção de Variáveis de Ambiente e Externalização de Configuração
- Bob construiu uma imagem Docker do OrderFlow de nível produtivo menor que 150 MB
2. Uma História Real de um Engenheiro de Operações
(1) Dor: Ambiente Inconsistente
Depois que Bob terminou de depurar o OrderFlow localmente e o implantou em produção, o serviço falhou ao iniciar devido a versões incompatíveis do driver MySQL, versões inconsistentes do JDK e configurações de fuso horário diferentes. Cada implantação exigia meio dia para solucionar discrepâncias de ambiente, e "Funciona na minha máquina" tornou-se o lema da equipe. Para piorar, os três servidores exigiam três implantações manuais separadas, e configurações eram frequentemente esquecidas.
(2) A Solução Docker
O Docker empacota a aplicação e todas as suas dependências em uma única imagem:
FROM eclipse-temurin:17-jre-alpine
COPY target/orderflow-service.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Implante com um único comando, garantindo um ambiente completamente consistente.
(3) Resultado
Depois que Bob começou a usar Docker, a imagem era construída uma vez localmente, e todos os três servidores faziam pull e executavam a partir da mesma fonte, eliminando inconsistências de ambiente. Um único comando do Docker Compose inicia o ambiente completo — OrderFlow, MySQL e Redis — e novos funcionários podem executá-lo localmente em apenas cinco minutos.
3. Dockerfile Multi-stage
(1) Processo de Build Multi-stage
graph TD
A["Estágio 1: Builder<br/>Maven + JDK 17<br/>Compilar + Empacotar"] --> B["orderflow-service.jar"]
B --> C["Estágio 2: Runtime<br/>JRE 17 Alpine<br/>Copiar apenas o JAR"]
C --> D["Imagem Final<br/>~150MB"]
(1) ▶ Exemplo: Dockerfile Multi-stage
# Estágio 1: Build
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
# Copiar pom.xml primeiro para cache de dependências
COPY pom.xml .
RUN mvn dependency:go-offline -B
# Copiar código-fonte e construir
COPY src ./src
RUN mvn package -DskipTests -B
# Estágio 2: Runtime
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# Criar usuário não-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Copiar JAR do builder
COPY --from=builder /build/target/*.jar app.jar
# Definir propriedade
RUN chown -R appuser:appgroup /app
USER appuser
# Expor porta
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
# Executar aplicação
ENTRYPOINT ["java", \
"-XX:+UseG1GC", \
"-XX:MaxRAMPercentage=75.0", \
"-jar", "app.jar"]
Saída:
// Execução bem-sucedida
| Imagem Base | Tamanho | Segurança | Casos de Uso |
|---|---|---|---|
eclipse-temurin:17 |
~450MB | Média | Desenvolvimento/Testes |
eclipse-temurin:17-jre-alpine |
~170MB | Média-Alta | Recomendada para Produção |
gcr.io/distroless/java17-debian12 |
~100MB | Máxima | Segurança Extrema |
(2) ▶ Exemplo: Imagem Distroless
# Estágio 1: Build
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
# Estágio 2: Runtime Distroless
FROM gcr.io/distroless/java17-debian12
COPY --from=builder /build/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Saída:
// Execução bem-sucedida
docker exec -it para entrar no modo de depuração. Elas são recomendadas para produção, mas use a imagem Alpine para depuração.
4. .dockerignore e Otimização de Imagem
(1) ▶ Exemplo: .dockerignore
# .dockerignore
.git
.github
.idea
*.md
target/
!target/*.jar
node_modules/
*.log
.env
docker-compose*.yml
Dockerfile*
| Estratégia de Otimização | Efeito | Descrição |
|---|---|---|
.dockerignore Excluir arquivos desnecessários |
Reduz o contexto de build | Não enviar .git, .idea, etc. |
| Primeiro, COPY pom.xml | Cachear dependências | Pular download se dependências não mudaram |
| Build multi-stage | Reduz o tamanho final da imagem | Não inclui Maven ou código-fonte |
| JRE em vez de JDK | Economiza ~200MB | Não requer ferramentas de compilação em runtime |
| Imagem Base Alpine | Reduzido em ~280MB | Um sistema Linux mínimo usando musl libc |
5. Orquestração Multi-Serviço com Docker Compose
(1) ▶ Exemplo: OrderFlow + MySQL + Redis
# docker-compose.yml
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
DB_HOST: mysql
DB_USERNAME: orderflow
DB_PASSWORD: ${DB_PASSWORD:-orderflow123}
REDIS_HOST: redis
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 3s
retries: 5
restart: unless-stopped
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: orderflow
MYSQL_USER: orderflow
MYSQL_PASSWORD: ${DB_PASSWORD:-orderflow123}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root123}
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
volumes:
mysql-data:
redis-data:
Saída:
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
(2) ▶ Exemplo: Inicialização e Verificação
# Construir e iniciar todos os serviços
docker compose up -d --build
# Verificar status dos serviços
docker compose ps
# Visualizar logs da aplicação
docker compose logs -f app
# Testar API
curl http://localhost:8080/actuator/health
# Parar todos os serviços
docker compose down -v
Saída:
CONTAINER ID IMAGE STATUS
abc123 latest Up 2 hours
| Comando | Descrição |
|---|---|
docker compose up -d |
Iniciar em segundo plano |
docker compose down |
Parar e remover contêineres |
docker compose logs -f app |
Visualizar logs da aplicação |
docker compose ps |
Verificar status dos serviços |
docker compose build |
Apenas construir a imagem |
6. Injeção de Variáveis de Ambiente
(1) ▶ Exemplo: Externalizando Configuração
# application-prod.yml (na imagem Docker)
spring:
datasource:
url: jdbc:mysql://${DB_HOST:localhost}:3306/orderflow
username: ${DB_USERNAME:orderflow}
password: ${DB_PASSWORD:defaultpass}
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
| Método de Configuração | Prioridade | Cenários Aplicáveis |
|---|---|---|
Docker Compose environment |
Alta | Implantação Simplificada |
Arquivo .env |
Média | Desenvolvimento Local |
| K8s ConfigMap / Secret | Alta | Produção |
# arquivo .env
DB_PASSWORD=secure_password_here
DB_ROOT_PASSWORD=root_secure_here
REDIS_PASSWORD=redis_secure_here
7. Exemplo Completo: Dockerização Completa do OrderFlow
# Dockerfile
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
EXPOSE 8080 8081
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-XX:+UseG1GC", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
# docker-compose.yml
version: "3.9"
services:
app:
build: .
ports:
- "8080:8080"
- "8081:8081"
environment:
SPRING_PROFILES_ACTIVE: prod
DB_HOST: mysql
DB_USERNAME: orderflow
DB_PASSWORD: ${DB_PASSWORD:-orderflow123}
REDIS_HOST: redis
MANAGEMENT_SERVER_PORT: "8081"
depends_on:
mysql: { condition: service_healthy }
redis: { condition: service_healthy }
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_DATABASE: orderflow
MYSQL_USER: orderflow
MYSQL_PASSWORD: ${DB_PASSWORD:-orderflow123}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root123}
volumes: [mysql-data:/var/lib/mysql]
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s; timeout: 5s; retries: 10
redis:
image: redis:7-alpine
volumes: [redis-data:/data]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s; timeout: 3s; retries: 5
volumes:
mysql-data:
redis-data:
❓ Perguntas Frequentes
docker compose logs -f app para visualizar logs; 2) docker compose exec app sh para entrar no contêiner (imagem Alpine); 3) Depuração remota: ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "app.jar"].depends_on e healthcheck?depends_on apenas garante a ordem de inicialização dos contêineres; não garante que o serviço esteja pronto. Quando usado em conjunto com condition: service_healthy, o Docker Compose aguardará o health check passar antes de iniciar o serviço dependente.mvn dependency:go-offline para aproveitar o cache de camadas do Docker; 2) Use .dockerignore para excluir arquivos irrelevantes; 3) Use montagem de cache do BuildKit.ndots). Alpine é recomendada para cenários com apenas JRE.📖 Resumo
- Dockerfile multi-stage: Compilação no estágio Builder + estágio Runtime contendo apenas o JAR e JRE
.dockerignoreexclui arquivos irrelevantes; primeiro COPY pom.xml para aproveitar a camada de cache- Docker Compose para orquestração multi-serviço: app + MySQL + Redis, com health checks para controlar a ordem de inicialização
- Configurar injeção de variáveis de ambiente; armazenar informações sensíveis em um arquivo .env ou K8s Secret
- Para construção de imagens, recomendamos Eclipse Temurin JRE Alpine (~170 MB) ou Distroless (~100 MB)
- Executar como usuário não-root; HEALTHCHECK é essencial para produção
📝 Exercícios
-
Exercício Básico (Dificuldade ⭐): Escreva um Dockerfile para o OrderFlow, construa a imagem, execute localmente e verifique que
/actuator/healthretorna "UP." -
Exercício Avançado (Dificuldade: ⭐⭐): Escreva um arquivo
docker-compose.ymlpara orquestrar os três serviços — OrderFlow, MySQL e Redis — e configurehealthcheckedepends_onpara garantir que os serviços iniciem na ordem correta. -
Desafio (Dificuldade: ⭐⭐⭐): Otimize a imagem para menos de 150 MB, use a imagem base Distroless, configure os parâmetros de memória da JVM (
MaxRAMPercentage) e adicione um usuário não-root e configurações relacionadas à segurança.



