Elasticsearch MigrationClickHouse Workshops

01 Construir el entorno de origen

Inicia Elasticsearch, Kibana, Filebeat, Elastic APM Server y OpenTelemetry Demo como referencia para la migración.

Ejecuta este módulo desde el directorio de artefactos del taller:

cd "$(git rev-parse --show-toplevel)/workshops/elasticsearch_migration_lab/part1"

Tiempo estimado: 20–30 minutos

Descripción general

Inicia una pila de observabilidad de Elasticsearch realista para producción con dos cargas de trabajo distintas, de modo que tengas un estado «anterior» realista con varias rutas de migración que analizar en las Partes 2–3.

  • Carga de trabajo 1: recopilación de logs basada en Filebeat; tres generadores (acceso web, aplicación e infraestructura) alimentan flujos de datos de Elasticsearch mediante Filebeat y pipelines de ingesta.
  • Carga de trabajo 2: OpenTelemetry Demo (Astronomy Shop); 16 microservicios (Go, Java, .NET, Python, Rust, Node.js, PHP y Ruby) instrumentados con SDK de OTel envían trazas, métricas y logs mediante un OTel Collector a Elastic APM Server.

Diagrama de arquitectura

Lo que tendrás al finalizar

  • Elasticsearch 8.15 ejecutándose con la seguridad desactivada (modo laboratorio) y recibiendo unos 300 eventos/minuto en 3 flujos de datos (Carga de trabajo 1)
  • Kibana 8.15 con 6 dashboards preconfigurados: Web Traffic Overview, Application Health, Infrastructure Overview, OTel Demo — APM Traces, OTel Demo — Latency y OTel Demo — Logs
  • Filebeat 8.15 recopilando logs de 3 generadores: acceso web (JSON), aplicación (JSON) e infraestructura (syslog)
  • Elastic APM Server 8.15 recibiendo trazas OTLP tanto de la aplicación Flask de muestra como de toda la pila OTel Demo
  • 4 pipelines de ingesta activos que realizan enriquecimiento geoip, análisis de user-agent, extracción grok y normalización de campos mediante scripts
  • Una política ILM (lab-observability-policy) que gestiona el ciclo de vida hot/warm/delete de los 3 flujos de datos
  • La tienda OTel Demo accesible en http://localhost:8090, con más de 15 microservicios instrumentados generando tráfico continuo
  • Todas las comprobaciones de validación superadas: bash validation/check.sh

Requisitos previos

RequisitoVersiónObservaciones
Docker Engine≥24.0Incluido en Docker Desktop 4.x
Docker Compose≥2.20Incluido con Docker Desktop; ejecuta docker compose version para comprobarlo
RAM disponible≥16 GB (se recomiendan 32 GB)Carga 1 ~3 GB + OTel Demo ~9 GB = ~12 GB en total
Espacio en disco≥5 GB libresPara imágenes y volúmenes de datos

Nota: Para la Opción B (EC2), también necesitas Terraform ≥1.5 y una cuenta de AWS con un par de claves de EC2. Consulta el Paso B.1 para obtener más información.


Elegir el entorno

Elige la opción que se ajuste a tu configuración:

OpciónIdeal paraRequisitos
Opción A — Local (Docker Compose)Mac/Linux con 16 GB de RAM disponibles, Windows WSL2Docker Desktop, 16 GB de RAM libres
Opción B — EC2 (Terraform + Docker Compose)Entornos AWS, recursos locales insuficientes, equipos que comparten una instanciaCuenta de AWS, Terraform ≥1.5, par de claves SSH

Ambas opciones utilizan los mismos archivos Compose y producen un entorno idéntico. Solo cambia dónde se ejecutan los contenedores.


Opción A: Local (Docker Compose)

Paso A.1: Definir el parámetro obligatorio del kernel (solo Linux y WSL2)

Elasticsearch necesita vm.max_map_count=262144 para evitar fallos OOM. Los usuarios de macOS deben omitir este paso: Docker Desktop lo define internamente.

Linux:

sudo sysctl -w vm.max_map_count=262144

Para conservarlo tras reiniciar:

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

Verificación: sysctl vm.max_map_count debe mostrar vm.max_map_count = 262144.

