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.

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
| Requisito | Versión | Observaciones |
|---|---|---|
| Docker Engine | ≥24.0 | Incluido en Docker Desktop 4.x |
| Docker Compose | ≥2.20 | Incluido 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 libres | Para 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ón | Ideal para | Requisitos |
|---|---|---|
| Opción A — Local (Docker Compose) | Mac/Linux con 16 GB de RAM disponibles, Windows WSL2 | Docker Desktop, 16 GB de RAM libres |
| Opción B — EC2 (Terraform + Docker Compose) | Entornos AWS, recursos locales insuficientes, equipos que comparten una instancia | Cuenta 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=262144Para conservarlo tras reiniciar:
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.confWSL2 (Windows):
# Run in WSL2 terminal
sudo sysctl -w vm.max_map_count=262144Verificación:
sysctl vm.max_map_countdebe mostrarvm.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 --buildSalida 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 StartedEspera 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 -dCómo funciona: Ambos archivos Compose comparten el mismo proyecto y red de Docker Compose. El contenedor
otelcol-demorecopila todas las señales de los microservicios de la demostración y las reenvía al contenedorelastic-apm-serveriniciado 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-bootstrapSalida 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.toolResultado 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.toolTras 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:
- Tienda: http://localhost:8090
- Interfaz del generador de carga: http://localhost:8090/loadgen (muestra estadísticas de tráfico de Locust)
- Feature flags: http://localhost:8090/feature (permite activar ingeniería del caos)
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.toolResultado 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.tfvarsAbre 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.mepara obtener tu IP pública y utiliza<YOUR_IP>/32comoallowed_ssh_cidr.
Paso B.2: Inicializar y aplicar
terraform init
terraform plan
terraform applyRevisa 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áticamentedocker compose up -den 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
psy, si sigue vacío, inicia tú la pila:
docker compose -f docker-compose.source.yml up -dSigue 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-bootstraphaya 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 -dCómo funciona: Ambos archivos Compose comparten el mismo proyecto y red de Docker Compose. El contenedor
otelcol-demorecopila todas las señales de los microservicios y las reenvía al contenedorelastic-apm-serveriniciado 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.toolConfirma 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.toolTambié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.toolNota 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 deterraform output kibana_url)
Kibana puede mostrar una pantalla de carga durante 30–60 segundos la primera vez mientras se inicializa.
Ir a los dashboards
- En la barra lateral izquierda de Kibana, haz clic en Analytics → Dashboards
- 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)
- 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.shEC2 (desde tu portátil):
bash validation/check.sh http://<EC2_IP>:9200 http://<EC2_IP>:5601EC2 (dentro de la sesión SSH):
bash ~/lab/partner_labs/02-elasticsearch-migration-lab/part1/validation/check.shSalida 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 primerocd 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 elasticsearchSolució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-bootstrap3. 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.shPuedes 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-*/_countdevuelvecount > 0
Ambas:
- Pasan todas las comprobaciones:
bash validation/check.sh
Siguiente: Parte 2: Análisis de arquitectura →
00 Preparación
Instala las herramientas necesarias, crea una cuenta de ClickHouse Cloud, clona el repositorio y verifica los artefactos del taller.
02 Analizar y diseñar
Inspecciona la carga de Elasticsearch, traduce su modelo de datos y sus consultas, y registra las decisiones de arquitectura de la migración.