From 2838ad0fb9f166491a0e560a6095b982dd9472d8 Mon Sep 17 00:00:00 2001 From: erl-100 Date: Mon, 22 Jun 2026 18:06:01 -0400 Subject: [PATCH 1/4] export eth-docker version --- ethd | 26 ++++++++++++++++++++++++++ grafana-cloud.yml | 1 + grafana.yml | 1 + 3 files changed, 28 insertions(+) diff --git a/ethd b/ethd index c6f724ab..91321a5f 100755 --- a/ethd +++ b/ethd @@ -2658,6 +2658,8 @@ reset to defaults." echo "Please make sure to run compatible client versions." fi + __write_eth_docker_version_metric + if [[ ! "$OSTYPE" = "darwin"* ]]; then # Release lock and remove lock file exec 200<&- @@ -4281,6 +4283,29 @@ __adjust_grandine_permissions() { } +# Writes the currently checked-out Eth Docker version as a node-exporter +# textfile-collector metric (see grafana.yml), so it can be tracked the same +# way the EL/CL client versions already are. "tag" is the latest release tag +# reachable from HEAD rather than an exact-match, so this covers both pinned/ +# stable installs (HEAD is on a tag) and tracking "main" (HEAD is ahead of +# the latest tag). +__write_eth_docker_version_metric() { + local tag + local commit + + tag=$(${__as_owner} git describe --tags --abbrev=0 2>/dev/null) || tag="" + commit=$(${__as_owner} git rev-parse --short HEAD 2>/dev/null) || commit="" + + ${__as_owner} mkdir -p ./.eth + { + echo "# HELP eth_docker_version_info Currently checked out Eth Docker version" + echo "# TYPE eth_docker_version_info gauge" + echo "eth_docker_version_info{tag=\"${tag}\",commit=\"${commit}\"} 1" + } | ${__as_owner} tee ./.eth/eth-docker-version.prom.tmp >/dev/null + ${__as_owner} mv ./.eth/eth-docker-version.prom.tmp ./.eth/eth-docker-version.prom +} + + upgrade() { update } @@ -4288,6 +4313,7 @@ upgrade() { start() { __adjust_grandine_permissions + __write_eth_docker_version_metric __docompose up -d --remove-orphans "$@" } diff --git a/grafana-cloud.yml b/grafana-cloud.yml index 71f0f680..fdcf424d 100644 --- a/grafana-cloud.yml +++ b/grafana-cloud.yml @@ -53,6 +53,7 @@ services: - /etc/hostname:/etc/nodename:ro - /etc/localtime:/etc/localtime:ro - ${NODE_EXPORTER_COLLECTOR_MOUNT_PATH:-/tmp/dummy-nodeexp-text}:/tmp/text-collector:ro + - ./.eth/eth-docker-version.prom:/tmp/text-collector/eth-docker-version.prom:ro <<: *logging labels: - metrics.scrape=true diff --git a/grafana.yml b/grafana.yml index 39d9ba1d..107999d0 100644 --- a/grafana.yml +++ b/grafana.yml @@ -76,6 +76,7 @@ services: - /etc/hostname:/etc/nodename:ro - /etc/localtime:/etc/localtime:ro - ${NODE_EXPORTER_COLLECTOR_MOUNT_PATH:-/tmp/dummy-nodeexp-text}:/tmp/text-collector:ro + - ./.eth/eth-docker-version.prom:/tmp/text-collector/eth-docker-version.prom:ro command: - '--path.rootfs=/rootfs' - '--path.sysfs=/host/sys' From e718ad84fc2e16d7f85a144fbc1d887cac55a0d9 Mon Sep 17 00:00:00 2001 From: erl-100 Date: Mon, 22 Jun 2026 18:08:18 -0400 Subject: [PATCH 2/4] Scope Alloy Docker discovery to this install's own Compose project --- alloy/config.alloy | 22 ++++++++++++++++++++++ ethd | 45 ++++++++++++++++++++++++++++++++++++++++---- grafana-cloud.yml | 5 +++-- grafana-rootless.yml | 2 ++ grafana.yml | 5 +++-- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/alloy/config.alloy b/alloy/config.alloy index 9ac2aae7..8169aebc 100644 --- a/alloy/config.alloy +++ b/alloy/config.alloy @@ -11,6 +11,17 @@ discovery.docker "docker_containers" { discovery.relabel "docker_logs" { targets = discovery.docker.docker_containers.targets + // discovery.docker sees every container on the host, not just this + // project's - keep only our own so multiple Eth Docker installs on one + // host don't ship each other's logs. Falls back to matching everything + // (today's behavior) if resolving COMPOSE_PROJECT_NAME ever fails, + // rather than matching nothing. + rule { + source_labels = ["__meta_docker_container_label_com_docker_compose_project"] + regex = coalesce(sys.env("COMPOSE_PROJECT_NAME"), ".*") + action = "keep" + } + rule { source_labels = ["__meta_docker_container_label_logs_collect"] regex = "true" @@ -37,6 +48,17 @@ loki.source.docker "docker_logs" { discovery.relabel "docker_metrics" { targets = discovery.docker.docker_containers.targets + // discovery.docker sees every container on the host, not just this + // project's - keep only our own so multiple Eth Docker installs on one + // host don't scrape/ship each other's metrics. Falls back to matching + // everything (today's behavior) if resolving COMPOSE_PROJECT_NAME ever + // fails, rather than matching nothing. + rule { + source_labels = ["__meta_docker_container_label_com_docker_compose_project"] + regex = coalesce(sys.env("COMPOSE_PROJECT_NAME"), ".*") + action = "keep" + } + rule { source_labels = ["__meta_docker_container_label_metrics_scrape"] regex = "true" diff --git a/ethd b/ethd index 91321a5f..39c4d3f1 100755 --- a/ethd +++ b/ethd @@ -2658,6 +2658,7 @@ reset to defaults." echo "Please make sure to run compatible client versions." fi + __pin_compose_project_name __write_eth_docker_version_metric if [[ ! "$OSTYPE" = "darwin"* ]]; then @@ -4283,26 +4284,61 @@ __adjust_grandine_permissions() { } +# Pins COMPOSE_PROJECT_NAME in .env to whatever Compose already resolves it +# to for this install, if it isn't already set there. This doesn't change +# which project Compose uses - the value is read back from Compose's own +# resolution (docker compose config), never computed independently - it just +# makes that name available for interpolation into the alloy container's +# environment (see grafana.yml), so config.alloy can scope Docker service +# discovery to this instance's own containers. Without this, Alloy's +# discovery.docker sees every container on the host's Docker socket, so +# running multiple Eth Docker installs on one host causes each instance's +# Alloy to also scrape/ship the others' metrics and logs. +__pin_compose_project_name() { + local existing + local resolved + + __get_value_from_env "COMPOSE_PROJECT_NAME" "${__env_file}" "existing" + if [[ -n "${existing}" ]]; then + return 0 + fi + + resolved=$(__docompose config 2>/dev/null | awk -F': ' '/^name:/{print $2; exit}') || resolved="" + if [[ -z "${resolved}" ]]; then + return 0 + fi + + __update_value_in_env "COMPOSE_PROJECT_NAME" "${resolved}" "${__env_file}" +} + + # Writes the currently checked-out Eth Docker version as a node-exporter # textfile-collector metric (see grafana.yml), so it can be tracked the same # way the EL/CL client versions already are. "tag" is the latest release tag # reachable from HEAD rather than an exact-match, so this covers both pinned/ # stable installs (HEAD is on a tag) and tracking "main" (HEAD is ahead of -# the latest tag). +# the latest tag). Writes into the same host directory node-exporter's +# textfile collector is already mounted from (NODE_EXPORTER_COLLECTOR_MOUNT_PATH, +# defaulting to ./.eth/node-exporter-text) - that mount is read-only inside +# the container, so the file has to land there from the host side. __write_eth_docker_version_metric() { local tag local commit + local textfile_dir tag=$(${__as_owner} git describe --tags --abbrev=0 2>/dev/null) || tag="" commit=$(${__as_owner} git rev-parse --short HEAD 2>/dev/null) || commit="" - ${__as_owner} mkdir -p ./.eth + __get_value_from_env "NODE_EXPORTER_COLLECTOR_MOUNT_PATH" "${__env_file}" "textfile_dir" + textfile_dir="${textfile_dir:-./.eth/node-exporter-text}" + + ${__as_owner} mkdir -p "${textfile_dir}" { echo "# HELP eth_docker_version_info Currently checked out Eth Docker version" echo "# TYPE eth_docker_version_info gauge" echo "eth_docker_version_info{tag=\"${tag}\",commit=\"${commit}\"} 1" - } | ${__as_owner} tee ./.eth/eth-docker-version.prom.tmp >/dev/null - ${__as_owner} mv ./.eth/eth-docker-version.prom.tmp ./.eth/eth-docker-version.prom + } | ${__as_owner} tee "${textfile_dir}/eth-docker-version.prom.tmp" >/dev/null + ${__as_owner} mv "${textfile_dir}/eth-docker-version.prom.tmp" "${textfile_dir}/eth-docker-version.prom" } @@ -4312,6 +4348,7 @@ upgrade() { start() { + __pin_compose_project_name __adjust_grandine_permissions __write_eth_docker_version_metric __docompose up -d --remove-orphans "$@" diff --git a/grafana-cloud.yml b/grafana-cloud.yml index fdcf424d..34ba4849 100644 --- a/grafana-cloud.yml +++ b/grafana-cloud.yml @@ -52,8 +52,7 @@ services: - /sys:/host/sys:ro,rslave - /etc/hostname:/etc/nodename:ro - /etc/localtime:/etc/localtime:ro - - ${NODE_EXPORTER_COLLECTOR_MOUNT_PATH:-/tmp/dummy-nodeexp-text}:/tmp/text-collector:ro - - ./.eth/eth-docker-version.prom:/tmp/text-collector/eth-docker-version.prom:ro + - ${NODE_EXPORTER_COLLECTOR_MOUNT_PATH:-./.eth/node-exporter-text}:/tmp/text-collector:ro <<: *logging labels: - metrics.scrape=true @@ -121,6 +120,8 @@ services: alloy: image: grafana/alloy:latest restart: unless-stopped + environment: + - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} volumes: - alloy-data:/var/lib/alloy - ./alloy:/etc/alloy diff --git a/grafana-rootless.yml b/grafana-rootless.yml index 86ed5911..d0d9410f 100644 --- a/grafana-rootless.yml +++ b/grafana-rootless.yml @@ -94,6 +94,8 @@ services: alloy: image: grafana/alloy:latest restart: unless-stopped + environment: + - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} volumes: - alloy-data:/var/lib/alloy - ./alloy:/etc/alloy diff --git a/grafana.yml b/grafana.yml index 107999d0..e2377dd4 100644 --- a/grafana.yml +++ b/grafana.yml @@ -75,8 +75,7 @@ services: - /sys:/host/sys:ro,rslave - /etc/hostname:/etc/nodename:ro - /etc/localtime:/etc/localtime:ro - - ${NODE_EXPORTER_COLLECTOR_MOUNT_PATH:-/tmp/dummy-nodeexp-text}:/tmp/text-collector:ro - - ./.eth/eth-docker-version.prom:/tmp/text-collector/eth-docker-version.prom:ro + - ${NODE_EXPORTER_COLLECTOR_MOUNT_PATH:-./.eth/node-exporter-text}:/tmp/text-collector:ro command: - '--path.rootfs=/rootfs' - '--path.sysfs=/host/sys' @@ -152,6 +151,8 @@ services: alloy: image: grafana/alloy:latest restart: unless-stopped + environment: + - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} volumes: - alloy-data:/var/lib/alloy - ./alloy:/etc/alloy From a6bd8fbb8a5a2848bdc3320fee3006ba1eef4cbf Mon Sep 17 00:00:00 2001 From: erl-100 Date: Mon, 22 Jun 2026 20:41:44 -0400 Subject: [PATCH 3/4] update comment --- alloy/config.alloy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/alloy/config.alloy b/alloy/config.alloy index 8169aebc..8d4756d5 100644 --- a/alloy/config.alloy +++ b/alloy/config.alloy @@ -13,9 +13,9 @@ discovery.relabel "docker_logs" { // discovery.docker sees every container on the host, not just this // project's - keep only our own so multiple Eth Docker installs on one - // host don't ship each other's logs. Falls back to matching everything - // (today's behavior) if resolving COMPOSE_PROJECT_NAME ever fails, - // rather than matching nothing. + // host don't ship each other's logs. Falls back to matching every + // container on the host if resolving COMPOSE_PROJECT_NAME ever fails, + // rather than matching none. rule { source_labels = ["__meta_docker_container_label_com_docker_compose_project"] regex = coalesce(sys.env("COMPOSE_PROJECT_NAME"), ".*") @@ -51,8 +51,8 @@ discovery.relabel "docker_metrics" { // discovery.docker sees every container on the host, not just this // project's - keep only our own so multiple Eth Docker installs on one // host don't scrape/ship each other's metrics. Falls back to matching - // everything (today's behavior) if resolving COMPOSE_PROJECT_NAME ever - // fails, rather than matching nothing. + // every container on the host if resolving COMPOSE_PROJECT_NAME ever + // fails, rather than matching none. rule { source_labels = ["__meta_docker_container_label_com_docker_compose_project"] regex = coalesce(sys.env("COMPOSE_PROJECT_NAME"), ".*") From c6f06127030027e33119493978d96ac86ce1a1f3 Mon Sep 17 00:00:00 2001 From: erl-100 Date: Tue, 23 Jun 2026 19:50:09 -0400 Subject: [PATCH 4/4] Read eth-docker version from README.md instead of nearest git tag --- ethd | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ethd b/ethd index 39c4d3f1..61288670 100755 --- a/ethd +++ b/ethd @@ -4314,19 +4314,20 @@ __pin_compose_project_name() { # Writes the currently checked-out Eth Docker version as a node-exporter # textfile-collector metric (see grafana.yml), so it can be tracked the same -# way the EL/CL client versions already are. "tag" is the latest release tag -# reachable from HEAD rather than an exact-match, so this covers both pinned/ -# stable installs (HEAD is on a tag) and tracking "main" (HEAD is ahead of -# the latest tag). Writes into the same host directory node-exporter's -# textfile collector is already mounted from (NODE_EXPORTER_COLLECTOR_MOUNT_PATH, -# defaulting to ./.eth/node-exporter-text) - that mount is read-only inside -# the container, so the file has to land there from the host side. +# way the EL/CL client versions already are. "tag" comes from README.md's +# "This is Eth Docker vX.Y.Z" line (the same source `version` reads). A +# release commit bumps that line straight to "vX.Y.Z-dev" for the next +# version, so this stays accurate on main between releases. Writes into +# the same host directory node-exporter's textfile collector is already +# mounted from (NODE_EXPORTER_COLLECTOR_MOUNT_PATH, defaulting to +# ./.eth/node-exporter-text) - that mount is read-only inside the +# container, so the file has to land there from the host side. __write_eth_docker_version_metric() { local tag local commit local textfile_dir - tag=$(${__as_owner} git describe --tags --abbrev=0 2>/dev/null) || tag="" + tag=$(grep -m1 "^This is Eth Docker v" README.md 2>/dev/null | sed -E 's/^This is Eth Docker //') || tag="" commit=$(${__as_owner} git rev-parse --short HEAD 2>/dev/null) || commit="" __get_value_from_env "NODE_EXPORTER_COLLECTOR_MOUNT_PATH" "${__env_file}" "textfile_dir"