Introduce a multi-stage Alpine Dockerfile that cross-compiles via buildx ($BUILDPLATFORM -> $TARGETARCH) so a single invocation produces both linux/amd64 and linux/arm64 images without a qemu-emulated builder. `make docker` loads the native-arch image locally for smoke tests; `make docker-push` publishes a multi-arch manifest. Ship a docker-compose.yaml with opt-in profiles for maglevd/frontend and a .env.example template so operators can mirror /etc/default/vpp-maglev muscle memory into containers.
157 lines
6.4 KiB
Markdown
157 lines
6.4 KiB
Markdown
# vpp-maglev
|
|
|
|
Health checker, gRPC control plane, CLI, and web dashboard for the VPP
|
|
`lb` (load-balancer) plugin. Runs as a set of three binaries under one
|
|
Debian package, plus an out-of-band tester built alongside:
|
|
|
|
- **`maglevd`** — the long-running health-checker daemon. Probes backends
|
|
(HTTP, TCP, ICMP), tracks their aggregate state, programs the VPP
|
|
dataplane via the `lb` plugin binary API, and exposes everything
|
|
over a gRPC API + Prometheus `/metrics` endpoint.
|
|
- **`maglevc`** — the interactive CLI client. Tab-completing shell with
|
|
inline help; also runs one-shot commands for scripting.
|
|
- **`maglevd-frontend`** — optional web dashboard. One binary with a
|
|
SolidJS Single-Page-App; connects to one or more maglevds over gRPC and
|
|
serves a live HTTP view (read-only `/view/` and optional basic-auth
|
|
`/admin/` with mutating commands).
|
|
- **`maglevt`** — optional out-of-band VIP probe TUI. Reads a
|
|
`maglev.yaml` and hits each frontend on a live HTTP path, reporting
|
|
latency and a configurable response-header tally so operators can see
|
|
failover as it happens. Does not talk gRPC; useful for validating a
|
|
`maglevd` restart end-to-end from a client perspective. Built by
|
|
`make` but not installed by the Debian package.
|
|
|
|
## Build and install
|
|
|
|
```sh
|
|
make install-deps # installs all build-time dependencies
|
|
make # builds build/<arch>/ binaries
|
|
make test # runs all tests
|
|
make pkg-deb # creates a Debian package for amd64 and arm64
|
|
```
|
|
|
|
Requires Go 1.25+ and (for `make proto`) `protoc` with `protoc-gen-go`
|
|
and `protoc-gen-go-grpc`. The SolidJS bundle under
|
|
`cmd/frontend/web/` is built automatically via `make` through the
|
|
`maglevd-frontend-web` target, which needs `npm`.
|
|
|
|
Produces `vpp-maglev_<version>_amd64.deb` and
|
|
`vpp-maglev_<version>_arm64.deb` in the `build/` directory by
|
|
cross-compiling with `GOOS=linux GOARCH=<arch>`. Requires `dpkg-deb`
|
|
(available on any Debian/Ubuntu host). The installed binaries report
|
|
the exact git commit via `maglevd --version` (and similarly for
|
|
`maglevc` / `maglevd-frontend`).
|
|
|
|
## Running
|
|
|
|
After installing, `maglevd` is enabled automatically but
|
|
`maglevd-frontend` is **not** — it's opt-in, so the web dashboard
|
|
doesn't surprise anyone who just wanted the daemon:
|
|
|
|
```sh
|
|
# edit /etc/vpp-maglev/maglev.yaml, then:
|
|
systemctl enable --now vpp-maglev
|
|
|
|
# optional: web dashboard. Edit /etc/default/vpp-maglev to set
|
|
# MAGLEV_FRONTEND_ARGS and (optionally) MAGLEV_FRONTEND_USER /
|
|
# MAGLEV_FRONTEND_PASSWORD for /admin/ access, then:
|
|
systemctl enable --now vpp-maglev-frontend
|
|
```
|
|
|
|
Or run the components by hand:
|
|
|
|
```sh
|
|
maglevd --config /etc/vpp-maglev/maglev.yaml --grpc-addr :9090
|
|
maglevd --version # print version and exit
|
|
|
|
maglevc --server localhost:9090 # interactive shell
|
|
maglevc show frontends # one-shot
|
|
maglevc -color=false show backends # one-shot, no ANSI color
|
|
maglevc set backend nginx0-ams pause
|
|
|
|
maglevd-frontend -server localhost:9090 -listen :8080
|
|
```
|
|
|
|
Send `SIGHUP` to `maglevd` to reload config without restarting.
|
|
`maglevd` requires:
|
|
|
|
- `CAP_NET_RAW` for ICMP health checks (raw sockets).
|
|
- `CAP_SYS_ADMIN` when `healthchecker.netns` is set so probes can
|
|
`setns(CLONE_NEWNET)` into the dataplane namespace. Without it,
|
|
every probe errors out with `enter netns "<name>": operation not
|
|
permitted`.
|
|
|
|
The Debian systemd unit grants both via `AmbientCapabilities` /
|
|
`CapabilityBoundingSet`, so `systemctl start vpp-maglev` works out
|
|
of the box. When running by hand under a non-root user, grant them
|
|
via `setcap cap_net_raw,cap_sys_admin=eip /usr/sbin/maglevd` or
|
|
equivalent.
|
|
|
|
`maglevd-frontend` also ignores `SIGHUP` so a controlling-terminal
|
|
disconnect (e.g. closing the SSH session it was started from)
|
|
doesn't kill the daemon; `SIGTERM` / `SIGINT` remain the clean
|
|
shutdown signals.
|
|
|
|
Every flag on every binary also has an environment-variable
|
|
equivalent (e.g. `MAGLEV_CONFIG`, `MAGLEV_GRPC_ADDR`, `MAGLEV_SERVER`,
|
|
`MAGLEV_SERVERS`, `MAGLEV_LISTEN`, `MAGLEV_LOG_LEVEL`) so all three
|
|
programs can be driven entirely via env in containerized
|
|
deployments.
|
|
|
|
## Documentation
|
|
|
|
- [docs/design.md](docs/design.md) — architecture, components, and
|
|
numbered functional / non-functional requirements. Start here if
|
|
you want the big picture before diving into the code.
|
|
- A minimal configuration file in
|
|
[debian/maglev.yaml](debian/maglev.yaml) shows every knob.
|
|
- [docs/user-guide.md](docs/user-guide.md) — flags, signals, and
|
|
`maglevc` command reference.
|
|
- [docs/config-guide.md](docs/config-guide.md) — full YAML reference.
|
|
- [docs/healthchecks.md](docs/healthchecks.md) — health state
|
|
machine, probe scheduling, rise/fall semantics.
|
|
- Manpages: `maglevd(8)`, `maglevc(1)`, `maglevd-frontend(8)`.
|
|
|
|
## Docker
|
|
|
|
A single multi-stage Alpine `Dockerfile` produces two images, driven
|
|
from `docker-compose.yaml` at the repo root:
|
|
|
|
- `git.ipng.ch/ipng/vpp-maglevd:latest` — the health-checker daemon.
|
|
- `git.ipng.ch/ipng/vpp-maglevd-frontend:latest` — the read-only web
|
|
dashboard.
|
|
|
|
Both services are **opt-in** via Docker Compose profiles, so the same
|
|
stack file works for operators who want the daemon only, the frontend
|
|
only (IPng's own deployment), or both on one host. Copy the example
|
|
env file, choose which services to run, and start the stack:
|
|
|
|
```sh
|
|
cp .env.example .env
|
|
$EDITOR .env # set COMPOSE_PROFILES and any overrides
|
|
docker compose up -d # starts whichever profiles are active
|
|
```
|
|
|
|
Valid `COMPOSE_PROFILES` values are `maglevd`, `frontend`, or both
|
|
comma-separated. Leaving it empty starts nothing. The daemon
|
|
container runs with all capabilities granted (`cap_add: ALL`) so ICMP
|
|
probes and `netns`-scoped probes both work without re-plumbing the
|
|
container; the frontend runs with no extra privileges. The `MAGLEV_*`
|
|
variables in `.env.example` mirror `/etc/default/vpp-maglev` on a
|
|
Debian install, so muscle memory carries over between the two
|
|
deployment modes.
|
|
|
|
Build or push the images:
|
|
|
|
```sh
|
|
make docker # buildx --load, native arch only (local smoke test)
|
|
make docker-push # buildx --push linux/amd64,linux/arm64 multi-arch manifest
|
|
```
|
|
|
|
`make docker` loads a single-arch image into the local daemon so you
|
|
can run it immediately; `make docker-push` produces a true multi-arch
|
|
manifest and pushes it to `git.ipng.ch/ipng/...`. Both use `docker
|
|
buildx`, and the Dockerfile cross-compiles from the host's
|
|
`$BUILDPLATFORM` to each `$TARGETARCH` via `make build-<arch>`, so no
|
|
qemu-emulated builder is involved.
|