- Go 99.3%
- Dockerfile 0.7%
Two changes bundled: 1. Float shared-ci-shared from :v1.0.7 (deleted by the morning's "keep last 3 versions" Forgejo prune) to :v1 — survives future prunes. 2. Swap the build / binaries / go-test steps from upstream docker.io/library/golang:1.25-alpine to loco/shared-go-base:v1 (built today, carries git + gcc + musl-dev + make + helm). Drops the per-step `apk add --no-cache git` in `build` (git is already in the image). hadolint/hadolint stays upstream — it's a special-purpose Dockerfile linter, not a base image. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .woodpecker | ||
| cmd | ||
| docs | ||
| internal | ||
| .ci-probe-2 | ||
| .gitignore | ||
| bao.yml | ||
| CHANGELOG.md | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| mkdocs.yml | ||
| README.md | ||
| sonar-project.properties | ||
discovery
WireGuard peer discovery server for the loop-coop mesh.
Deployment. Runs as an Incus system container on
service-machine(mesh10.92.0.18, publicdiscovery.svc.loop-coop.net:3000). Consumed by Talos KubeSpan in thetalos-hcloud-clusterplatform — nodes register via this service to establish the WireGuard mesh.
Implements the siderolabs discovery protocol (MPL-2.0): peers register encrypted blobs, discover each other, and stay current via long-lived streaming Watch RPCs. The server never decrypts peer data — it relays opaque ciphertext between nodes.
Binaries
| Binary | Purpose |
|---|---|
discovery-server |
gRPC server (:3000) + Prometheus metrics (:2122) |
wg-peer |
Per-node daemon: registers WireGuard peer, keeps wg in sync |
integration-test |
Live smoke test exercising all gRPC methods |
Quick Start
# Build
CGO_ENABLED=0 go build ./cmd/discovery-server
# Run (TLS required)
./discovery-server \
--cert server.crt \
--key server.key \
--log-dev
# With mTLS client verification
./discovery-server \
--cert server.crt \
--key server.key \
--ca ca-bundle.pem
# With OpenBao snapshot persistence
./discovery-server \
--cert server.crt \
--key server.key \
--bao-addr http://10.90.0.2:8200 \
--bao-token-file /run/bao-agent/token
# With OTLP tracing disabled
./discovery-server --cert ... --key ... --otlp-endpoint ""
Flags
| Flag | Default | Description |
|---|---|---|
--addr |
:3000 |
gRPC listen address |
--metrics-addr |
:2122 |
Prometheus metrics listen address |
--cert |
(required) | TLS certificate file (PEM) |
--key |
(required) | TLS key file (PEM) |
--ca |
— | CA bundle for mTLS client verification; empty = server-TLS only |
--bao-addr |
— | OpenBao address for snapshot persistence |
--bao-token-file |
— | File containing OpenBao token |
--otlp-endpoint |
http://10.90.0.2:4318 |
OTLP HTTP endpoint; empty = tracing disabled |
--log-level |
info |
Log level: debug, info, warn, error |
--log-dev |
false | Pretty console log format for development |
Deployment
Runs on service-machine (10.90.0.3) as a Podman container inside Incus:
Container image: git.loop-coop.net/loco/mesh-discovery:<version>
gRPC: 10.90.0.3:3000 (+ HAProxy public frontend on gateway :3000)
Metrics: 10.90.0.3:2122 (scraped by local Prometheus)
Traces: → Alloy at 10.92.0.13:4318 → cluster Tempo
Logs: → host journal → Alloy → local Loki (10.90.0.3:3110)
Documentation
- Architecture — data flow, state machine, shutdown sequence
- Operations — deployment, metrics reference, logs, smoke testing
- wg-peer — peer daemon flags, key management, reconciliation
- Development — building, testing, CI pipelines, local dev
Testing
go test ./...
go test -coverprofile=coverage.out ./...
# Fuzz (30s each)
go test -fuzz=FuzzUpdate -fuzztime=30s ./internal/state/
go test -fuzz=FuzzUpdateDelete -fuzztime=30s ./internal/state/
go test -fuzz=FuzzEndpointUpdate -fuzztime=30s ./internal/state/
go test -fuzz=FuzzWatchFanout -fuzztime=30s ./internal/state/
# Live smoke test
go run ./cmd/integration-test -endpoint=10.90.0.3:3000 -insecure
Release
Push to main → bump pipeline tags v0.x.y+1 → release pipeline builds
binaries + container and creates a Forgejo release.
License
Server code: MIT. Depends on siderolabs/discovery-api and
siderolabs/discovery-client (MPL-2.0).