Grafana Alloy es el colector de telemetría de Grafana Labs y sustituye al antiguo Grafana Agent. Incluye los componentes del OpenTelemetry Collector junto con los de Prometheus y Loki, así que un único proceso puede recibir datos por OTLP, procesarlos y reenviarlos a varios destinos. En este tutorial instalarás Alloy en Ubuntu 24.04 desde el repositorio oficial de Grafana y lo configurarás como colector OpenTelemetry: recibirá métricas, logs y trazas por OTLP, recogerá las métricas del propio servidor y lo enviará todo a Prometheus (o Mimir), Loki y Tempo.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios
sudo. - Al menos 1 GB de RAM libre para Alloy. El consumo real depende del volumen de telemetría.
- Los backends de destino ya en marcha y accesibles desde el servidor:
- Prometheus con el receptor de remote write activado (
--web.enable-remote-write-receiver) o Mimir. - Loki.
- Tempo con el receptor OTLP gRPC en el puerto
4317.
- Prometheus con el receptor de remote write activado (
En los ejemplos se usan prometheus.internal, loki.internal y tempo.internal como nombres de esos servicios. Sustitúyelos por las direcciones reales de tu entorno. Si usas Grafana Cloud, los tres endpoints y sus credenciales aparecen en la página de tu stack.
Paso 1: Instalar Grafana Alloy
Alloy se publica en el mismo repositorio APT que Grafana. Instala las herramientas necesarias y descarga la clave de firma del repositorio:
sudo apt update
sudo apt install gpg wget
sudo mkdir -p /etc/apt/keyrings
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
Añade el repositorio indicando la clave con signed-by:
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
Actualiza el índice e instala el paquete:
sudo apt update
sudo apt install alloy
Comprueba la versión instalada:
alloy --version
alloy, version v1.11.0 (branch: HEAD, revision: 3b8a1e2c)
El paquete crea el usuario de sistema alloy, el servicio systemd alloy.service, el archivo de configuración /etc/alloy/config.alloy y el archivo de opciones de arranque /etc/default/alloy.
Paso 2: Entender la sintaxis de configuración
La configuración de Alloy se escribe en un lenguaje propio (antes llamado River) formado por componentes. Cada componente tiene un tipo y una etiqueta, recibe argumentos y expone valores que otros componentes consumen. El flujo de datos se define conectando la salida de uno con la entrada del siguiente:
prometheus.scrape "ejemplo" {
targets = [{"__address__" = "localhost:9100"}]
forward_to = [prometheus.remote_write.principal.receiver]
}
prometheus.remote_write "principal" {
endpoint {
url = "http://prometheus.internal:9090/api/v1/write"
}
}
En este fragmento, prometheus.scrape "ejemplo" recoge métricas y las envía a prometheus.remote_write.principal.receiver, que es el valor que exporta el componente prometheus.remote_write "principal". Los componentes de OpenTelemetry siguen el mismo patrón, pero usan bloques output con las señales metrics, logs y traces, y sus entradas se llaman input.
El pipeline que vas a construir tiene esta forma:
| Señal | Entrada | Procesado | Destino |
|---|---|---|---|
| Métricas | OTLP y métricas del host | memory_limiter, batch | Prometheus por remote write |
| Logs | OTLP | memory_limiter, batch | Loki |
| Trazas | OTLP | memory_limiter, batch | Tempo por OTLP gRPC |
Paso 3: Guardar las direcciones de los backends
En lugar de escribir las URL y las credenciales en config.alloy, defínelas como variables de entorno en /etc/default/alloy. El servicio systemd carga ese archivo al arrancar, y la configuración las lee con sys.env():
sudo nano /etc/default/alloy
Conserva las variables que ya trae el archivo (CONFIG_FILE y CUSTOM_ARGS) y añade al final:
PROMETHEUS_URL="http://prometheus.internal:9090/api/v1/write"
LOKI_URL="http://loki.internal:3100/loki/api/v1/push"
TEMPO_ENDPOINT="tempo.internal:4317"
Protege el archivo, ya que si más adelante añades contraseñas irán aquí:
sudo chmod 640 /etc/default/alloy
sudo chown root:alloy /etc/default/alloy
Paso 4: Escribir la configuración del colector
Haz una copia de la configuración de ejemplo y abre el archivo:
sudo cp /etc/alloy/config.alloy /etc/alloy/config.alloy.orig
sudo nano /etc/alloy/config.alloy
Sustituye todo el contenido por la configuración siguiente. Cada bloque lleva un comentario que explica su función:
logging {
level = "info"
format = "logfmt"
}
// Receptor OTLP: acepta métricas, logs y trazas por gRPC (4317) y HTTP (4318)
otelcol.receiver.otlp "default" {
grpc {
endpoint = "0.0.0.0:4317"
}
http {
endpoint = "0.0.0.0:4318"
}
output {
metrics = [otelcol.processor.memory_limiter.default.input]
logs = [otelcol.processor.memory_limiter.default.input]
traces = [otelcol.processor.memory_limiter.default.input]
}
}
// Rechaza datos antes de quedarse sin memoria si llega un pico de tráfico
otelcol.processor.memory_limiter "default" {
check_interval = "1s"
limit = "512MiB"
output {
metrics = [otelcol.processor.batch.default.input]
logs = [otelcol.processor.batch.default.input]
traces = [otelcol.processor.batch.default.input]
}
}
// Agrupa los datos en lotes para reducir el número de peticiones a los backends
otelcol.processor.batch "default" {
output {
metrics = [otelcol.exporter.prometheus.default.input]
logs = [otelcol.exporter.loki.default.input]
traces = [otelcol.exporter.otlp.tempo.input]
}
}
// Métricas OTLP convertidas al formato de Prometheus
otelcol.exporter.prometheus "default" {
forward_to = [prometheus.remote_write.default.receiver]
}
// Logs OTLP convertidos al formato de Loki
otelcol.exporter.loki "default" {
forward_to = [loki.write.default.receiver]
}
// Trazas enviadas a Tempo por OTLP gRPC
otelcol.exporter.otlp "tempo" {
client {
endpoint = sys.env("TEMPO_ENDPOINT")
tls {
insecure = true
}
}
}
// Métricas del propio servidor (CPU, memoria, disco, red), equivalentes a node_exporter
prometheus.exporter.unix "host" { }
prometheus.scrape "host" {
targets = prometheus.exporter.unix.host.targets
scrape_interval = "30s"
forward_to = [prometheus.remote_write.default.receiver]
}
prometheus.remote_write "default" {
endpoint {
url = sys.env("PROMETHEUS_URL")
}
external_labels = {
instance_host = constants.hostname,
}
}
loki.write "default" {
endpoint {
url = sys.env("LOKI_URL")
}
}
La opción tls { insecure = true } envía las trazas a Tempo sin cifrar, lo cual solo es aceptable dentro de una red privada. Si Tempo está en otra red, quítala y usa su endpoint TLS.
Si tus backends piden autenticación (por ejemplo Grafana Cloud), añade un bloque basic_auth dentro de cada endpoint, con la contraseña en /etc/default/alloy:
prometheus.remote_write "default" {
endpoint {
url = sys.env("PROMETHEUS_URL")
basic_auth {
username = sys.env("PROMETHEUS_USER")
password = sys.env("PROMETHEUS_PASSWORD")
}
}
}
Antes de aplicar la configuración, comprueba la sintaxis con alloy fmt. Si el archivo es válido, imprime la versión formateada; si hay un error, indica la línea:
alloy fmt /etc/alloy/config.alloy > /dev/null && echo "Sintaxis correcta"
Sintaxis correcta
Paso 5: Arrancar el servicio y revisar el pipeline
Habilita el servicio para que arranque con el sistema y reinícialo para cargar la nueva configuración y las variables de entorno:
sudo systemctl enable alloy
sudo systemctl restart alloy
sudo systemctl status alloy
● alloy.service - Vendor-agnostic OpenTelemetry Collector distribution with programmable pipelines
Loaded: loaded (/usr/lib/systemd/system/alloy.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-09-25 10:12:41 UTC; 5s ago
Revisa los registros en busca de errores de conexión con los backends:
sudo journalctl -u alloy -n 50 --no-pager
Comprueba que el receptor OTLP escucha en los dos puertos:
sudo ss -tlnp | grep alloy
LISTEN 0 4096 127.0.0.1:12345 0.0.0.0:* users:(("alloy",pid=4121,fd=7))
LISTEN 0 4096 *:4317 *:* users:(("alloy",pid=4121,fd=12))
LISTEN 0 4096 *:4318 *:* users:(("alloy",pid=4121,fd=13))
El puerto 12345 es la interfaz web de Alloy, que por defecto solo escucha en 127.0.0.1. Para verla desde tu equipo sin exponerla, abre un túnel SSH:
ssh -L 12345:127.0.0.1:12345 your_user@your_server_ip
Con el túnel abierto, visita http://localhost:12345. La interfaz muestra cada componente con su estado (healthy o el error concreto) y el grafo del pipeline, lo que permite ver de un vistazo qué conexión falla.
Paso 6: Abrir los puertos OTLP en el cortafuegos
Tus aplicaciones necesitan alcanzar los puertos 4317 y 4318. Ábrelos solo para la red desde la que envían telemetría, por ejemplo una red privada 10.0.0.0/24:
sudo ufw allow from 10.0.0.0/24 to any port 4317 proto tcp
sudo ufw allow from 10.0.0.0/24 to any port 4318 proto tcp
sudo ufw status
Advertenciael receptor OTLP de esta guía no pide autenticación. No abras los puertos 4317 y 4318 a todo Internet; si las aplicaciones están fuera de tu red, usa una VPN o una red privada entre servidores.
Paso 7: Enviar un log de prueba por OTLP
Para confirmar que el pipeline funciona de extremo a extremo sin instrumentar todavía ninguna aplicación, envía un registro de log en formato OTLP/JSON al puerto HTTP con curl:
curl -s -X POST http://127.0.0.1:4318/v1/logs \
-H "Content-Type: application/json" \
-d '{
"resourceLogs": [{
"resource": {
"attributes": [{"key": "service.name", "value": {"stringValue": "prueba-alloy"}}]
},
"scopeLogs": [{
"logRecords": [{
"severityText": "INFO",
"body": {"stringValue": "Hola desde curl a traves de Alloy"}
}]
}]
}]
}'
Si el receptor acepta los datos, responde con un objeto JSON vacío o con {"partialSuccess":{}}. En Grafana, abre Explore, elige el origen de datos de Loki y ejecuta esta consulta:
{service_name="prueba-alloy"}
Deberías ver la línea Hola desde curl a traves de Alloy. Según la versión, el exportador de Loki puede guardar el nombre del servicio como etiqueta service_name o job; si la consulta no devuelve nada, busca con {job="prueba-alloy"}.
Para las trazas y métricas, configura tus aplicaciones con el SDK de OpenTelemetry de su lenguaje y apúntalas al colector con las variables estándar:
export OTEL_EXPORTER_OTLP_ENDPOINT="http://your_server_ip:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_SERVICE_NAME="mi-servicio"
Las trazas aparecerán en Grafana usando el origen de datos de Tempo, y las métricas del host en el de Prometheus, por ejemplo con la consulta node_load1.
Solución de problemas
El servicio no arranca tras cambiar la configuración. Los registros indican el componente y la línea con el error:
sudo journalctl -u alloy -n 30 --no-pager
Un error típico es component "otelcol.exporter.otlp.tempo" does not exist cuando el nombre referenciado en un output no coincide con la etiqueta del componente.
sys.env() devuelve una cadena vacía. Las variables de /etc/default/alloy solo se cargan al reiniciar el servicio, no con una recarga. Ejecuta sudo systemctl restart alloy después de editarlas.
Remote write devuelve 404 o server returned HTTP status 404. Prometheus no tiene activado el receptor de remote write. Arráncalo con la opción --web.enable-remote-write-receiver o apunta PROMETHEUS_URL a Mimir (/api/v1/push).
Tempo rechaza las trazas. Comprueba que Tempo tiene habilitado el receptor OTLP gRPC y que TEMPO_ENDPOINT es host:puerto sin http://.
Consumo de memoria alto. Reduce el limit de otelcol.processor.memory_limiter para que Alloy rechace datos antes, y revisa en la interfaz web qué componente acumula más datos.
Conclusión
Has instalado Grafana Alloy en Ubuntu 24.04 y lo has configurado como colector OpenTelemetry que recibe OTLP, limita la memoria, agrupa los datos y los reparte entre Prometheus, Loki y Tempo, además de recoger las métricas del propio servidor. Como siguientes pasos puedes añadir loki.source.journal para enviar el journal de systemd a Loki, instrumentar tus aplicaciones con el SDK de OpenTelemetry de su lenguaje, o desplegar Alloy en cada servidor para que reenvíe su telemetría a este colector central.