Paso A.2: Iniciar la Carga de trabajo 1 (pila de Elasticsearch)

cd docker
docker compose -f docker-compose.source.yml up -d --build

Salida esperada (contenedores iniciándose):

[+] 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

Espera 2–3 minutos a que Elasticsearch se inicie por completo y el contenedor bootstrap termine de configurar los flujos de datos, las políticas ILM, los pipelines de ingesta y los dashboards de Kibana.

Paso A.3: Iniciar la Carga de trabajo 2 (OpenTelemetry Demo)

Nota: La Carga de trabajo 2 requiere unos 9 GB de RAM para 16 microservicios. Ejecútala cuando la Carga 1 esté sana.

Desde el mismo directorio docker/, añade los servicios de OTel Demo a la red existente:

docker compose -f docker-compose.source.yml -f docker-compose.otel-demo.yml up -d

Cómo funciona: Ambos archivos Compose comparten el mismo proyecto y red de Docker Compose. El contenedor otelcol-demo recopila todas las señales de los microservicios de la demostración y las reenvía al contenedor elastic-apm-server iniciado por la Carga de trabajo 1.

La primera ejecución descarga unos 1,5 GB de imágenes de OTel Demo. Espera 3–5 minutos a que todos los servicios estén sanos.

Paso A.4: Supervisar el bootstrap

El contenedor es-bootstrap crea todos los flujos de datos, políticas ILM, pipelines de ingesta y plantillas de índices componibles, e importa los dashboards de Kibana. Observa cómo termina:

docker compose -f docker-compose.source.yml logs -f es-bootstrap

Salida final esperada cuando termina el bootstrap:

es-bootstrap  | ILM policy created.
es-bootstrap  | ...
es-bootstrap  | Dashboards imported.
es-bootstrap  | Bootstrap complete!

Pulsa Ctrl+C para dejar de seguir los logs.

Paso A.5: Verificar que los datos fluyen

Comprueba el estado del clúster de Elasticsearch:

curl -s http://localhost:9200/_cluster/health | python3 -m json.tool

Resultado esperado: "status": "green" o "status": "yellow" (amarillo es normal en un clúster de un solo nodo).

Comprueba que existen los 3 flujos de datos y contienen documentos:

curl -s http://localhost:9200/_data_stream/logs-* | python3 -m json.tool | grep '"name"'

Salida esperada:

"name": "logs-application-lab"
"name": "logs-infrastructure-lab"
"name": "logs-web_access-lab"

Comprueba el recuento de documentos en todos los flujos:

curl -s "http://localhost:9200/logs-*/_count" | python3 -m json.tool

Tras 2–3 minutos de generación de datos, deberías ver un "count" de miles. Si muestra 0, es posible que los generadores todavía se estén preparando; espera 1 minuto y vuelve a intentarlo.

Comprueba que existen los 4 pipelines de ingesta:

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"'

Paso A.6: Acceder a la tienda OTel Demo

Cuando se ejecute la Carga 2 (3–5 minutos después del Paso A.3), abre Astronomy Shop:

Verificación: Debes ver la tienda Astronomy Shop. El generador de carga envía automáticamente unos 5 usuarios simultáneos; las trazas APM aparecerán en Kibana en 1–2 minutos.

Para comprobar que los datos APM fluyen a Elasticsearch:

curl -s "http://localhost:9200/traces-apm-*/_count" | python3 -m json.tool

Resultado esperado: "count" crece por encima de 0 en 2 minutos.


Opción B: EC2 (Terraform)

La configuración de Terraform en terraform/ aprovisiona una instancia EC2 t3.2xlarge (8 vCPU / 32 GB de RAM), instala Docker y Docker Compose mediante user-data, define automáticamente vm.max_map_count=262144, clona el repositorio del laboratorio e inicia la Carga de trabajo 1 (la pila de Elasticsearch). No tienes que definir el parámetro del kernel manualmente. Tú iniciarás la Carga 2 (OpenTelemetry Demo) en el Paso B.4, cuando la Carga 1 esté sana; la t3.2xlarge admite ambas.

Paso B.1: Copiar la plantilla de variables

cd terraform
cp terraform.tfvars.example terraform.tfvars

Abre terraform.tfvars e introduce tus 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"

