test: add production compose smoke harness
This commit is contained in:
@@ -4,16 +4,19 @@ This directory is intentionally separate from the development/toolchain Compose
|
||||
files. It starts only the Linux server and nginx TLS terminator; Windows clients
|
||||
connect through nginx at `/v1/agent`.
|
||||
|
||||
Before the first start, create `server.toml` from the authoritative example:
|
||||
Before the first start, create `server.toml` from the Compose-specific example:
|
||||
|
||||
```sh
|
||||
cp ../../docs/examples/server.toml server.toml
|
||||
chmod 0640 server.toml
|
||||
cp server.toml.example server.toml
|
||||
chmod 0644 server.toml
|
||||
```
|
||||
|
||||
Set `RVBOX_SERVER_IMAGE` to an immutable image reference, plus absolute paths
|
||||
for `RVBOX_TLS_CERT` and `RVBOX_TLS_KEY`. The TLS key must be readable by Docker
|
||||
but should remain inaccessible to ordinary host users. Validate before start:
|
||||
but should remain inaccessible to ordinary host users. `server.toml` can be
|
||||
kept outside this directory by setting `RVBOX_SERVER_CONFIG` to its absolute
|
||||
path; this is useful for a controlled smoke run without changing deployment
|
||||
files. Validate before start:
|
||||
|
||||
```sh
|
||||
docker compose -f compose.yaml config
|
||||
@@ -25,3 +28,24 @@ ownership required by the non-root server. `server-data` is the sole persistent
|
||||
data volume and must be backed up as a whole while the server is stopped;
|
||||
`server-run` contains only the ephemeral local control socket. Do not publish,
|
||||
proxy, or enable JSON-RPC except for intentional loopback debugging.
|
||||
|
||||
`server.toml` contains configuration rather than credentials and must be
|
||||
world-readable on the host (`0644`): a bind mount preserves host file ownership,
|
||||
while the server intentionally runs as the fixed unprivileged container UID
|
||||
`65532`. Keep TLS private keys outside `server.toml` and restrict the key file
|
||||
separately.
|
||||
|
||||
The provided Compose-specific example binds the private agent and observability
|
||||
listeners to `0.0.0.0` *inside the Compose network*. This is required for nginx
|
||||
to proxy them. It does not publish those ports to the host.
|
||||
|
||||
Set `RVBOX_HTTPS_BIND` when a deployment must bind a particular host interface;
|
||||
it defaults to `0.0.0.0`. The repeatable test-only smoke lane binds only
|
||||
loopback, uses material beneath `.test-runs`, and can be run after building a
|
||||
local runtime image:
|
||||
|
||||
```sh
|
||||
docker build -f deploy/Dockerfile.runtime -t rvbox-server:test .
|
||||
scripts/test-production-compose run --run-id production-smoke
|
||||
scripts/test-production-compose clean --run-id production-smoke --purge --yes
|
||||
```
|
||||
|
||||
@@ -10,10 +10,10 @@ services:
|
||||
image: "${RVBOX_SERVER_IMAGE:?set RVBOX_SERVER_IMAGE to a pinned rvbox-server image}"
|
||||
user: "0:0"
|
||||
entrypoint: ["/bin/sh", "-ec"]
|
||||
command: >-
|
||||
mkdir -p /var/lib/rvbox-server /run/rvbox &&
|
||||
chown 65532:65532 /var/lib/rvbox-server /run/rvbox &&
|
||||
chmod 0700 /var/lib/rvbox-server /run/rvbox
|
||||
# Compose does not turn a scalar `command` into one shell script argument.
|
||||
# Preserve this whole program as $0 for /bin/sh -c rather than passing
|
||||
# `mkdir` followed by its words as separate shell positional arguments.
|
||||
command: ["mkdir -p /var/lib/rvbox-server /run/rvbox && chown 65532:65532 /var/lib/rvbox-server /run/rvbox && chmod 0700 /var/lib/rvbox-server /run/rvbox"]
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp:mode=1777,size=8m
|
||||
@@ -34,7 +34,7 @@ services:
|
||||
- /tmp:mode=1777,size=32m
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./server.toml
|
||||
source: ${RVBOX_SERVER_CONFIG:-./server.toml}
|
||||
target: /etc/rvbox/server.toml
|
||||
read_only: true
|
||||
- type: volume
|
||||
@@ -67,7 +67,7 @@ services:
|
||||
server:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "${RVBOX_HTTPS_PORT:-443}:443"
|
||||
- "${RVBOX_HTTPS_BIND:-0.0.0.0}:${RVBOX_HTTPS_PORT:-443}:443"
|
||||
tmpfs:
|
||||
- /var/cache/nginx:uid=101,gid=101,mode=0755,size=16m
|
||||
- /var/run:uid=101,gid=101,mode=0755,size=4m
|
||||
@@ -87,7 +87,12 @@ services:
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop: ["ALL"]
|
||||
cap_add: ["NET_BIND_SERVICE"]
|
||||
# The nginx master creates worker-owned temporary directories beneath its
|
||||
# explicitly mounted tmpfs paths, then drops workers to UID/GID 101. These
|
||||
# are the exact bootstrap capabilities required for that lifecycle,
|
||||
# including Docker user-namespace-remapping hosts; it retains no network,
|
||||
# process, mount, or broad administration capability.
|
||||
cap_add: ["NET_BIND_SERVICE", "DAC_OVERRIDE", "CHOWN", "SETUID", "SETGID"]
|
||||
|
||||
volumes:
|
||||
server-data:
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# RVBox Linux-server Docker Compose configuration.
|
||||
# Copy this file to server.toml before starting the production stack.
|
||||
#
|
||||
# The server is private to the Compose network. These two listeners deliberately
|
||||
# bind all container interfaces so nginx can reach them; Compose publishes only
|
||||
# nginx's TLS port to the host.
|
||||
|
||||
[server]
|
||||
data_dir = "/var/lib/rvbox-server"
|
||||
agent_listen = "0.0.0.0:6899"
|
||||
agent_path = "/v1/agent"
|
||||
control_socket = "/run/rvbox/server.sock"
|
||||
|
||||
[json_rpc]
|
||||
# The unauthenticated compatibility adapter is intentionally disabled in the
|
||||
# production stack. Use a separately scoped loopback debugging setup if needed.
|
||||
enabled = false
|
||||
|
||||
[observability]
|
||||
# nginx exposes only /livez and /readyz, not the metrics listener itself.
|
||||
listen = "0.0.0.0:6901"
|
||||
Reference in New Issue
Block a user