Elasticsearch MigrationClickHouse Workshops

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.

Diagrama da arquitetura

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

RequisitoVersãoObservações
Docker Engine≥24.0Incluído no Docker Desktop 4.x
Docker Compose≥2.20Incluí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 livresPara 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çãoMais indicada paraRequisitos
Opção A — Local (Docker Compose)Mac/Linux com 16 GB de RAM disponível, Windows WSL2Docker Desktop, 16 GB de RAM livre
Opção B — EC2 (Terraform + Docker Compose)Ambientes AWS, recursos locais insuficientes, equipes compartilhando uma instânciaConta 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=262144

Para manter a configuração após reinicializações:

echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf

WSL2 (Windows):

# Run in WSL2 terminal
sudo sysctl -w vm.max_map_count=262144

Verificação: sysctl vm.max_map_count deve exibir vm.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 --build

Saí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         Started

Aguarde 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 -d

Como funciona: Os dois arquivos compose compartilham o mesmo projeto e a mesma rede do Docker Compose. O contêiner otelcol-demo coleta todos os sinais dos microsserviços de demonstração e os encaminha ao contêiner elastic-apm-server iniciado 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-bootstrap

Saí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.tool

Esperado: "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.tool

Apó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:

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.tool

Esperado: "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.tfvars

Abra 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.me para obter seu IP público e use <YOUR_IP>/32 como allowed_ssh_cidr.

Etapa B.2: inicializar e aplicar

terraform init
terraform plan
terraform apply

Revise 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-server etc.) — o user-data executou docker compose up -d automaticamente 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 ps e, se continuar vazio, inicie a stack manualmente:
docker compose -f docker-compose.source.yml up -d

Em 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-bootstrap

Linha 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-bootstrap tiver 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 -d

Como funciona: Os dois arquivos compose compartilham o mesmo projeto e a mesma rede do Docker Compose. O contêiner otelcol-demo coleta todos os sinais dos microsserviços de demonstração e os encaminha ao contêiner elastic-apm-server iniciado 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.tool

Confirme 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.tool

Você 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.tool

Observaçã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 por terraform output kibana_url)

O Kibana pode exibir uma tela de carregamento por 30–60 segundos no primeiro acesso enquanto é inicializado.

  1. Na barra lateral esquerda do Kibana, clique em Analytics → Dashboards
  2. 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)
  3. 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.sh

EC2 (a partir do laptop):

bash validation/check.sh http://<EC2_IP>:9200 http://<EC2_IP>:5601

EC2 (dentro da sessão SSH):

bash ~/lab/partner_labs/02-elasticsearch-migration-lab/part1/validation/check.sh

Saí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 primeiro cd 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 elasticsearch

Correçã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-bootstrap

3. 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.sh

Você 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-*/_count retorna count > 0

Ambas:

  • Todas as verificações de validação passam: bash validation/check.sh

Próximo: Parte 2: análise da arquitetura →

Nesta página

Acompanhar seu progresso?

Opcional. Enviaremos um link por e-mail para confirmar seu endereço; o progresso será registrado depois que você o abrir.

Use seu e-mail corporativo, não um endereço pessoal.

O acompanhamento do progresso também exige a aceitação dos Termos de Serviço atuais nas Configurações de privacidade.

PT