Dónde encontrar ssh_key_name: AWS Console → EC2 → Key Pairs. Utiliza el nombre que aparece allí (sin .pem).

Cómo averiguar tu IP: Ejecuta curl -s ifconfig.me para obtener tu IP pública y utiliza <YOUR_IP>/32 como allowed_ssh_cidr.

Paso B.2: Inicializar y aplicar

terraform init
terraform plan
terraform apply

Revisa el plan y escribe yes cuando se solicite. El aprovisionamiento tarda unos 2–3 minutos.

Ejemplo de salida correcta:

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"

Paso B.3: Conectarse y observar el inicio

Obtén el comando SSH de la salida de Terraform y conéctate:

# 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>

Una vez conectado, comprueba si el script user-data de EC2 ya inició la pila:

cd ~/lab/partner_labs/02-elasticsearch-migration-lab/part1/docker
docker compose -f docker-compose.source.yml ps
  • Si aparecen contenedores (elasticsearch, kibana, elastic-apm-server, etc.), user-data ejecutó automáticamente docker compose up -d en el primer inicio. Continúa.
  • Si no aparece nada, user-data aún se está ejecutando, no ha empezado o ha fallado. Espera 60–90 segundos, repite ps y, si sigue vacío, inicia tú la pila:
docker compose -f docker-compose.source.yml up -d

Sigue los logs del contenedor bootstrap para confirmar que la inicialización termina:

docker compose -f docker-compose.source.yml logs -f es-bootstrap

Última línea esperada: es-bootstrap | [INFO] Bootstrap complete!

Pulsa Ctrl-C cuando aparezca.

Paso B.4: Iniciar la Carga de trabajo 2 (OpenTelemetry Demo)

Nota: La Carga 2 requiere unos 9 GB de RAM para 16 microservicios. Ejecútala solo cuando la Carga 1 esté sana y el contenedor es-bootstrap haya terminado (Paso B.3).

Desde el mismo directorio docker/ dentro de la sesión SSH, añade los servicios de OTel Demo a la red existente:

docker compose -f docker-compose.source.yml -f docker-compose.otel-demo.yml up -d

Cómo funciona: Ambos archivos Compose comparten el mismo proyecto y red de Docker Compose. El contenedor otelcol-demo recopila todas las señales de los microservicios y las reenvía al contenedor elastic-apm-server iniciado por la Carga 1.

La primera ejecución descarga unos 1,5 GB de imágenes. Espera 3–5 minutos.

Paso B.5: Verificar desde la instancia EC2

Ejecuta estos comandos dentro de la sesión SSH usando localhost. Fuera de la instancia, el grupo de seguridad restringe los puertos 9200 y 5601 al CIDR permitido; no están abiertos a toda Internet:

# 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

Confirma que los contenedores de la Carga 2 se ejecutan y las trazas APM fluyen:

# 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

También puedes verificar ES desde tu portátil utilizando la IP pública de terraform output:

curl -s http://<EC2_PUBLIC_IP>:9200/_cluster/health | python3 -m json.tool

Nota sobre la interfaz de la tienda OTel: La interfaz Astronomy Shop (puerto 8090) no está expuesta en el grupo de seguridad predeterminado. Para acceder desde tu portátil, abre el puerto 8090 en terraform/main.tf (y vuelve a aplicar) o utiliza el reenvío de puertos SSH: ssh -i ~/.ssh/<key-name>.pem -L 8090:localhost:8090 ec2-user@<EC2_PUBLIC_IP>; después visita http://localhost:8090.


Paso 1.6: Abrir Kibana (ambas opciones)

Acceder a Kibana

  • Local: http://localhost:5601
  • EC2: http://<EC2_PUBLIC_IP>:5601 (usa la IP de terraform output kibana_url)

Kibana puede mostrar una pantalla de carga durante 30–60 segundos la primera vez mientras se inicializa.

Ir a los dashboards

  1. En la barra lateral izquierda de Kibana, haz clic en Analytics → Dashboards
  2. Debes ver 4 dashboards:
    • Web Traffic Overview — tasas de solicitudes, códigos de estado y distribución geográfica
    • Application Health — volumen de logs por severidad y seguimiento de errores
    • Infrastructure Overview — volumen de syslog por host y procesos principales
    • OTel Demo — APM Traces — volumen de trazas y servicios principales (aparece al iniciar la Carga 2)
  3. Haz clic en Web Traffic Overview y define el intervalo en Last 15 minutes (arriba a la derecha)

