diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000000..4f8d701a81 --- /dev/null +++ b/example/README.md @@ -0,0 +1,52 @@ +# Docker Compose example + +This directory contains a Docker Compose environment that can be used to test +Grafana Alloy. + +By default, only Grafana and databases are exposed: + +* Grafana, for visualizing telemetry (`localhost:3000`) +* Grafana Mimir, for storing metrics (`localhost:9009`) +* Grafana Loki, for storing logs (`localhost:3000`) +* Grafana Tempo, for storing traces (`localhost:3200`) +* Grafana Pyroscope, for storing profiles (`localhost:4040`) + +Grafana is automatically provisioned with the appropriate datasources and +dashboards for monitoring Grafana Alloy. + +To start the environment, run: + +```bash +docker compose up -d +``` + +To stop the environment, run: + +```bash +docker compose down +``` + +## Running Alloy + +Alloy can either be run locally or within Docker Compose. The [example +configuration](./config/alloy/config.alloy) can be used to send self-monitoring +data from a local Alloy to the various databases running in Docker Compose. + +To run Alloy within Docker Compose, pass `--profile=alloy` to `docker compose` +when starting and stopping the environment: + +```bash +docker compose --profile=alloy up -d +``` + +```bash +docker compose --profile=alloy down +``` + +## Visualizing + +To visualize Alloy data in Grafana, open in a web +browser and look at the dashboards in the `Alloy` folder. + +> **NOTE**: It can take up to a minute for Alloy metrics and profiles to start +> appearing. diff --git a/example/compose.yaml b/example/compose.yaml new file mode 100644 index 0000000000..720a1d8726 --- /dev/null +++ b/example/compose.yaml @@ -0,0 +1,32 @@ +name: alloy-example + +include: + - ./grafana.yaml + - ./databases.yaml + +services: + alloy: + image: grafana/alloy:v1.0.0 + pull_policy: always + profiles: ["alloy"] + restart: on-failure + volumes: + - ./config/alloy:/etc/alloy + environment: + REMOTE_WRITE_HOST: mimir:9009 + LOKI_HOST: loki:3100 + TEMPO_HOST: tempo:4317 + PYROSCOPE_HOST: pyroscope:4040 + depends_on: + - mimir + - loki + - tempo + - pyroscope + command: + - run + - /etc/alloy/config.alloy + - --storage.path=/var/lib/alloy/data + - --server.http.listen-addr=0.0.0.0:12345 + - --stability.level=experimental # Enable all functionality + ports: + - "12345:12345" diff --git a/example/config/alloy/config.alloy b/example/config/alloy/config.alloy new file mode 100644 index 0000000000..74ef592c42 --- /dev/null +++ b/example/config/alloy/config.alloy @@ -0,0 +1,74 @@ +// This file serves as an example Alloy configuration to interact with the +// Docker Compose environment. +// +// This configuration works whether you are running Alloy locally or within the +// Docker Compose environment when the `alloy` profile is enabled. + +logging { + level = "debug" + + // Forward internal logs to the local Loki instance. + write_to = [loki.write.loki.receiver] +} + +tracing { + // Write all spans. Don't do this in production! + sampling_fraction = 1.0 + + // Forward internal spans to the local Tempo instance. + write_to = [otelcol.exporter.otlp.tempo.input] +} + +// Collect metrics from the local running Alloy instance and forward to +// Prometheus. +prometheus.exporter.self "alloy" {} +prometheus.scrape "alloy" { + targets = prometheus.exporter.self.alloy.targets + forward_to = [prometheus.remote_write.mimir.receiver] +} + +// Collect profiles from the local running Alloy instance and forward to +// Pyroscope. +pyroscope.scrape "default" { + targets = [ + {"__address__" = "localhost:12345", "service_name" = "alloy"}, + ] + forward_to = [pyroscope.write.pyroscope.receiver] +} + +prometheus.remote_write "mimir" { + endpoint { + url = format( + "http://%s/api/v1/push", + coalesce(env("REMOTE_WRITE_HOST"), "localhost:9009"), + ) + } +} + +loki.write "loki" { + endpoint { + url = format( + "http://%s/loki/api/v1/push", + coalesce(env("LOKI_HOST"), "localhost:3100"), + ) + } +} + +otelcol.exporter.otlp "tempo" { + client { + endpoint = coalesce(env("TEMPO_HOST"), "localhost:4317") + + tls { + insecure = true + } + } +} + +pyroscope.write "pyroscope" { + endpoint { + url = format( + "http://%s", + coalesce(env("PYROSCOPE_HOST"), "localhost:4040"), + ) + } +} diff --git a/example/config/grafana/datasources/datasource.yml b/example/config/grafana/datasources/datasource.yml new file mode 100644 index 0000000000..2bf975bbfe --- /dev/null +++ b/example/config/grafana/datasources/datasource.yml @@ -0,0 +1,53 @@ +apiVersion: 1 + +deleteDatasources: + - name: Mimir + +datasources: +- name: Mimir + type: prometheus + access: proxy + orgId: 1 + url: http://mimir:9009/prometheus + basicAuth: false + isDefault: false + version: 1 + editable: true + jsonData: + # The recommended scrape interval is 60s. + timeInterval: '60s' +- name: Loki + type: loki + access: proxy + orgId: 1 + url: http://loki:3100 + basicAuth: false + isDefault: false + version: 1 + editable: true + jsonData: + derivedFields: + - datasourceUid: tempo + matcherRegex: tid=(\w+) + name: TraceID + url: $${__value.raw} +- name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: false + version: 1 + editable: true + apiVersion: 1 + uid: tempo +- name: Pyroscope + type: grafana-pyroscope-datasource + access: proxy + orgId: 1 + url: http://pyroscope:4040/ + basicAuth: false + isDefault: false + version: 1 + editable: true diff --git a/example/config/grafana/grafana.ini b/example/config/grafana/grafana.ini new file mode 100644 index 0000000000..ba1078c518 --- /dev/null +++ b/example/config/grafana/grafana.ini @@ -0,0 +1,9 @@ +[analytics] +reporting_enabled = false +[auth.anonymous] +enabled = true +org_role = Admin +[explore] +enabled = true +[users] +default_theme = dark diff --git a/example/config/mimir/mimir.yaml b/example/config/mimir/mimir.yaml new file mode 100644 index 0000000000..e48447f24c --- /dev/null +++ b/example/config/mimir/mimir.yaml @@ -0,0 +1,63 @@ +# Do not use this configuration in production. +# It is for demonstration purposes only. +multitenancy_enabled: false + +activity_tracker: {} + +alertmanager: {} + +alertmanager_storage: + backend: local + +server: + http_listen_port: 9009 + + # Configure the server to allow messages up to 100MB. + grpc_server_max_recv_msg_size: 104857600 + grpc_server_max_send_msg_size: 104857600 + grpc_server_max_concurrent_streams: 1000 + +distributor: + pool: + health_check_ingesters: true + +ingester_client: + grpc_client_config: + grpc_compression: gzip + max_recv_msg_size: 104857600 + max_send_msg_size: 104857600 + +ingester: + ring: + final_sleep: 0s + kvstore: + store: inmemory + min_ready_duration: 0s + num_tokens: 512 + replication_factor: 1 + +blocks_storage: + backend: filesystem + bucket_store: + sync_dir: /tmp/mimir/tsdb-sync + filesystem: + dir: /tmp/mimir/blocks + tsdb: + dir: /tmp/mimir/tsdb + +compactor: + sharding_ring: + kvstore: + store: inmemory + +ruler: + enable_api: true + +ruler_storage: + backend: filesystem + local: + directory: /tmp/mimir/rules + +limits: + ingestion_burst_size: 500000 + ingestion_rate: 250000 diff --git a/example/databases.yaml b/example/databases.yaml new file mode 100644 index 0000000000..4ea8f972be --- /dev/null +++ b/example/databases.yaml @@ -0,0 +1,35 @@ +services: + mimir: + image: grafana/mimir:2.12.0 + restart: on-failure + command: + - -config.file=/etc/mimir-config/mimir.yaml + volumes: + - ./config/mimir:/etc/mimir-config + ports: + - "9009:9009" + + loki: + image: grafana/loki:3.0.0 + restart: on-failure + ports: + - "3100:3100" + + tempo: + image: grafana/tempo:2.4.1 + restart: on-failure + command: + - "-storage.trace.backend=local" # tell tempo where to permanently put traces + - "-storage.trace.local.path=/tmp/tempo/traces" + - "-storage.trace.wal.path=/tmp/tempo/wal" # tell tempo where to store the wal + - "-auth.enabled=false" # disables the requirement for the X-Scope-OrgID header + - "-server.http-listen-port=3200" + ports: + - "3200:3200" + - "4317:4317" + + pyroscope: + image: grafana/pyroscope:1.5.0 + restart: on-failure + ports: + - "4040:4040" diff --git a/example/grafana.yaml b/example/grafana.yaml new file mode 100644 index 0000000000..e93c7d6e5b --- /dev/null +++ b/example/grafana.yaml @@ -0,0 +1,47 @@ +services: + grafana: + image: grafana/grafana:10.1.9 + restart: on-failure + command: + - --config=/etc/grafana-config/grafana.ini + volumes: + - ./config/grafana:/etc/grafana-config + - ./config/grafana/datasources:/etc/grafana/provisioning/datasources + ports: + - "3000:3000" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"] + interval: 1s + start_interval: 0s + timeout: 10s + retries: 5 + + # Provision alloy-mixin after Grafana is healthy and running. + provision-dashboards: + build: images/grizzly + restart: on-failure + depends_on: + grafana: + condition: service_healthy + environment: + - GRAFANA_URL=http://grafana:3000 + volumes: + - ../operations/alloy-mixin:/etc/alloy-mixin + working_dir: /etc/alloy-mixin + command: grr apply grizzly/dashboards.jsonnet + + # Watch dashboards for changes and apply them to Grafana. + watch-dashboards: + build: images/grizzly + restart: on-failure + depends_on: + grafana: + condition: service_healthy + environment: + - GRAFANA_URL=http://grafana:3000 + volumes: + - ../operations/alloy-mixin:/etc/alloy-mixin + working_dir: /etc/alloy-mixin + command: grr watch dashboards/ grizzly/dashboards.jsonnet + + diff --git a/example/images/grizzly/Dockerfile b/example/images/grizzly/Dockerfile new file mode 100644 index 0000000000..e9ef275208 --- /dev/null +++ b/example/images/grizzly/Dockerfile @@ -0,0 +1,2 @@ +FROM golang:1.22-alpine +RUN go install github.com/grafana/grizzly/cmd/grr@v0.2.1