From 61f02a03358d518ebf58c3fbf07c4f70fcc11be9 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 17 Mar 2026 16:42:53 -0700 Subject: [PATCH] Localize Alloy container image (#300) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add `containers/alloy/` with dual Dockerfile + Nix build files for Grafana Alloy v1.14.0 - Both builds fetch source from forge mirror (`forge.ops.eblu.me/mirrors/alloy.git`), build the web UI (Node), then compile the Go binary with `netgo embedalloyui` tags - Update all three alloy deployments (alloy-k8s, alloy-ringtail, alloy-tracing-ringtail) to use `registry.ops.eblu.me/blumeops/alloy` - `promtail_journal_enabled` tag omitted — requires systemd headers and none of our configs use `loki.source.journal` ## Build verification - **Dockerfile:** Tested locally via `docker build`, binary reports `v1.14.0` with correct tags - **Nix:** Tested on ringtail via `nix-build`, all three hashes (fetchgit, npmDeps, goModules) resolved and build succeeds ## Post-merge steps 1. Wait for CI to build the container from main (both Dockerfile and Nix workflows) 2. `mise run container-list alloy` to find the `[main]` tagged image 3. C0 follow-up to update `newTag` in all three kustomizations from `v1.14.0-placeholder` to the real tag 4. Sync ArgoCD apps and verify pods come up healthy Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/300 --- argocd/manifests/alloy-k8s/daemonset.yaml | 2 +- argocd/manifests/alloy-k8s/kustomization.yaml | 4 +- .../manifests/alloy-ringtail/daemonset.yaml | 2 +- .../alloy-ringtail/kustomization.yaml | 4 +- .../alloy-tracing-ringtail/daemonset.yaml | 2 +- .../alloy-tracing-ringtail/kustomization.yaml | 4 +- containers/alloy/Dockerfile | 65 ++++++++ containers/alloy/default.nix | 140 ++++++++++++++++++ .../feature-localize-alloy-container.infra.md | 1 + 9 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 containers/alloy/Dockerfile create mode 100644 containers/alloy/default.nix create mode 100644 docs/changelog.d/feature-localize-alloy-container.infra.md diff --git a/argocd/manifests/alloy-k8s/daemonset.yaml b/argocd/manifests/alloy-k8s/daemonset.yaml index 98d69dc..60b8883 100644 --- a/argocd/manifests/alloy-k8s/daemonset.yaml +++ b/argocd/manifests/alloy-k8s/daemonset.yaml @@ -19,7 +19,7 @@ spec: fsGroup: 473 # alloy user group containers: - name: alloy - image: grafana/alloy:kustomized + image: registry.ops.eblu.me/blumeops/alloy:kustomized args: - run - --server.http.listen-addr=0.0.0.0:12345 diff --git a/argocd/manifests/alloy-k8s/kustomization.yaml b/argocd/manifests/alloy-k8s/kustomization.yaml index 6209a0b..38f0676 100644 --- a/argocd/manifests/alloy-k8s/kustomization.yaml +++ b/argocd/manifests/alloy-k8s/kustomization.yaml @@ -9,8 +9,8 @@ resources: - daemonset.yaml images: - - name: grafana/alloy - newTag: v1.14.0 + - name: registry.ops.eblu.me/blumeops/alloy + newTag: v1.14.0-placeholder configMapGenerator: - name: alloy-config diff --git a/argocd/manifests/alloy-ringtail/daemonset.yaml b/argocd/manifests/alloy-ringtail/daemonset.yaml index 6f723b8..fffd66e 100644 --- a/argocd/manifests/alloy-ringtail/daemonset.yaml +++ b/argocd/manifests/alloy-ringtail/daemonset.yaml @@ -19,7 +19,7 @@ spec: fsGroup: 473 # alloy user group containers: - name: alloy - image: grafana/alloy:kustomized + image: registry.ops.eblu.me/blumeops/alloy:kustomized args: - run - --server.http.listen-addr=0.0.0.0:12345 diff --git a/argocd/manifests/alloy-ringtail/kustomization.yaml b/argocd/manifests/alloy-ringtail/kustomization.yaml index 6209a0b..38f0676 100644 --- a/argocd/manifests/alloy-ringtail/kustomization.yaml +++ b/argocd/manifests/alloy-ringtail/kustomization.yaml @@ -9,8 +9,8 @@ resources: - daemonset.yaml images: - - name: grafana/alloy - newTag: v1.14.0 + - name: registry.ops.eblu.me/blumeops/alloy + newTag: v1.14.0-placeholder configMapGenerator: - name: alloy-config diff --git a/argocd/manifests/alloy-tracing-ringtail/daemonset.yaml b/argocd/manifests/alloy-tracing-ringtail/daemonset.yaml index 75cfea7..e56cc9d 100644 --- a/argocd/manifests/alloy-tracing-ringtail/daemonset.yaml +++ b/argocd/manifests/alloy-tracing-ringtail/daemonset.yaml @@ -18,7 +18,7 @@ spec: hostPID: true containers: - name: alloy - image: grafana/alloy:kustomized + image: registry.ops.eblu.me/blumeops/alloy:kustomized args: - run - --server.http.listen-addr=0.0.0.0:12346 diff --git a/argocd/manifests/alloy-tracing-ringtail/kustomization.yaml b/argocd/manifests/alloy-tracing-ringtail/kustomization.yaml index fec545b..fd342c3 100644 --- a/argocd/manifests/alloy-tracing-ringtail/kustomization.yaml +++ b/argocd/manifests/alloy-tracing-ringtail/kustomization.yaml @@ -8,8 +8,8 @@ resources: - daemonset.yaml images: - - name: grafana/alloy - newTag: v1.14.0 + - name: registry.ops.eblu.me/blumeops/alloy + newTag: v1.14.0-placeholder configMapGenerator: - name: alloy-tracing-config diff --git a/containers/alloy/Dockerfile b/containers/alloy/Dockerfile new file mode 100644 index 0000000..e9bae40 --- /dev/null +++ b/containers/alloy/Dockerfile @@ -0,0 +1,65 @@ +# Grafana Alloy telemetry collector +# Three-stage build: Web UI (Node), server (Go), runtime (Alpine) + +ARG CONTAINER_APP_VERSION=1.14.0 +ARG ALLOY_VERSION=v${CONTAINER_APP_VERSION} +ARG ALLOY_COMMIT=626a738319812d58ebc25ca6d71651f4925b8b18 + +FROM node:22-alpine AS ui-build + +ARG ALLOY_COMMIT +RUN apk add --no-cache git + +RUN mkdir /app && cd /app \ + && git init \ + && git remote add origin https://forge.ops.eblu.me/mirrors/alloy.git \ + && git fetch --depth 1 origin ${ALLOY_COMMIT} \ + && git checkout FETCH_HEAD + +WORKDIR /app/internal/web/ui +RUN npm ci +RUN npx tsc -b && npx vite build + +FROM golang:1.25-alpine3.22 AS build + +ARG ALLOY_VERSION +ARG ALLOY_COMMIT +RUN apk add --no-cache build-base git + +RUN mkdir /app && cd /app \ + && git init \ + && git remote add origin https://forge.ops.eblu.me/mirrors/alloy.git \ + && git fetch --depth 1 origin ${ALLOY_COMMIT} \ + && git checkout FETCH_HEAD + +WORKDIR /app + +# Copy pre-built web UI assets +COPY --from=ui-build /app/internal/web/ui/dist /app/internal/web/ui/dist + +ENV CGO_ENABLED=1 + +# promtail_journal_enabled omitted: requires systemd headers (libsystemd-dev) +# and our k8s deployments read pod logs from the filesystem, not journald +RUN RELEASE_BUILD=1 VERSION=${ALLOY_VERSION} \ + GO_TAGS="netgo embedalloyui" \ + SKIP_UI_BUILD=1 \ + make alloy + +FROM alpine:3.22 + +LABEL org.opencontainers.image.title=alloy +LABEL org.opencontainers.image.description="Grafana Alloy is an OpenTelemetry Collector distribution" +LABEL org.opencontainers.image.source=https://github.com/grafana/alloy + +RUN apk --no-cache add ca-certificates tzdata \ + && addgroup -g 473 alloy \ + && adduser -D -u 473 -G alloy alloy \ + && mkdir -p /var/lib/alloy/data \ + && chown -R alloy:alloy /var/lib/alloy + +COPY --from=build --chown=473:473 /app/build/alloy /bin/alloy + +ENTRYPOINT ["/bin/alloy"] +ENV ALLOY_DEPLOY_MODE=docker +CMD ["run", "/etc/alloy/config.alloy", "--storage.path=/var/lib/alloy/data"] diff --git a/containers/alloy/default.nix b/containers/alloy/default.nix new file mode 100644 index 0000000..f8e4966 --- /dev/null +++ b/containers/alloy/default.nix @@ -0,0 +1,140 @@ +# Nix-built Grafana Alloy telemetry collector +# Builds v1.14.0 from forge mirror with embedded web UI +# Uses stdenv + make (not buildGoModule) due to multi-module workspace +# with local replace directives (collector/ -> ../, ../syntax, ../extension) +# Built with dockerTools.buildLayeredImage for efficient layer caching +{ pkgs ? import { } }: + +let + version = "1.14.0"; + + src = pkgs.fetchgit { + url = "https://forge.ops.eblu.me/mirrors/alloy.git"; + rev = "v${version}"; + hash = "sha256-gxNz4XDE8XSl6LsP3k8DERqDdMLcmbWKfXZGGyRULkg="; + }; + + ui = pkgs.buildNpmPackage { + inherit version; + pname = "alloy-ui"; + src = "${src}/internal/web/ui"; + npmDepsHash = "sha256-GT0yisPn+3FCtWL3he0i5zPMlaWNparQDefU69G4Yis="; + + buildPhase = '' + runHook preBuild + npx tsc -b + npx vite build + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/dist + cp -r dist/* $out/dist/ + runHook postInstall + ''; + }; + + # Pre-fetch Go modules for all three go.mod files (fixed-output derivation) + goModules = pkgs.stdenv.mkDerivation { + pname = "alloy-go-modules"; + inherit src version; + + nativeBuildInputs = with pkgs; [ go git cacert ]; + + buildPhase = '' + export GOPATH=$TMPDIR/go + export GOFLAGS=-modcacherw + # Download modules for all three go.mod files + go mod download + cd syntax && go mod download && cd .. + cd collector && go mod download && cd .. + ''; + + installPhase = '' + cp -r $TMPDIR/go/pkg/mod $out + ''; + + outputHashMode = "recursive"; + outputHash = "sha256-rD7zqomSVv4d8NaC7jXXgihuQvK8guaAN0KrsBRWMVQ="; + outputHashAlgo = "sha256"; + }; + + alloy = pkgs.stdenv.mkDerivation { + inherit src version; + pname = "alloy"; + + nativeBuildInputs = with pkgs; [ + go + git + gnumake + cacert + ]; + + buildPhase = '' + runHook preBuild + + export HOME=$TMPDIR + export GOPATH=$TMPDIR/go + export GOFLAGS=-modcacherw + + # Populate module cache from pre-fetched modules + mkdir -p $GOPATH/pkg + cp -r ${goModules} $GOPATH/pkg/mod + chmod -R u+w $GOPATH/pkg/mod + + # Copy pre-built web UI assets + cp -r ${ui}/dist/ internal/web/ui/dist + + # Build using upstream Makefile + # promtail_journal_enabled omitted: requires systemd headers + # and our k8s deployments read pod logs from the filesystem, not journald + RELEASE_BUILD=1 \ + VERSION=v${version} \ + GO_TAGS="netgo embedalloyui" \ + SKIP_UI_BUILD=1 \ + make alloy + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp build/alloy $out/bin/alloy + runHook postInstall + ''; + + meta = with pkgs.lib; { + description = "OpenTelemetry Collector distribution with programmable pipelines"; + homepage = "https://grafana.com/docs/alloy/"; + license = licenses.asl20; + mainProgram = "alloy"; + }; + }; +in + +pkgs.dockerTools.buildLayeredImage { + name = "blumeops/alloy"; + tag = "latest"; + + contents = [ + alloy + pkgs.cacert + pkgs.tzdata + ]; + + config = { + Entrypoint = [ "${alloy}/bin/alloy" ]; + Cmd = [ "run" "/etc/alloy/config.alloy" "--storage.path=/var/lib/alloy/data" ]; + Env = [ + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + "TZDIR=${pkgs.tzdata}/share/zoneinfo" + "ALLOY_DEPLOY_MODE=docker" + ]; + ExposedPorts = { + "12345/tcp" = { }; + }; + User = "65534"; + }; +} diff --git a/docs/changelog.d/feature-localize-alloy-container.infra.md b/docs/changelog.d/feature-localize-alloy-container.infra.md new file mode 100644 index 0000000..42a2c21 --- /dev/null +++ b/docs/changelog.d/feature-localize-alloy-container.infra.md @@ -0,0 +1 @@ +Localize Grafana Alloy container image with dual Dockerfile + Nix builds from forge mirror