observability: fix alloy ui component, busybox healthchecks for loki/alloy
- alloy 1.x renamed the server component to ui; the old block failed the initial load and the container crash-looped - grafana/loki is distroless and grafana/alloy lacks wget, so their healthchecks could never run; local images add a static busybox from alpine for that one command - deploy.sh builds all three local images if missing - tests: 3 new seams
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
# Alloy + a static busybox.
|
||||
#
|
||||
# grafana/alloy has a shell but no wget/curl, so the compose healthcheck
|
||||
# cannot run anything inside the container. This image drops a static
|
||||
# busybox into it for the healthcheck command only. All Alloy behavior is
|
||||
# unchanged.
|
||||
#
|
||||
# Build on dankclaw:
|
||||
# podman build -t franksdank/alloy:latest -f dankclaw/alloy/Containerfile .
|
||||
|
||||
FROM docker.io/library/alpine:latest AS tools
|
||||
# busybox provides wget for the healthcheck.
|
||||
|
||||
FROM docker.io/grafana/alloy:latest
|
||||
COPY --from=tools /bin/busybox /usr/local/bin/busybox
|
||||
@@ -149,7 +149,8 @@ services:
|
||||
retries: 3
|
||||
|
||||
loki:
|
||||
image: docker.io/grafana/loki:latest
|
||||
# Local build: grafana/loki + static busybox (healthcheck).
|
||||
image: franksdank/loki:latest
|
||||
container_name: loki
|
||||
restart: unless-stopped
|
||||
# Rootless: container root maps to the invoking user (dank), which
|
||||
@@ -163,13 +164,14 @@ services:
|
||||
- /opt/loki/config:/etc/loki
|
||||
- /opt/loki/data:/loki
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3100/ready"]
|
||||
test: ["CMD", "/usr/local/bin/busybox", "wget", "--spider", "-q", "http://localhost:3100/ready"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
alloy:
|
||||
image: docker.io/grafana/alloy:latest
|
||||
# Local build: grafana/alloy + static busybox (healthcheck).
|
||||
image: franksdank/alloy:latest
|
||||
container_name: alloy
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
@@ -180,7 +182,7 @@ services:
|
||||
depends_on:
|
||||
- loki
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:12345/-/healthy"]
|
||||
test: ["CMD", "/usr/local/bin/busybox", "wget", "--spider", "-q", "http://localhost:12345/-/healthy"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Loki + a static busybox.
|
||||
#
|
||||
# grafana/loki is distroless: no shell, no wget, so the compose healthcheck
|
||||
# cannot run anything inside the container. This image drops a static
|
||||
# busybox into it for the healthcheck command only. All Loki behavior is
|
||||
# unchanged.
|
||||
#
|
||||
# Build on dankclaw:
|
||||
# podman build -t franksdank/loki:latest -f dankclaw/loki/Containerfile .
|
||||
|
||||
FROM docker.io/library/alpine:latest AS tools
|
||||
# busybox provides wget for the healthcheck.
|
||||
|
||||
FROM docker.io/grafana/loki:latest
|
||||
COPY --from=tools /bin/busybox /usr/local/bin/busybox
|
||||
+10
-4
@@ -139,10 +139,16 @@ fi
|
||||
|
||||
if [ '${COMPOSE_UP[$TARGET]}' = '1' ]; then
|
||||
echo '[4/4] Restarting stack...'
|
||||
if ! podman image exists franksdank/caddy-porkbun:latest; then
|
||||
echo ' franksdank/caddy-porkbun image missing; building it (a few minutes)...'
|
||||
podman build -t franksdank/caddy-porkbun:latest -f dankclaw/caddy/Containerfile .
|
||||
fi
|
||||
# Locally built images: caddy + porkbun module, and loki/alloy + a static
|
||||
# busybox (their upstream images lack the wget the healthchecks need).
|
||||
for dir in caddy loki alloy; do
|
||||
img=franksdank/$dir
|
||||
[ "$dir" = "caddy" ] && img=franksdank/caddy-porkbun
|
||||
if ! podman image exists $img:latest; then
|
||||
echo " $img image missing; building it..."
|
||||
podman build -t $img:latest -f dankclaw/$dir/Containerfile .
|
||||
fi
|
||||
done
|
||||
podman-compose -f '${COMPOSE[$TARGET]}' up -d
|
||||
else
|
||||
echo '[4/4] Skipping compose restart (stack runs as bare containers on this host)'
|
||||
|
||||
@@ -6,9 +6,10 @@ logging {
|
||||
}
|
||||
|
||||
// Local listener so the container healthcheck can probe us.
|
||||
server {
|
||||
http_listen_addr = "0.0.0.0:12345"
|
||||
grpc_listen_addr = "0.0.0.0:12346"
|
||||
// Alloy >= 1.0 renamed the server component to ui.
|
||||
ui {
|
||||
host = "0.0.0.0"
|
||||
port = 12345
|
||||
}
|
||||
|
||||
// Ship logs to Loki (container name on the podman network).
|
||||
|
||||
@@ -136,3 +136,29 @@ CADDYFILE="$REPO_ROOT/dankclaw/Caddyfile"
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
# --- distroless healthchecks (loki/alloy carry a static busybox) ---
|
||||
|
||||
@test "loki and alloy run from local images carrying a static busybox" {
|
||||
local compose="$REPO_ROOT/dankclaw/compose.yaml"
|
||||
grep -q 'image: franksdank/loki:latest' "$compose" || { echo "loki image not local"; return 1; }
|
||||
grep -q 'image: franksdank/alloy:latest' "$compose" || { echo "alloy image not local"; return 1; }
|
||||
local img
|
||||
for img in loki alloy; do
|
||||
local cf="$REPO_ROOT/dankclaw/$img/Containerfile"
|
||||
[ -f "$cf" ] || { echo "missing $cf"; return 1; }
|
||||
grep -q 'busybox' "$cf" || { echo "$cf does not install busybox"; return 1; }
|
||||
done
|
||||
}
|
||||
|
||||
@test "loki and alloy healthchecks use the busybox wget" {
|
||||
local compose="$REPO_ROOT/dankclaw/compose.yaml"
|
||||
local n
|
||||
n=$(grep -c '/usr/local/bin/busybox' "$compose")
|
||||
[ "$n" -ge 2 ] || { echo "expected >=2 busybox healthchecks, found $n"; return 1; }
|
||||
}
|
||||
|
||||
@test "alloy config uses the ui component (the server component was renamed)" {
|
||||
grep -qE '^ui \{' "$REPO_ROOT/shared/alloy/config.alloy"
|
||||
! grep -qE '^server \{' "$REPO_ROOT/shared/alloy/config.alloy"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user