Build, Publish & Run
This guide walks you through every step from cloning the repository to a running broker — in all supported deployment variants.
Prerequisites
| Tool | Minimum version | Required for |
|---|---|---|
| .NET 10 SDK | 10.0 | All variants |
| Git | any | Cloning |
| Docker Desktop | any | Container variant |
| PowerShell | 7+ | Scripts (scripts/*.ps1) |
Step 1 — Clone
git clone https://github.com/Kuestenlogik/Surgewave.git
cd Surgewave
Step 2 — Build
The build compiles the full solution and produces NuGet packages under artifacts/packages/.
Using the script (recommended):
.\scripts\build.ps1
Or directly with the .NET CLI:
dotnet build Kuestenlogik.Surgewave.slnx -c Release
publish.ps1(step 4) performs its own implicit build, so you only need this step when you specifically want the.nupkgartifacts — for example to feed thesurgewave-localNuGet feed consumed by the Samples solution.
Step 3 — Test (optional)
dotnet test Kuestenlogik.Surgewave.slnx -v normal
Step 4 — Choose a deployment variant
Pick the variant that matches your use case.
Variant A — Development (dotnet run)
Fastest way to get started. No publish step required, uses the Debug/Release build output directly.
# Broker only
dotnet run --project src/Kuestenlogik.Surgewave.Broker
# Broker + Control UI
dotnet run --project src/Kuestenlogik.Surgewave.Broker
dotnet run --project src/Kuestenlogik.Surgewave.Control --urls "http://localhost:5050"
Endpoints:
| Service | URL / Address |
|---|---|
| Kafka protocol | localhost:9092 |
| gRPC | localhost:9093 |
| Control UI | http://localhost:5050 |
| Gateway HTTP | http://localhost:8082 |
Suitable for development and local testing. Restart required on code changes.
Variant B — Published Executables
Produces self-contained, trimmed, single-file binaries for the target platform. No .NET runtime needed on the target machine.
Publish:
# All services for the current platform (default: win-x64)
.\scripts\publish.ps1
# Specific platform
.\scripts\publish.ps1 -Runtime linux-x64
# Specific services only
.\scripts\publish.ps1 -Service Broker,Control
Output: artifacts/pub/<Service>/<Runtime>/
| Service | Executable |
|---|---|
| Broker | surgewave-broker / surgewave-broker.exe |
| Gateway | surgewave-gateway / surgewave-gateway.exe |
| Control UI | surgewave-control / surgewave-control.exe |
| Marketplace | surgewave-marketplace / surgewave-marketplace.exe |
| Connector | surgewave-connect / surgewave-connect.exe |
| CLI | surgewave / surgewave.exe |
Run (Windows — via script):
# Starts Broker, Gateway and Control in separate windows
.\scripts\start.ps1
# With PostgreSQL wire protocol (port 5432, for materialized-view demos)
# Only use when port 5432 is free — a local PostgreSQL server would conflict
.\scripts\start.ps1 -PostgreSql
# Stop everything
.\scripts\stop.ps1
Run (manually / Linux):
# Broker
./artifacts/pub/Broker/linux-x64/surgewave-broker
# Control UI on a custom port
./artifacts/pub/Control/linux-x64/surgewave-control --urls http://localhost:5050
# Gateway
./artifacts/pub/Gateway/linux-x64/surgewave-gateway
Run as a systemd service (Linux):
# /etc/systemd/system/surgewave-broker.service
[Unit]
Description=Surgewave Broker
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/surgewave/broker
ExecStart=/opt/surgewave/broker/surgewave-broker
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now surgewave-broker
sudo systemctl status surgewave-broker
Run as a Windows Service:
sc.exe create SurgewaveBroker `
binPath= "C:\surgewave\broker\surgewave-broker.exe" `
start= auto
sc.exe start SurgewaveBroker
Variant C — Container (Docker)
Produces OCI-compliant container images using .NET's native container support — no Dockerfile required.
Publish container images:
# Containers only (all services)
.\scripts\publish.ps1 -Mode Container
# Executables AND containers (default)
.\scripts\publish.ps1
# One service only
.\scripts\publish.ps1 -Mode Container -Service Broker
Every run produces portable .tar archives under artifacts/pub/containers/ —
one per service. These are the real deployment artifacts and can be moved to
any host that has Docker or Podman installed.
artifacts/pub/containers/
├── broker.tar
├── gateway.tar
├── control.tar
├── marketplace.tar
└── connector.tar
With Docker running during publish — each tar is additionally loaded into
the local Docker daemon right after it is produced, so you can docker run
immediately without an extra step:
docker images surgewave/
# REPOSITORY TAG IMAGE ID ...
# surgewave/surgewave-broker 0.1.0 ...
# surgewave/surgewave-gateway 0.1.0 ...
# surgewave/surgewave-control 0.1.0 ...
# ...
Loading .tar archives into Docker later (or on another host):
Use docker load -i <file> to register a tar with the local Docker daemon.
The tag is embedded in the archive, so no extra metadata is required.
# Single tar
docker load -i artifacts/pub/containers/broker.tar
# Loaded image: surgewave/surgewave-broker:0.1.0
# All tars at once (bash)
for tar in artifacts/pub/containers/*.tar; do
docker load -i "$tar"
done
# All tars at once (PowerShell)
Get-ChildItem artifacts/pub/containers/*.tar | ForEach-Object { docker load -i $_ }
# Verify what got registered
docker images surgewave/
Podman uses the same syntax with podman load -i <file>. The archives are
portable — copy them to any host (scp, USB stick, artifact registry) and
load them there with the same command.
Run with Docker:
# Broker (minimal)
docker run -d \
--name surgewave-broker \
-p 9092:9092 \
-p 9093:9093 \
-v surgewave-data:/app/data \
surgewave/surgewave-broker:0.1.0
# Control UI
docker run -d \
--name surgewave-control \
-p 5050:5050 \
surgewave/surgewave-control:0.1.0
# Gateway
docker run -d \
--name surgewave-gateway \
-p 8082:8082 \
surgewave/surgewave-gateway:0.1.0
Run the CLI in Docker (one-shot):
The CLI ships as surgewave/surgewave-cli:0.1.0 — the same image referenced by
deployments/docker/docker-compose.yml under the cli profile. Because
the CLI is not a long-running service it is excluded from docker compose up
and invoked on demand via docker compose run or plain docker run:
# From the compose directory — uses the compose network automatically
cd deployments/docker
docker compose run --rm surgewave-cli --help
docker compose run --rm surgewave-cli topics list --broker surgewave-broker:9092
docker compose run --rm surgewave-cli plugin list --broker http://surgewave-broker:9093
# Or with plain docker run — attach to the compose network manually
docker run --rm -it --network docker_surgewave-network surgewave/surgewave-cli:0.1.0 --help
docker run --rm -it --network docker_surgewave-network surgewave/surgewave-cli:0.1.0 \
topics list --broker surgewave-broker:9092
Convenient shell alias so surgewave <cmd> always hits the containerised CLI:
# bash / zsh
alias surgewave='docker compose -f deployments/docker/docker-compose.yml run --rm surgewave-cli'
# PowerShell
function surgewave { docker compose -f deployments/docker/docker-compose.yml run --rm surgewave-cli @args }
Run with Docker Compose:
# docker-compose.yml
services:
broker:
image: surgewave/surgewave-broker:0.1.0
ports:
- "9092:9092" # Kafka protocol
- "9093:9093" # gRPC
environment:
- Surgewave__Storage__DataDirectory=/app/data
- Surgewave__Storage__LogDirectory=/app/logs
- DOTNET_RUNNING_IN_CONTAINER=true
volumes:
- surgewave-data:/app/data
- surgewave-logs:/app/logs
restart: unless-stopped
control:
image: surgewave/surgewave-control:0.1.0
ports:
- "5050:5050"
restart: unless-stopped
gateway:
image: surgewave/surgewave-gateway:0.1.0
ports:
- "8082:8082"
restart: unless-stopped
volumes:
surgewave-data:
surgewave-logs:
docker compose up -d
docker compose logs -f broker
Step 5 — Verify
Once any variant is running:
# List topics (Surgewave CLI)
surgewave topics list
# Or with a Kafka client
kafka-topics.sh --bootstrap-server localhost:9092 --list
# Control UI
open http://localhost:5050
# Health endpoint
curl https://localhost:9093/health
Ports Reference
| Port | Protocol | Description |
|---|---|---|
9092 |
TCP | Kafka wire protocol |
9093 |
TCP | gRPC API |
9091 |
TCP | Native Surgewave protocol |
1883 |
TCP | MQTT |
5432 |
TCP | PostgreSQL wire protocol (opt-in) |
5050 |
HTTP | Control UI |
8082 |
HTTP | Gateway / REST proxy |
Script Reference
| Script | Purpose |
|---|---|
scripts/build.ps1 |
Compile and produce NuGet packages to artifacts/packages/ |
scripts/publish.ps1 |
Publish executables and/or container images |
scripts/start.ps1 |
Launch published Broker, Gateway and Control in separate windows |
scripts/stop.ps1 |
Stop services started by start.ps1 |
scripts/docs.ps1 |
Build DocFX docs (-Serve for local preview at http://localhost:8080) |
scripts/run-coverage.ps1 |
Tests with code coverage report |
scripts/run-integration-tests.ps1 |
Start broker, run Kafka compatibility tests, stop broker |
scripts/run-all-benchmarks.ps1 |
Run all BenchmarkDotNet benchmark suites |
Next Steps
- Configuration — all
appsettings.jsonoptions and environment variables - Plugin System — install
.swpkgplugins - Clustering — multi-broker setup
- Kubernetes Deployment — production orchestration