Docker é uma plataforma que permite empacotar, distribuir e executar aplicações dentro de containers.
Um container é como uma “caixinha” que contém tudo o que uma aplicação precisa para rodar: código, bibliotecas, dependências e configurações.
Vantagens principais:
- Portabilidade: funciona da mesma forma em qualquer ambiente (seja no seu notebook, em um servidor ou na nuvem).
- Rapidez: containers são mais leves e iniciam em segundos, diferentemente de máquinas virtuais.
- Escalabilidade: fácil criar múltiplas instâncias da mesma aplicação.
- Isolamento: cada container roda separado, evitando conflitos de dependências.
| Aspecto | Containers 🐳 | VMs 💻 |
|---|---|---|
| Peso | Leves (compartilham kernel do SO) | Pesadas (SO completo por VM) |
| Inicialização | Segundos | Minutos |
| Consumo de Recursos | Baixo | Alto |
| Portabilidade | Alta (mesma imagem em qualquer host) | Menor (dependente do hypervisor) |
| Isolamento | Bom (nível de processo) | Forte (nível de hardware) |
Resumo: Containers são ideais para desenvolvimento ágil e escalável, enquanto VMs ainda são úteis para cenários que exigem isolamento extremo.
Imagem:
- Modelo imutável que descreve o ambiente de execução.
- Contém o sistema operacional mínimo + bibliotecas + código da aplicação.
- Exemplo:
node:20-alpine(imagem oficial do Node.js baseada no Alpine Linux).
Container:
- Instância em execução de uma imagem.
- Você pode criar vários containers a partir da mesma imagem.
- Containers são descartáveis: você pode parar, remover e recriar rapidamente.
📝 Analogia:
- Imagem = receita de bolo.
- Container = o bolo pronto feito a partir da receita.
A arquitetura do Docker é composta por quatro partes principais:
- Ferramenta de linha de comando (
docker run,docker ps, etc.). - O usuário interage com o Docker por aqui.
- Processo em background que faz todo o trabalho “pesado”.
- Cria, gerencia e executa containers e imagens.
- Conjunto formado pelo Client + Daemon.
- É o “motor” do Docker que executa e gerencia containers.
- Local onde imagens são armazenadas e distribuídas.
- O Docker Hub é o registro público padrão (como um “GitHub de imagens”).
- Também é possível ter registries privados (AWS ECR, GitHub Packages, etc.).
🔗 Fluxo básico de uso:
- Você pede ao Client:
docker run nginx. - O Daemon busca a imagem no Registry (Docker Hub).
- O Daemon cria um container a partir dessa imagem.
- O container roda no seu sistema.
O que são:
Uma imagem é um “pacote” que contém tudo que uma aplicação precisa para rodar (bibliotecas, dependências, binários e arquivos de configuração).
Camadas (Layers):
- Cada instrução do
Dockerfile(ex.:RUN,COPY,ADD) cria uma camada. - Essas camadas são cacheadas → reaproveitamento em builds futuros.
- Camadas imutáveis: apenas a camada final muda ao atualizar.
Reuso:
- Imagens podem ser baseadas em outras.
- Exemplo:
FROM node:20-alpine→ reaproveita uma imagem oficial.
Versionamento:
- Controlado por tags (ex.:
nginx:1.25,nginx:latest). - Tags ajudam a garantir consistência no ambiente (evitar
latestem produção).
O que são:
- São instâncias em execução de uma imagem.
- Criados, parados e removidos rapidamente.
Ciclo de vida:
docker run # cria e inicia um container
docker start # inicia um container parado
docker stop # para um container
docker restart # reinicia um container
docker rm # remove definitivamente um container📝 Exemplo prático:
docker run -d --name meu_nginx nginx:latest
docker stop meu_nginx
docker start meu_nginx
docker rm -f meu_nginxProblema: Containers são efêmeros → ao parar/remover, dados internos são perdidos.
Solução: Volumes.
Tipos de volumes:
- Volumes gerenciados (
docker volume create): mantidos pelo Docker. - Bind mounts: mapeiam uma pasta do host para dentro do container.
Exemplo prático:
docker run -d -v meu_volume:/var/lib/mysql mysql:8➡️ Os dados do banco ficam persistentes no volume meu_volume.
O Docker cria redes virtuais para comunicação entre containers.
Tipos principais:
- Bridge (padrão): containers comunicam-se entre si usando nomes/IPs.
- Host: o container compartilha a rede do host (desempenho/necessidades especiais).
- Overlay: usada em clusters (ex.: Docker Swarm, Kubernetes).
Comandos úteis:
docker network ls
docker network create minha_rede
docker run --network minha_rede ...Docker Hub:
- Registro público oficial de imagens.
- Possui imagens oficiais (ex.:
nginx,postgres,node).
Registries privados:
- Empresas podem manter repositórios privados para imagens internas.
- Exemplos: AWS ECR, Azure ACR, GitHub Packages, GitLab Registry.
Autenticação:
docker login my-registry.com
docker push my-registry.com/minha-imagem:1.0✅ Resumo visual:
- Imagens → base imutável (receita).
- Containers → instâncias vivas (o prato pronto).
- Volumes → guardam dados mesmo após o container morrer.
- Redes → conectam containers entre si.
- Registries → bibliotecas de imagens (públicas ou privadas).
Cria e executa um container a partir de uma imagem.
Principais opções:
-d→ executa em background (detached).--name→ dá um nome ao container.-p→ mapeia portas (host:container).-v→ monta volumes.
📝 Exemplo:
docker run -d --name meu_nginx -p 8080:80 nginx:latest➡️ Sobe o Nginx no background, acessível em http://localhost:8080.
Lista os containers em execução.
Use -a para ver todos (inclusive parados).
docker ps
docker ps -aParar um container ativo:
docker stop meu_nginxRemover um container (parado ou com -f forçando):
docker rm meu_nginxListar imagens disponíveis localmente:
docker imagesRemover uma imagem não utilizada:
docker rmi nginx:latestExecuta comandos dentro de um container em execução (ex.: abrir um shell).
docker exec -it meu_nginx bash➡️ Abre um terminal interativo dentro do container meu_nginx.
Mostra os logs de um container (útil para depuração).
docker logs meu_nginx
docker logs -f meu_nginx # segue os logs em tempo realBaixar imagens do Docker Hub ou registry privado:
docker pull postgres:16Enviar imagens para um registry:
docker tag minha_api:1.0 my-registry.com/minha_api:1.0
docker push my-registry.com/minha_api:1.0✅ Resumo rápido dos comandos básicos:
| Comando | Função |
|---|---|
docker run |
Criar e executar container |
docker ps |
Listar containers |
docker stop |
Parar container |
docker rm |
Remover container |
docker images |
Listar imagens |
docker rmi |
Remover imagem |
docker exec |
Executar comando dentro do container |
docker logs |
Ver logs do container |
docker pull |
Baixar imagem do registry |
docker push |
Enviar imagem para registry |
- É um arquivo de texto que contém instruções para construir uma imagem Docker.
- Funciona como uma receita: cada linha define uma etapa que será transformada em uma camada da imagem.
- Nome padrão:
Dockerfile(sem extensão).
Um Dockerfile típico tem a seguinte estrutura:
# Imagem base
FROM node:20-alpine
# Diretório de trabalho
WORKDIR /app
# Copiar arquivos para dentro do container
COPY package*.json ./
RUN npm install
COPY . .
# Porta exposta
EXPOSE 3000
# Comando padrão
CMD ["npm", "start"]Define a imagem base a ser utilizada.
Exemplo:
FROM python:3.11-slimExecuta comandos durante a construção da imagem.
Exemplo:
RUN apt-get update && apt-get install -y curlCopia arquivos do host para dentro da imagem.
Exemplo:
COPY . /appDefine o diretório de trabalho dentro da imagem.
Exemplo:
WORKDIR /appDefine o comando padrão a ser executado quando o container iniciar.
Só pode existir um CMD → se tiver vários, apenas o último é usado.
Exemplo:
CMD ["node", "server.js"]Parecido com CMD, mas torna o comando fixo.
O que for passado no docker run será tratado como argumento.
Exemplo:
ENTRYPOINT ["python", "app.py"]Para construir uma imagem a partir de um Dockerfile:
docker build -t minha_api:1.0 .-t→ define nome e tag da imagem..→ indica o diretório atual (onde está o Dockerfile).
- Use imagens oficiais leves (ex.:
alpine,slim).- Exemplo:
node:20-alpineem vez denode:20.
- Exemplo:
- Combine comandos
RUNpara reduzir camadas.RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* - Copie apenas o necessário (use
.dockerignorepara excluir arquivos). - Multi-stage builds → construa em uma imagem maior e copie o resultado para uma imagem final menor.
# Etapa 1: build
FROM node:20 as builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Etapa 2: imagem final
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html➡️ Apenas o resultado final vai para produção.
✅ Resumo
- Dockerfile = receita de uma imagem.
- Instruções principais:
FROM,RUN,COPY,WORKDIR,CMD,ENTRYPOINT. - Build com
docker build. - Boas práticas → imagens leves, multi-stage builds,
.dockerignore.
- Containers são efêmeros → quando param ou são removidos, os dados internos desaparecem.
- Para manter dados além do ciclo de vida do container, usamos volumes.
- Volumes permitem:
- Persistência de dados.
- Compartilhamento entre múltiplos containers.
- Backup e migração de informações.
Existem duas formas comuns de montar volumes em containers:
docker run -d -v meu_volume:/var/lib/mysql mysql:8- Cria um volume chamado
meu_volume. - Monta-o no caminho
/var/lib/mysqldentro do container.
docker run -d --mount source=meu_volume,target=/var/lib/mysql mysql:8- Sintaxe mais explícita e flexível.
- Útil para configurações avançadas.
Mapeia um diretório do host para dentro do container.
Exemplo:
docker run -v $(pwd):/app node:20➡️ O diretório atual do host é acessível dentro do container em /app.
- Prós: fácil para desenvolvimento (edição em tempo real).
- Contras: depende do host → menos portável.
Criados e gerenciados pelo Docker.
Local padrão: /var/lib/docker/volumes/.
Exemplo:
docker volume create dados_db
docker run -d -v dados_db:/var/lib/mysql mysql:8- Prós: mais portáveis, ideais para produção.
- Contras: menos transparência (não acessíveis diretamente no host sem comandos Docker).
Bancos de Dados
docker run -d -v db_dados:/var/lib/postgresql/data postgres:16Arquivos de Configuração
docker run -d -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf nginx:latestAmbiente de Desenvolvimento
docker run -it -v $(pwd):/app node:20 bash✅ Resumo
- Volumes resolvem o problema da perda de dados quando containers são removidos.
- Bind mount: conecta pasta do host → bom para desenvolvimento.
- Volumes gerenciados: controlados pelo Docker → melhor para produção.
- Principais usos: bancos de dados, configs, desenvolvimento colaborativo.
Quando instalamos o Docker, ele cria redes padrão automaticamente:
- Rede privada criada pelo Docker.
- Usada quando não especificamos nenhuma rede.
- Containers conectados a essa rede podem se comunicar entre si usando IP interno ou nome do container.
Exemplo:
docker run -d --name web1 nginx
docker run -d --name web2 nginx
# web1 pode acessar web2 usando:
# curl http://web2- O container não terá rede.
- Sem comunicação externa → usado em casos de segurança ou processamento isolado.
docker run -d --network none alpine sleep 3600- O container compartilha a rede do host.
- Útil para performance de rede ou serviços que precisam expor portas diretamente.
docker run -d --network host nginx➡️ O Nginx escutará diretamente nas portas do host.
Podemos criar redes personalizadas para organizar melhor os containers.
Criar uma rede
docker network create minha_redeRodar containers na rede
docker run -d --name app --network minha_rede nginx
docker run -d --name db --network minha_rede postgresInspecionar redes
docker network ls
docker network inspect minha_rede➡️ Assim, app pode se conectar ao db usando o nome db.
Containers na mesma rede podem se comunicar pelo nome do container.
Exemplo:
db(PostgreSQL) rodando na redeapp_net.api(Node.js) também conectado àapp_net.- A
apipode acessar o banco usandodb:5432no lugar delocalhost.
📝 Exemplo prático:
docker network create app_net
docker run -d --name db --network app_net -e POSTGRES_PASSWORD=123 postgres:16
docker run -d --name api --network app_net meu_api:1.0✅ Resumo
- Redes padrão:
bridge: comunicação isolada entre containers.none: sem rede.host: usa a rede do host.
- Redes customizadas → maior controle, containers se comunicam pelo nome.
- Comunicação entre containers → usar nomes de container ou service name (em Compose/Kubernetes).
- Docker Compose é uma ferramenta para definir e gerenciar múltiplos containers como um único serviço.
- Permite descrever toda a stack da aplicação em um arquivo
docker-compose.yml. - Ideal para:
- Projetos com vários serviços (ex.: frontend + backend + banco).
- Facilitar o desenvolvimento local (um único comando sobe tudo).
- Garantir que todos usem a mesma configuração.
Exemplo básico:
version: "3.9"
services:
web:
image: nginx:latest
ports:
- "8080:80"
api:
build: ./api
ports:
- "3000:3000"
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:Subir serviços:
docker compose upSubir em segundo plano (detached):
docker compose up -dParar e remover serviços:
docker compose downVer containers ativos:
docker compose psVer logs dos serviços:
docker compose logs -fStack completa
version: "3.9"
services:
frontend:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./frontend:/usr/share/nginx/html
backend:
build: ./backend
ports:
- "3000:3000"
environment:
DB_HOST: db
DB_USER: user
DB_PASS: pass
depends_on:
- db
db:
image: postgres:16
restart: always
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:➡️ Neste exemplo:
- O frontend (Nginx) serve arquivos estáticos.
- O backend (API) se comunica com o banco usando
db:5432. - O Postgres mantém dados persistentes em
db_data.
✅ Resumo
- Docker Compose simplifica o gerenciamento de múltiplos containers.
- Arquivo central:
docker-compose.yml. - Comandos principais:
up,down,ps,logs. - Permite criar stacks completas (web + api + db) com poucas linhas.
Mostra detalhes completos de um container ou imagem em formato JSON.
Informações disponíveis:
- Configuração (volumes, redes, portas).
- Variáveis de ambiente.
- Caminhos de montagem.
- Status de execução.
Exemplo:
docker inspect meu_container➡️ Útil para depuração ou checar parâmetros de rede e volumes.
Mostra a saída padrão (stdout e stderr) de um container.
Usos comuns:
- Ver mensagens de erro.
- Acompanhar execução em tempo real.
Exemplo:
docker logs meu_api
docker logs -f meu_api # segue logs em tempo realExibe uso em tempo real de recursos de cada container:
- CPU (%)
- Memória usada
- I/O de disco
- Tráfego de rede
Exemplo:
docker stats➡️ Semelhante ao top do Linux, mas para containers.
Verificam se o container está saudável.
Podem ser configurados no Dockerfile ou no Compose.
Permitem que orquestradores (Compose, Swarm, Kubernetes) saibam se o container precisa ser reiniciado.
Healthcheck no Dockerfile
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1➡️ Verifica a cada 30s se a rota /health responde.
Healthcheck no Docker Compose
version: "3.9"
services:
api:
build: ./api
ports:
- "3000:3000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3✅ Resumo
docker inspect→ informações detalhadas do container.docker logs→ análise de execução e erros.docker stats→ monitoramento de consumo de recursos.- Healthchecks → garantem que o container esteja realmente funcionando.
Por padrão, muitos containers rodam como usuário root → aumenta o risco de segurança se alguém explorar vulnerabilidades.
Boa prática: criar e usar usuários não-root.
Exemplo em Dockerfile:
FROM node:20-alpine
# Cria um usuário
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY . .
# Define o usuário para execução
USER appuser
CMD ["node", "server.js"]➡️ Assim, mesmo que o container seja comprometido, o invasor terá privilégios limitados.
- Imagens oficiais (ex.:
nginx,postgres,node) são mantidas pela comunidade/empresa responsável → mais confiáveis. - Imagens desconhecidas podem conter backdoors ou software desatualizado.
Sempre verifique:
- Fonte da imagem.
- Quantidade de downloads e estrelas.
- Atualizações recentes.
Exemplo seguro:
docker pull postgres:16Exemplo de risco:
docker pull usuario123/postgres-modificadoManter imagens sempre atualizadas é fundamental para corrigir falhas de segurança.
Exemplo:
docker pull nginx:latest
docker pull node:20-alpineApós atualizar, reconstrua containers:
docker compose up -d --buildFerramentas que analisam imagens em busca de falhas conhecidas (CVEs).
Exemplo: Trivy.
Instalação (Ubuntu/Debian):
sudo apt install trivyEscaneando imagens:
trivy image nginx:latest
trivy image postgres:16➡️ Resultado mostra vulnerabilidades e recomendações de atualização.
✅ Resumo
- Nunca rode containers como root → use usuários dedicados.
- Prefira imagens oficiais e mantenha-as atualizadas (
docker pull). - Evite imagens de fontes duvidosas.
- Use scanners como Trivy para verificar vulnerabilidades.
Objetivo: empacotar uma aplicação Node.js em um container.
Estrutura de projeto:
api/
├── package.json
├── package-lock.json
├── server.js
└── Dockerfile
Exemplo de Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Build e execução:
docker build -t minha_api:1.0 ./api
docker run -d --name api -p 3000:3000 minha_api:1.0➡️ A API agora roda em http://localhost:3000.
Objetivo: subir um banco de dados rapidamente sem instalar localmente.
PostgreSQL
docker run -d --name meu_postgres \
-e POSTGRES_USER=user \
-e POSTGRES_PASSWORD=pass \
-e POSTGRES_DB=meubanco \
-v pg_data:/var/lib/postgresql/data \
-p 5432:5432 postgres:16MySQL
docker run -d --name meu_mysql \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=meubanco \
-v mysql_data:/var/lib/mysql \
-p 3306:3306 mysql:8➡️ Ambos criam volumes (pg_data, mysql_data) para persistência.
Objetivo: rodar um ambiente com frontend, backend e banco.
Usaremos Docker Compose para orquestrar os serviços.
Estrutura:
project/
├── api/
│ ├── Dockerfile
│ └── server.js
├── frontend/
│ └── index.html
└── docker-compose.yml
Exemplo de docker-compose.yml:
version: "3.9"
services:
frontend:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./frontend:/usr/share/nginx/html
backend:
build: ./backend
ports:
- "3000:3000"
environment:
DB_HOST: db
DB_USER: user
DB_PASS: pass
depends_on:
- db
db:
image: postgres:16
restart: always
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:Subindo a stack:
docker compose up -d➡️ Serviços disponíveis:
- Frontend → http://localhost:8080
- API → http://localhost:3000
- Postgres → localhost:5432
✅ Resumo
- API Node.js → containerizada em imagem leve e reutilizável.
- PostgreSQL/MySQL → fácil de rodar e persistir dados com volumes.
- Stack completa (Nginx + API + DB) → substitui ambientes complexos com um único comando.
Imagens menores = menos tempo de build, menos uso de rede e mais segurança.
Use imagens leves (ex.: alpine, slim) e remova dependências desnecessárias após uso.
Multi-stage builds (ex.: Node.js):
# Etapa 1: build
FROM node:20 as builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Etapa 2: imagem final leve
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm install --only=production
CMD ["node", "dist/server.js"]➡️ A imagem final contém apenas os arquivos essenciais.
Nomeie volumes e redes para facilitar manutenção; evite deixar tudo no bridge.
Exemplo:
services:
api:
networks:
- backend
volumes:
- api_data:/app/data
db:
networks:
- backend
volumes:
- db_data:/var/lib/postgresql/data
networks:
backend:
volumes:
api_data:
db_data:Use Git e separe arquivos por ambiente:
docker-compose.dev.ymldocker-compose.prod.yml
Exemplo (produção):
docker compose -f docker-compose.prod.yml up -dCom o tempo, o Docker acumula containers parados, imagens antigas e volumes não utilizados.
Comandos úteis:
docker container prune # remove containers parados
docker image prune # remove imagens não usadas
docker volume prune # remove volumes órfãos
docker system prune -a # remove TUDO não utilizado (atenção!)✅ Resumo
- Imagens menores → mais rápidas e seguras (use multi-stage).
- Volumes/redes organizados → melhor manutenção e isolamento.
- Versione Compose → ambientes consistentes (dev/prod).
- Limpeza periódica → evita desperdício de espaço.
Problema: gerenciar containers manualmente funciona em projetos pequenos, mas em ambientes maiores é necessário automatizar.
Soluções:
-
Docker Swarm
- Orquestrador nativo do Docker.
- Fácil de configurar, bom para ambientes menores.
- Suporta clustering, balanceamento de carga e replicação.
- Exemplo:
docker swarm init docker service create --replicas 3 nginx
-
Kubernetes (K8s)
- Orquestrador mais usado em produção.
- Suporta autoescalonamento, alta disponibilidade, secrets e volumes avançados.
- Mais complexo, mas padrão de mercado.
CI/CD (Integração Contínua e Entrega Contínua) automatiza build, testes e deploy.
Docker no CI/CD:
- Criar imagens da aplicação em pipelines.
- Rodar testes dentro de containers.
- Publicar imagens em registries (Docker Hub, GitHub Packages, AWS ECR).
Ferramentas: GitHub Actions, GitLab CI/CD, Jenkins.
Exemplo (GitHub Actions):
name: CI/CD
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build image
run: docker build -t minha_api:latest .
- name: Push image
run: docker push usuario/minha_api:latestContainers podem ser implantados em diversos provedores:
-
AWS
- ECS (Elastic Container Service): gerencia containers com ou sem Kubernetes.
- EKS (Elastic Kubernetes Service): Kubernetes gerenciado.
-
Azure
- AKS (Azure Kubernetes Service): Kubernetes como serviço.
- Azure Container Instances (ACI): containers simples sem orquestrador.
-
GCP
- GKE (Google Kubernetes Engine): Kubernetes gerenciado.
- Cloud Run: roda containers serverless.
➡️ A nuvem elimina a necessidade de manter servidores próprios.
Monitoramento é essencial para aplicações em containers.
-
Prometheus
- Coleta métricas (CPU, memória, I/O, rede).
- Usa exporters para integrar com serviços (ex.: cAdvisor para containers).
-
Grafana
- Interface para visualizar métricas e criar dashboards.
Exemplo básico (Docker Compose):
version: "3.9"
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"➡️ Resultado:
- Prometheus coleta métricas em http://localhost:9090.
- Grafana exibe dashboards em http://localhost:3000.
✅ Resumo
- Orquestração: Swarm (simples) e Kubernetes (padrão de mercado).
- CI/CD com Docker: pipelines automatizados para build, teste e deploy.
- Deploy em nuvem: AWS, Azure e GCP oferecem soluções prontas.
- Observabilidade: Prometheus + Grafana para métricas e dashboards.