Verificación: El dashboard debe mostrar datos en tiempo real y actualizar los gráficos. Si todos los paneles están vacíos, espera 2 minutos y actualiza.

Para ver las trazas APM de OTel Demo en Kibana, ve a Observability → APM → Services después de iniciar la Carga 2.


Paso 1.7: Ejecutar el script de validación

Ejecuta el script para confirmar que todos los componentes de la Parte 1 están sanos antes de continuar.

Local:

bash validation/check.sh

EC2 (desde tu portátil):

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

EC2 (dentro de la sesión SSH):

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

Salida esperada cuando pasan todas las comprobaciones (unos 5 minutos después de iniciar ambas cargas):

============================================
 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
============================================

Nota: Las comprobaciones 14–16 (OTel Demo) muestran [SKIP] hasta que la Carga 2 se haya iniciado por completo. Repite la validación después de 5 minutos.


Solución de problemas

Todos los comandos siguientes suponen que estás en part1/docker/ (el mismo directorio utilizado antes). Si has cambiado, ejecuta primero cd part1/docker.

1. OOM de Elasticsearch / vm.max_map_count demasiado bajo

Síntoma: El contenedor elasticsearch termina inmediatamente o se reinicia repetidamente. docker compose logs elasticsearch muestra:

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

Solución (Linux / WSL2):

sudo sysctl -w vm.max_map_count=262144
# Then restart the container:
docker compose -f docker-compose.source.yml restart elasticsearch

Solución (macOS): Este error no debería producirse en macOS, ya que Docker Desktop lo configura automáticamente. Si aparece, reinicia Docker Desktop.


2. Falla bootstrap: Elasticsearch no está listo a tiempo

Síntoma: El contenedor es-bootstrap termina con un error como Connection refused o curl: (7) Failed to connect. Ocurre si Elasticsearch tarda en iniciarse, algo habitual cuando hay presión de memoria.

Solución: Reinicia solo el contenedor bootstrap cuando Elasticsearch esté sano:

# 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. El pipeline GeoIP muestra que falta el país

Síntoma: El script de validación informa [FAIL] GeoIP enrichment not working — geo.country_name missing from web access docs, o una comprobación manual muestra "country_name": null.

Causa: Elasticsearch descarga la base de datos GeoIP al iniciarse por primera vez. Tarda 1–2 minutos. Los documentos indexados antes no se enriquecen de forma retroactiva.

Solución: Espera 2 minutos y vuelve a ejecutar la validación:

bash validation/check.sh

Puedes confirmar que la base de datos se ha cargado:

curl -s "http://localhost:9200/_ingest/geoip/stats" | python3 -m json.tool | grep '"databases_count"'

Resultado esperado: "databases_count": 1 (o más). Si muestra 0, espera otro minuto y reinténtalo.


Comprobación

Antes de continuar con la Parte 2, verifica todo lo siguiente:

Carga de trabajo 1 (Elasticsearch):

  • Elasticsearch está sano: curl http://localhost:9200/_cluster/health
  • Existen 3 flujos de datos: curl http://localhost:9200/_data_stream/logs-*
  • La política ILM está vinculada: curl http://localhost:9200/_ilm/policy/lab-observability-policy
  • Kibana muestra dashboards con datos en tiempo real en http://localhost:5601

Carga de trabajo 2 (OTel Demo):

  • La tienda se carga en http://localhost:8090
  • Las trazas APM aparecen en Kibana: Observability → APM → Services (más de 15 servicios visibles)
  • curl http://localhost:9200/traces-apm-*/_count devuelve count > 0

Ambas:

  • Pasan todas las comprobaciones: bash validation/check.sh

Siguiente: Parte 2: Análisis de arquitectura →

En esta página

¿Quieres seguir tu progreso?

Opcional. Enviaremos un enlace por correo para confirmar tu dirección; el progreso se registrará cuando lo abras.

Usa tu correo de trabajo, no uno personal.

Para seguir el progreso también debes aceptar los Términos del servicio actuales en la Configuración de privacidad.

ES