Goldmane is a flow aggregation service that provides a central, aggregated view of network flows in a Kubernetes cluster. It receives per-node flow data from Felix via gRPC, aggregates flows across nodes and time, and optionally emits them to an upstream HTTP endpoint. It also serves queries for the Whisker UI.
Operational guidance (build, test, debug recipes) lives in
goldmane/CLAUDE.md. This document is for
architecture, invariants, and the daemon's external surface.
Defined in proto/api.proto. Goldmane exposes three services on a
single TLS-enabled port (default 443, typically accessed via
Kubernetes Service on port 7443):
FlowCollector— receives streaming flow updates from Felix on each node (ConnectRPC, bidirectional streaming). Deduplicates flows on reconnection.Flows— serves flow queries to consumers (Whisker UI, debugging tools). SupportsList(paginated),Stream(live updates), andFilterHints(autocomplete-style filter discovery).Statistics— serves per-policy/per-rule statistics with optional time-series data.
| Package | Description |
|---|---|
cmd/ |
Main entrypoint — calls daemon.Run() with env-based config |
cmd/stream/ |
Debug CLI tool that connects to Goldmane and prints streamed flows |
cmd/flowgen/ |
Test tool that generates fake flow data |
cmd/health/ |
Health check binary |
pkg/daemon/ |
Daemon setup — gRPC server, TLS, health, emitter, sink management |
pkg/goldmane/ |
Core aggregation engine — single main loop serializing all operations (flow ingestion, rollover, queries, stream backfill, sink changes) |
pkg/storage/ |
BucketRing (ring buffer of time-bucketed flow data), DiachronicFlow (per-flow-key time series), indices for sorting/filtering |
pkg/server/ |
gRPC service implementations wrapping the Goldmane engine |
pkg/client/ |
Go client wrappers for the gRPC services |
pkg/emitter/ |
Pushes aggregated flows to an upstream HTTP endpoint via a rate-limited workqueue |
pkg/stream/ |
Stream management for live flow subscriptions |
pkg/types/ |
Internal flow types (minified from proto) and filter logic |
pkg/internal/ |
Flow cache (deduplication) and file-watching utilities |
proto/ |
Protobuf definitions and generated code |
fv/ |
Functional verification tests (vanilla go test, not Ginkgo) |
Felix (per-node) --gRPC--> FlowCollector --> Goldmane main loop --> BucketRing
| |
| +--> Flows/Statistics gRPC queries
| +--> Stream subscriptions
|
+--> (on rollover) --> Emitter --> upstream HTTP endpoint
BucketRing— ring buffer ofAggregationBuckets. Each bucket covers a fixed time interval (default 15 s). On rollover, the oldest bucket is recycled. Keeps ~1 hour of history (242 buckets).DiachronicFlow— tracks a single flow key's statistics across all time buckets.- Rollover — every
AggregationWindow(15 s), the main loop advances the ring. On rollover, old buckets are emitted to the sink (if configured) and streams receive updates. - Sink — optional downstream consumer of aggregated flows (the
emitter). Can be enabled/disabled at runtime via a file watch
(
FileConfigPath). - Emitter — batches aggregated flows and pushes them to an
upstream endpoint over HTTPS with mTLS. Tracks progress in a
ConfigMap(flow-emitter-stateincalico-system).
- A change to any of the five concepts above — bucket layout, rollover cadence, emit semantics, sink reload protocol — is a protocol-level change. Callers (Felix's flow reporter, Whisker, the emitter's upstream consumer) will notice. Update this document and bump proto compatibility if the wire format changes.
- The main loop serialises all operations. Adding a new operation
that must not block the loop (e.g. a long-running query) needs
an explicit design — do not just
goit. - A change to
BucketRing's sizing orAggregationWindowdefault affects memory footprint; benchmark before changing.
All config via environment variables (see pkg/daemon/daemon.go
Config struct). Adding a new env var is a design change: it
extends the daemon's external contract.
| Env var | Default | Description |
|---|---|---|
LOG_LEVEL |
info |
Log level |
PORT |
443 |
gRPC listen port |
PUSH_URL |
(empty) | HTTP endpoint for flow emission |
AGGREGATION_WINDOW |
15s |
Bucket duration |
EMIT_AFTER_SECONDS |
30 |
Delay before emitting (completeness vs latency) |
EMITTER_AGGREGATION_WINDOW |
5m |
Time window aggregated per emission |
SERVER_CERT_PATH / SERVER_KEY_PATH |
(empty) | Server TLS for gRPC |
CLIENT_CERT_PATH / CLIENT_KEY_PATH / CA_CERT_PATH |
(empty) | Client mTLS for upstream HTTP endpoint |
HEALTH_PORT |
8080 |
Health check port |
PROFILE_PORT |
0 (disabled) |
pprof port |
PROMETHEUS_PORT |
0 (disabled) |
Prometheus metrics port |
- A new env var needs a default that preserves existing behaviour (opt-in or no-op by default).
- Changing a default for an existing var is an observable behaviour change — treat it as a semver-minor at least.
- TLS-related vars (
*_CERT_PATH/*_KEY_PATH) interact with the operator's secret mounts; coordinate with the operator CR when changing defaults or adding new cert inputs.
Goldmane's observable surface. Adding/renaming/removing a metric is a contract change for dashboards and alerting; record it here.
Aggregator metrics (goldmane_aggr_*):
goldmane_aggr_received_flows_total— total flows ingested into the aggregator.goldmane_aggr_dropped_flows_total— flows dropped due to full buffer.goldmane_aggr_num_unique_flows— current number of unique flow keys.goldmane_aggr_flow_index_buffer_size— current ingestion buffer depth.goldmane_aggr_flow_index_batch_size— number of flows processed per batch.goldmane_aggr_flow_index_latency_ms— time to index a single flow.goldmane_aggr_rollover_duration_ms— time spent performing bucket rollover.goldmane_aggr_rollover_latency_ms— time between rollovers (should be ~15 s).goldmane_aggr_backfill_latency_ms— time to backfill a new stream with historical data.
Collector metrics (goldmane_collector_*):
goldmane_collector_received_flows(label:source) — flows received per Felix node.goldmane_collector_flow_process_latency(label:source) — ingestion latency histogram per node.goldmane_collector_num_clients— number of connected Felix clients (should match node count).
Stream metrics:
goldmane_num_streams— number of active gRPC stream subscriptions.
- A new metric needs a name in the documented namespace
(
goldmane_*,goldmane_aggr_*, orgoldmane_collector_*) and an entry in this table. - Dropping a metric is a dashboard-breaking change — record the reason and migration path in the removal commit.
- Label cardinality matters: per-node labels (
source) are fine up to cluster size; per-flow-key labels would be unbounded and are forbidden.
- Keep this document in sync with the code. A change to the gRPC services, core components, key concepts, config surface, or Prometheus metrics must update the relevant section in the same PR. Exemptions: (a) a bug fix that restores behaviour this doc already describes, (b) a mechanical refactor with no observable change, (c) comment / log-message edits, (d) dependency bumps. If in doubt, update the doc.
- Operational recipes (build, test, debug) do not belong here —
they live in
goldmane/CLAUDE.md.