01 Criar o ambiente de origem
Inicie o Elasticsearch, Kibana, Filebeat, Elastic APM Server e o OpenTelemetry Demo como linha de base da migração.
Execute este módulo a partir do diretório de artefatos do workshop:
cd "$(git rev-parse --show-toplevel)/workshops/elasticsearch_migration_lab/part1"Tempo estimado: 20–30 minutos
Visão geral
Inicie uma stack de observabilidade Elasticsearch realista para produção com duas cargas de trabalho distintas — assim você terá um estado realista de "antes", com vários caminhos de migração para analisar nas Partes 2–3.
- Carga de trabalho 1: coleta de logs baseada no Filebeat — três geradores de logs (acesso web, aplicação e infraestrutura) alimentando fluxos de dados do Elasticsearch por meio do Filebeat e de pipelines de ingestão.
- Carga de trabalho 2: OpenTelemetry Demo (Astronomy Shop) — 16 microsserviços (Go, Java, .NET, Python, Rust, Node.js, PHP e Ruby) instrumentados com SDKs do OTel, enviando traces/métricas/logs por um OTel Collector ao Elastic APM Server.

O que você terá ao final
- Elasticsearch 8.15 em execução com a segurança desabilitada (modo de laboratório), recebendo cerca de 300 eventos/minuto em 3 fluxos de dados (Carga de trabalho 1)
- Kibana 8.15 com 6 dashboards predefinidos: Visão geral do tráfego web, Integridade da aplicação, Visão geral da infraestrutura, OTel Demo — Traces de APM, OTel Demo — Latência, OTel Demo — Logs
- Filebeat 8.15 coletando logs de 3 geradores: acesso web (JSON), aplicação (JSON) e infraestrutura (syslog)
- Elastic APM Server 8.15 recebendo traces OTLP tanto da aplicação Flask de exemplo quanto da stack completa do OTel Demo
- 4 pipelines de ingestão ativos realizando enriquecimento GeoIP, análise de user-agent, extração grok e normalização de campos por script
- Uma política de ILM (
lab-observability-policy) gerenciando o ciclo de vida hot/warm/delete dos 3 fluxos de dados - Loja do OTel Demo acessível em http://localhost:8090, com mais de 15 microsserviços instrumentados gerando tráfego contínuo
- Todas as verificações de validação aprovadas:
bash validation/check.sh
Pré-requisitos
| Requisito | Versão | Observações |
|---|---|---|
| Docker Engine | ≥24.0 | Incluído no Docker Desktop 4.x |
| Docker Compose | ≥2.20 | Incluído no Docker Desktop; execute docker compose version para verificar |
| RAM disponível | ≥16 GB (32 GB recomendados) | Carga de trabalho 1 ~3 GB + OTel Demo ~9 GB = ~12 GB no total |
| Espaço em disco | ≥5 GB livres | Para imagens e volumes de dados |
Observação: Para a Opção B (EC2), você também precisa do Terraform ≥1.5 e de uma conta AWS com um par de chaves do EC2. Consulte a Etapa B.1 para obter detalhes.
Escolher o ambiente
Escolha a opção adequada à sua configuração:
| Opção | Mais indicada para | Requisitos |
|---|---|---|
| Opção A — Local (Docker Compose) | Mac/Linux com 16 GB de RAM disponível, Windows WSL2 | Docker Desktop, 16 GB de RAM livre |
| Opção B — EC2 (Terraform + Docker Compose) | Ambientes AWS, recursos locais insuficientes, equipes compartilhando uma instância | Conta AWS, Terraform ≥1.5, par de chaves SSH |
As duas opções usam os mesmos arquivos compose e produzem um ambiente em execução idêntico. A única diferença é onde os contêineres são executados.
Opção A: local (Docker Compose)
Etapa A.1: definir o parâmetro de kernel obrigatório (somente Linux e WSL2)
O Elasticsearch exige vm.max_map_count=262144 para evitar falhas de OOM. Usuários do macOS devem pular esta etapa — o Docker Desktop define esse valor internamente.
Linux:
sudo sysctl -w vm.max_map_count=262144Para manter a configuração após reinicializações:
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.confWSL2 (Windows):
# Run in WSL2 terminal
sudo sysctl -w vm.max_map_count=262144Verificação:
sysctl vm.max_map_countdeve exibirvm.max_map_count = 262144.
Etapa A.2: iniciar a Carga de trabalho 1 (stack do Elasticsearch)
cd docker
docker compose -f docker-compose.source.yml up -d --buildSaída esperada (contêineres sendo iniciados):
[+] Running 10/10
[+] Network docker_default Created
[+] Container elasticsearch Started
[+] Container kibana Started
[+] Container elastic-apm-server Started
[+] Container es-bootstrap Started
[+] Container filebeat Started
[+] Container log-generator-web Started
[+] Container log-generator-app Started
[+] Container log-generator-infra Started
[+] Container sample-app StartedAguarde de 2 a 3 minutos para que o Elasticsearch seja completamente iniciado e o contêiner de bootstrap termine de configurar os fluxos de dados, as políticas de ILM, os pipelines de ingestão e os dashboards do Kibana.
Etapa A.3: iniciar a Carga de trabalho 2 (OpenTelemetry Demo)
Observação: A Carga de trabalho 2 exige cerca de 9 GB de RAM para 16 microsserviços. Execute-a depois que a Carga de trabalho 1 estiver íntegra.
A partir do mesmo diretório docker/, adicione os serviços do OTel Demo à rede existente:
docker compose -f docker-compose.source.yml -f docker-compose.otel-demo.yml up -dComo funciona: Os dois arquivos compose compartilham o mesmo projeto e a mesma rede do Docker Compose. O contêiner
otelcol-democoleta todos os sinais dos microsserviços de demonstração e os encaminha ao contêinerelastic-apm-serveriniciado pela Carga de trabalho 1.
Na primeira execução, cerca de 1,5 GB de imagens do OTel Demo são baixados. Aguarde de 3 a 5 minutos para que todos os serviços fiquem íntegros.
Etapa A.4: monitorar o bootstrap
O contêiner es-bootstrap cria todos os fluxos de dados, políticas de ILM, pipelines de ingestão e modelos de índice combináveis, além de importar os dashboards do Kibana. Acompanhe até a conclusão:
docker compose -f docker-compose.source.yml logs -f es-bootstrapSaída final esperada quando o bootstrap estiver concluído:
es-bootstrap | ILM policy created.
es-bootstrap | ...
es-bootstrap | Dashboards imported.
es-bootstrap | Bootstrap complete!Pressione Ctrl+C para parar de acompanhar os logs.
Etapa A.5: verificar se os dados estão fluindo
Verifique a integridade do cluster Elasticsearch:
curl -s http://localhost:9200/_cluster/health | python3 -m json.toolEsperado: "status": "green" ou "status": "yellow" (yellow é normal para um cluster de nó único).
Verifique se os 3 fluxos de dados existem e contêm documentos:
curl -s http://localhost:9200/_data_stream/logs-* | python3 -m json.tool | grep '"name"'Saída esperada:
"name": "logs-application-lab"
"name": "logs-infrastructure-lab"
"name": "logs-web_access-lab"Verifique as contagens de documentos em todos os fluxos de dados:
curl -s "http://localhost:9200/logs-*/_count" | python3 -m json.toolApós 2–3 minutos de geração de dados, você deverá ver "count" na casa dos milhares. Se o valor for 0, os geradores de logs talvez ainda estejam aquecendo — aguarde 1 minuto e tente novamente.
Verifique se os 4 pipelines de ingestão existem:
curl -s "http://localhost:9200/_ingest/pipeline/web-access-enrichment,app-log-enrichment,infra-log-parsing,default-enrichment" \
| python3 -m json.tool | grep -E '"web-access|app-log|infra-log|default-enrich"'Etapa A.6: acessar a loja do OTel Demo
Quando a Carga de trabalho 2 estiver em execução (3–5 minutos após a Etapa A.3), abra a Astronomy Shop:
- Loja: http://localhost:8090
- Interface do gerador de carga: http://localhost:8090/loadgen (mostra estatísticas de tráfego do Locust)
- Feature flags: http://localhost:8090/feature (habilita engenharia do caos)
Verificação: Você deverá ver a loja da Astronomy Shop. O gerador de carga envia automaticamente cerca de 5 usuários simultâneos — os traces de APM aparecerão no Kibana em 1–2 minutos.
Para verificar se os dados de APM estão fluindo para o Elasticsearch:
curl -s "http://localhost:9200/traces-apm-*/_count" | python3 -m json.toolEsperado: "count" crescendo acima de 0 em até 2 minutos.
Opção B: EC2 (Terraform)
A configuração do Terraform em terraform/ provisiona uma instância EC2 t3.2xlarge (8 vCPUs/32 GB de RAM), instala o Docker e o Docker Compose por meio de user-data, define vm.max_map_count=262144 automaticamente, clona o repositório do laboratório e inicia a Carga de trabalho 1 (a stack do Elasticsearch). Não é necessário definir o parâmetro de kernel manualmente. Você iniciará a Carga de trabalho 2 (o OpenTelemetry Demo) na Etapa B.4, depois que a Carga de trabalho 1 estiver íntegra — a t3.2xlarge tem capacidade para ambas.
Etapa B.1: copiar o modelo de variáveis
cd terraform
cp terraform.tfvars.example terraform.tfvarsAbra terraform.tfvars e preencha seus valores:
aws_region = "us-east-1" # AWS region to deploy in
instance_type = "t3.2xlarge" # 8 vCPU / 32 GB; required for dual-workload stack
ssh_key_name = "my-key-pair" # Name of your EC2 key pair in AWS (without .pem extension)
allowed_ssh_cidr = "0.0.0.0/0" # Restrict to your IP for security: "x.x.x.x/32"
lab_repo_url = "https://github.com/ClickHouse/clickhouse-partner-labs.git"Onde encontrar
ssh_key_name: Console da AWS → EC2 → Key Pairs. O nome exibido ali (sem.pem) é o valor a ser usado aqui.
Como encontrar seu IP: Execute
curl -s ifconfig.mepara obter seu IP público e use<YOUR_IP>/32comoallowed_ssh_cidr.
Etapa B.2: inicializar e aplicar
terraform init
terraform plan
terraform applyRevise a saída do plano e digite yes quando solicitado. O provisionamento leva aproximadamente 2–3 minutos.
Exemplo de saída em caso de sucesso:
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
Outputs:
elasticsearch_url = "http://54.198.12.34:9200"
instance_public_dns = "ec2-54-198-12-34.compute-1.amazonaws.com"
instance_public_ip = "54.198.12.34"
kibana_url = "http://54.198.12.34:5601"
ssh_command = "ssh -i ~/.ssh/my-key-pair.pem ec2-user@54.198.12.34"Etapa B.3: conectar e acompanhar a inicialização
Obtenha o comando SSH na saída do Terraform e conecte-se:
# Get the exact SSH command
terraform output ssh_command
# Connect (replace with the actual output from above)
ssh -i ~/.ssh/<key-name>.pem ec2-user@<EC2_PUBLIC_IP>Após a conexão, verifique primeiro se o script de user-data do EC2 já iniciou a stack para você:
cd ~/lab/partner_labs/02-elasticsearch-migration-lab/part1/docker
docker compose -f docker-compose.source.yml ps- Se houver contêineres listados (
elasticsearch,kibana,elastic-apm-serveretc.) — o user-data executoudocker compose up -dautomaticamente na primeira inicialização. Avance para a próxima etapa. - Se nada for exibido — o user-data ainda está em execução, ainda não começou ou falhou. Aguarde 60–90 segundos, repita o comando
pse, se continuar vazio, inicie a stack manualmente:
docker compose -f docker-compose.source.yml up -dEm seguida, acompanhe os logs do contêiner de bootstrap para confirmar que a inicialização foi concluída:
docker compose -f docker-compose.source.yml logs -f es-bootstrapLinha final esperada: es-bootstrap | [INFO] Bootstrap complete!
Pressione Ctrl-C para parar de acompanhar quando vir essa linha.
Etapa B.4: iniciar a Carga de trabalho 2 (OpenTelemetry Demo)
Observação: A Carga de trabalho 2 exige cerca de 9 GB de RAM para 16 microsserviços. Execute-a somente depois que a Carga de trabalho 1 estiver íntegra e o contêiner
es-bootstraptiver terminado (Etapa B.3).
No mesmo diretório docker/ dentro da sessão SSH, adicione os serviços do OTel Demo à rede existente:
docker compose -f docker-compose.source.yml -f docker-compose.otel-demo.yml up -dComo funciona: Os dois arquivos compose compartilham o mesmo projeto e a mesma rede do Docker Compose. O contêiner
otelcol-democoleta todos os sinais dos microsserviços de demonstração e os encaminha ao contêinerelastic-apm-serveriniciado pela Carga de trabalho 1.
Na primeira execução, cerca de 1,5 GB de imagens do OTel Demo são baixados. Aguarde de 3 a 5 minutos para que todos os serviços fiquem íntegros.
Etapa B.5: verificar a partir da instância EC2
Execute estes comandos dentro da sessão SSH usando localhost. Fora da instância EC2, o grupo de segurança restringe as portas 9200 e 5601 apenas ao CIDR permitido — elas não ficam abertas à Internet em geral:
# Cluster health
curl -s http://localhost:9200/_cluster/health | python3 -m json.tool
# Data streams
curl -s http://localhost:9200/_data_stream/logs-* | python3 -m json.tool | grep '"name"'
# Document counts
curl -s "http://localhost:9200/logs-*/_count" | python3 -m json.toolConfirme se os contêineres da Carga de trabalho 2 estão em execução e se os traces de APM estão fluindo:
# OTel demo containers (should list 16+ services like frontend, cartservice, otelcol-demo, etc.)
docker compose -f docker-compose.source.yml -f docker-compose.otel-demo.yml ps
# APM trace count (should be > 0 and growing 2 minutes after Workload 2 starts)
curl -s "http://localhost:9200/traces-apm-*/_count" | python3 -m json.toolVocê também pode executar a verificação do ES no seu laptop usando o IP público de terraform output:
curl -s http://<EC2_PUBLIC_IP>:9200/_cluster/health | python3 -m json.toolObservação sobre a interface da loja do OTel: A interface da Astronomy Shop (porta 8090) não é exposta no grupo de segurança padrão. Para acessá-la pelo laptop, abra a porta 8090 em
terraform/main.tf(e aplique novamente) ou use encaminhamento de porta SSH:ssh -i ~/.ssh/<key-name>.pem -L 8090:localhost:8090 ec2-user@<EC2_PUBLIC_IP>; depois, acesse http://localhost:8090.
Etapa 1.6: abrir o Kibana (as duas opções)
Acessar o Kibana
- Local: http://localhost:5601
- EC2:
http://<EC2_PUBLIC_IP>:5601(use o endereço IP exibido porterraform output kibana_url)
O Kibana pode exibir uma tela de carregamento por 30–60 segundos no primeiro acesso enquanto é inicializado.
Navegar até os dashboards
- Na barra lateral esquerda do Kibana, clique em Analytics → Dashboards
- Você deverá ver 4 dashboards:
- Web Traffic Overview — taxas de requisições, códigos de status e distribuição geográfica
- Application Health — volume de logs por severidade e acompanhamento de erros
- Infrastructure Overview — volume de syslog por host e principais processos
- OTel Demo — APM Traces — volume de traces e principais serviços (aparece após o início da Carga de trabalho 2)
- Clique em Web Traffic Overview e defina o intervalo de tempo como Last 15 minutes (canto superior direito)
Verificação: O dashboard deve mostrar dados em tempo real com gráficos sendo atualizados. Se todos os painéis estiverem vazios, aguarde 2 minutos para que os geradores de logs produzam dados suficientes e atualize a página.
Para ver os traces de APM do OTel Demo no Kibana, acesse Observability → APM → Services depois que a Carga de trabalho 2 estiver em execução.
Etapa 1.7: executar o script de validação
Execute o script de validação para confirmar que todos os componentes da Parte 1 estão íntegros antes de prosseguir.
Local:
bash validation/check.shEC2 (a partir do laptop):
bash validation/check.sh http://<EC2_IP>:9200 http://<EC2_IP>:5601EC2 (dentro da sessão SSH):
bash ~/lab/partner_labs/02-elasticsearch-migration-lab/part1/validation/check.shSaída esperada quando todas as verificações passam (execute cerca de 5 minutos após iniciar as duas cargas de trabalho):
============================================
Part 1 Validation — Source Environment
ES: http://localhost:9200
Kibana: http://localhost:5601
OTelCol: http://localhost:8888
============================================
[PASS] Elasticsearch is reachable
[PASS] Data streams exist (3 found: logs-web_access-lab, logs-application-lab, logs-infrastructure-lab)
[PASS] ILM policy 'lab-observability-policy' exists
[PASS] Ingest pipeline 'web-access-enrichment' exists
[PASS] Ingest pipeline 'app-log-enrichment' exists
[PASS] Ingest pipeline 'infra-log-parsing' exists
[PASS] Ingest pipeline 'default-enrichment' exists
[PASS] Data stream 'logs-web_access-lab' has data (3,241 docs)
[PASS] Data stream 'logs-application-lab' has data (1,876 docs)
[PASS] Data stream 'logs-infrastructure-lab' has data (2,104 docs)
[PASS] GeoIP enrichment working (country: United States)
[PASS] Kibana is reachable
[PASS] Kibana dashboards imported (4 found)
[PASS] OTel Collector (otelcol-demo) is reachable
[PASS] APM traces indexed from OTel Demo (5,832 spans)
[PASS] OTel Demo storefront reachable at http://localhost:8090
============================================
Results: 16 passed, 0 failed, 0 skipped
============================================Observação: As verificações 14–16 (OTel Demo) mostram
[SKIP]até que a Carga de trabalho 2 seja totalmente iniciada. Execute a validação novamente após 5 minutos.
Solução de problemas
Todos os comandos abaixo pressupõem que você esteja em
part1/docker/(o mesmo diretório de trabalho usado nas etapas anteriores). Se mudou de diretório, execute primeirocd part1/docker.
1. OOM do Elasticsearch/vm.max_map_count muito baixo
Sintoma: O contêiner elasticsearch é encerrado imediatamente ou reinicia repetidamente. docker compose logs elasticsearch mostra:
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]Correção (Linux/WSL2):
sudo sysctl -w vm.max_map_count=262144
# Then restart the container:
docker compose -f docker-compose.source.yml restart elasticsearchCorreção (macOS): Este erro não deve ocorrer no macOS — o Docker Desktop define o valor automaticamente. Se ele aparecer, reinicie o Docker Desktop.
2. Falha no bootstrap — Elasticsearch não ficou pronto a tempo
Sintoma: O contêiner es-bootstrap é encerrado com um erro como Connection refused ou curl: (7) Failed to connect. Isso ocorre quando o Elasticsearch demora para iniciar (algo comum em máquinas sob pressão de memória).
Correção: Reinicie apenas o contêiner de bootstrap depois que o Elasticsearch estiver íntegro:
# Wait for Elasticsearch to be fully up
until curl -sf http://localhost:9200/_cluster/health > /dev/null 2>&1; do
echo "Waiting for Elasticsearch..."; sleep 5
done
# Re-run bootstrap
docker compose -f docker-compose.source.yml restart es-bootstrap
# Watch it complete
docker compose -f docker-compose.source.yml logs -f es-bootstrap3. O pipeline GeoIP indica país AUSENTE
Sintoma: O script de validação informa [FAIL] GeoIP enrichment not working — geo.country_name missing from web access docs, ou uma verificação manual mostra "country_name": null.
Causa: O Elasticsearch baixa o banco de dados GeoIP na primeira inicialização. Isso leva 1–2 minutos. Documentos indexados antes de o banco de dados ficar disponível não são enriquecidos retroativamente.
Correção: Aguarde 2 minutos e execute a validação novamente:
bash validation/check.shVocê pode confirmar se o banco de dados foi carregado:
curl -s "http://localhost:9200/_ingest/geoip/stats" | python3 -m json.tool | grep '"databases_count"'Esperado: "databases_count": 1 (ou mais). Se aparecer 0, aguarde mais um minuto e tente novamente.
Checkpoint
Antes de prosseguir para a Parte 2, verifique todos os itens a seguir:
Carga de trabalho 1 (Elasticsearch):
- O Elasticsearch está íntegro:
curl http://localhost:9200/_cluster/health - Existem 3 fluxos de dados:
curl http://localhost:9200/_data_stream/logs-* - A política de ILM está anexada:
curl http://localhost:9200/_ilm/policy/lab-observability-policy - O Kibana mostra dashboards com dados em tempo real em http://localhost:5601
Carga de trabalho 2 (OTel Demo):
- A loja é carregada em http://localhost:8090
- Os traces de APM aparecem no Kibana: Observability → APM → Services (mais de 15 serviços visíveis)
-
curl http://localhost:9200/traces-apm-*/_countretornacount > 0
Ambas:
- Todas as verificações de validação passam:
bash validation/check.sh
Próximo: Parte 2: análise da arquitetura →
00 Configuração
Instale as ferramentas necessárias, crie uma conta do ClickHouse Cloud, clone o repositório e verifique os artefatos do workshop.
02 Analisar e projetar
Inspecione a carga de trabalho do Elasticsearch, traduza seu modelo de dados e suas consultas e registre as decisões da arquitetura de migração.