102 lines
3.6 KiB
Markdown
102 lines
3.6 KiB
Markdown
# Server
|
|
|
|
The authoritative server executable.
|
|
|
|
## Running
|
|
|
|
```
|
|
Usage: tw_server [--quicr-port <port>] [--cluster-port <port>]
|
|
--quicr-port UDP port for player connections (default: 8101)
|
|
--cluster-port UDP port for zone-server peering (default: 8102)
|
|
```
|
|
|
|
Metrics reporting to TimescaleDB stays off until `TIMESCALEDB_HOST` is set:
|
|
|
|
| Variable | Default |
|
|
|------------------------|----------------|
|
|
| `TIMESCALEDB_HOST` | unset (off) |
|
|
| `TIMESCALEDB_PORT` | `5432` |
|
|
| `TIMESCALEDB_DB` | `mmo` |
|
|
| `TIMESCALEDB_USER` | `mmo` |
|
|
| `TIMESCALEDB_PASSWORD` | empty |
|
|
| `TIMESCALEDB_TABLE` | `zone_metrics` |
|
|
|
|
## Building natively
|
|
|
|
See the root `README.md`. The target is `tw_server` and the binary lands in
|
|
`<build-dir>/modules/server/tw_server`.
|
|
|
|
## Building the image
|
|
|
|
`Dockerfile` has three stages: a toolchain stage holding the C++ build
|
|
environment, a build stage that compiles `tw_server` with clang, and a runtime
|
|
stage that carries only the binary and its shared libraries. The build context is
|
|
the repository root, so run it from there:
|
|
|
|
```bash
|
|
$ docker build -f modules/server/Dockerfile -t tw_server .
|
|
```
|
|
|
|
The toolchain stage installs the compiler and tools (clang, cmake, ninja, mold,
|
|
glslangValidator) and the development packages CMake looks for (Vulkan, SDL2,
|
|
protobuf, libpq, libpqxx) from apt. It touches no source, so it only rebuilds
|
|
when that package list changes.
|
|
|
|
The build stage configures a Release build on top of it with `CC=clang` /
|
|
`CXX=clang++`. glm, entt, Jolt, spdlog, expected, Catch2 and tracy are cloned
|
|
while configuring, so the build needs network access. `.dockerignore` keeps the
|
|
local build directories and those cloned sources out of the context.
|
|
|
|
## Reusing the toolchain
|
|
|
|
Layer caching already keeps apt out of a rebuild, but the cache is local and dies
|
|
with `docker builder prune`. To pin the toolchain down, build that stage on its
|
|
own and tag it:
|
|
|
|
```bash
|
|
$ docker build -f modules/server/Dockerfile --target toolchain -t tw_toolchain .
|
|
```
|
|
|
|
`TOOLCHAIN_IMAGE` then points the build stage at it, and the apt step is skipped
|
|
outright rather than cache-hit:
|
|
|
|
```bash
|
|
$ docker build -f modules/server/Dockerfile \
|
|
--build-arg TOOLCHAIN_IMAGE=tw_toolchain -t tw_server .
|
|
```
|
|
|
|
The default is the in-file `toolchain` stage, so a plain build still works
|
|
standalone. Any registry tag works too, which is the useful form on CI. To carry
|
|
it between machines by hand:
|
|
|
|
```bash
|
|
$ docker save tw_toolchain | zstd -o tw_toolchain.tar.zst
|
|
$ zstd -dc tw_toolchain.tar.zst | docker load
|
|
```
|
|
|
|
The runtime stage is `gcr.io/distroless/cc-debian13:nonroot` — glibc, libstdc++
|
|
and a `nonroot` user, no shell and no package manager. Since nothing can be
|
|
installed there, the build stage walks `ldd` over the binary and stages every
|
|
shared library it resolved into `/rootfs`, which the runtime stage copies in
|
|
whole. glibc and the loader are filtered out of that list: the binary is built
|
|
against 2.39 and the runtime image ships 2.41, which runs it, but the two must
|
|
not be mixed.
|
|
|
|
Nothing in the image can be executed except the server, so `docker exec` and
|
|
`docker run --entrypoint` are of no use for poking around. Swap the base for
|
|
`gcr.io/distroless/cc-debian13:debug-nonroot` when a busybox shell is needed.
|
|
|
|
Run it, publishing both UDP ports:
|
|
|
|
```bash
|
|
$ docker run --rm -p 8101:8101/udp -p 8102:8102/udp tw_server
|
|
```
|
|
|
|
Arguments after the image name reach the binary, and environment variables are
|
|
passed as usual:
|
|
|
|
```bash
|
|
$ docker run --rm -p 9101:9101/udp -e TIMESCALEDB_HOST=timescale \
|
|
tw_server --quicr-port 9101
|
|
```
|