docs(release): organize installation and operator guides by task
This commit is contained in:
+119
-92
@@ -1,107 +1,134 @@
|
||||
# Single-node delivery contract
|
||||
# Single-node delivery
|
||||
|
||||
`contract.v1.json` describes the first pre-release installation interface. It is
|
||||
separate from judging v1/v2 wire formats and never rewrites historical reports.
|
||||
The reference target is Arch/CachyOS Linux x86_64-v3, glibc 2.44, systemd and cgroup
|
||||
v2. Images and service libraries are bound to explicit file/catalog fingerprints;
|
||||
support for other distributions requires a separately verified delivery profile.
|
||||
The single-node profile packages the application, four judging runtimes and the
|
||||
installation tools for offline use. `contract.v1.json` defines the installation
|
||||
interface. Judging v1/v2 reports keep their existing formats.
|
||||
|
||||
The target has at least 4 GiB RAM and 12 GiB installation/data capacity. Judging
|
||||
and problem-import concurrency remain one each. Configured service and execution
|
||||
budgets, effective kernel limits and free capacity must also pass preflight; total
|
||||
RAM alone does not prove enough capacity or verified execution isolation.
|
||||
Preflight requires at least 12 GiB of filesystem capacity and derives required
|
||||
free bytes from the verified application, protected runtime-image copies and
|
||||
separate GNU legacy copy, plus 4 GiB of mutable-data/operation reserve. It does
|
||||
not assume that a nominal 12-GiB filesystem exposes 12 GiB free after metadata.
|
||||
Full installation and recovery acceptance is in progress. Validate a release on
|
||||
an independent test node before using it for production.
|
||||
|
||||
Release payloads are directory bundles with a bounded manifest: at most 50,000
|
||||
single-link regular files, 256 MiB per file, 4 GiB total and 8 MiB metadata. The
|
||||
manifest SHA-256 is supplied separately by the operator. Links, extra members,
|
||||
private paths and unexpected file changes are refused. Built payloads and real
|
||||
configuration never belong in Git. Validation is read-only and does not claim
|
||||
that any service has been installed, started or verified:
|
||||
## Requirements
|
||||
|
||||
| Item | Required profile |
|
||||
| --- | --- |
|
||||
| OS | Arch/CachyOS, Linux x86_64-v3, glibc 2.44, systemd 262, cgroup v2 |
|
||||
| Memory | At least 4 GiB, with enough free capacity for the configured services and tasks |
|
||||
| Storage | At least 12 GiB filesystem capacity; preflight calculates the required free space |
|
||||
| Concurrency | One judging job and one problem import |
|
||||
| Dependencies | PostgreSQL 18.6 and the fixed broker runtime, prepared from verified offline materials |
|
||||
|
||||
Other distributions need a separately verified profile. Preflight checks the
|
||||
effective kernel limits and available capacity as well as nominal RAM and disk
|
||||
size. Its free-space calculation includes the application, protected runtime
|
||||
images, the separate GNU legacy image and 4 GiB for mutable data and operations.
|
||||
|
||||
## Verify a bundle
|
||||
|
||||
Use a separately trusted checker and the manifest digest supplied with the release:
|
||||
|
||||
```sh
|
||||
python3.13 -m scripts.release contract deploy/release/contract.v1.json
|
||||
python3.13 -m scripts.release verify /path/to/bundle --manifest-sha256 SHA256_FROM_RECEIPT
|
||||
```
|
||||
|
||||
Application versions live below `/opt/kf-onlinejudge/releases`; `current` selects
|
||||
an explicitly installed version. Private operator/service configuration lives in
|
||||
`/etc/kf-onlinejudge` and `/etc/kf-judge`, mutable application data under
|
||||
`/var/lib/kf-onlinejudge`, and protected Sandbox state/images under
|
||||
`/var/lib/kf-judge`. The delegated task cgroup is separate from the Root factory's
|
||||
own supervision cgroup. Application processes do not initialize tables on start;
|
||||
Backend Alembic remains the only migration entry point.
|
||||
All application services and the separate delegated task subtree live beneath
|
||||
`kfonlinejudge.slice`: 3840 MiB memory, no swap, 384 processes/threads and two CPU
|
||||
equivalents. The remaining physical RAM is reserved for the kernel/minimal OS.
|
||||
The task subtree is `/sys/fs/cgroup/kfonlinejudge.slice/kf-judge-tasks`, a sibling
|
||||
of the Root factory supervision unit under that same total node budget. Its
|
||||
installation template does not prove the effective limits; actual service and
|
||||
task limits are read back in the independent acceptance environment.
|
||||
A bundle contains at most 50,000 single-link regular files, 256 MiB per file,
|
||||
4 GiB in total and 8 MiB of metadata. Verification rejects links, extra members,
|
||||
private paths and changed bytes. Keep bundles and real configuration outside Git.
|
||||
|
||||
Database login identities are separate for migration, API/outbox, Coordinator,
|
||||
problem import and local identity operations. Rust Worker and Root factory do not
|
||||
hold database credentials. Root factory has no MQ/platform/SSH/GitHub identity;
|
||||
privileged execution remains inside Sandbox. Public and admin browser traffic
|
||||
share the HTTPS site; execution-control interfaces remain internal.
|
||||
Verification is read-only. Installation, running services and execution isolation
|
||||
each need their own acceptance evidence.
|
||||
|
||||
Upgrade and restore must retain immutable problem versions, submitted source,
|
||||
audit and original judging reports. A consistent backup cut has a zero confirmed
|
||||
data-loss target; restoring from already prepared release/backup materials has a
|
||||
30-minute recovery target, including service health and actual four-language
|
||||
verification. These are acceptance targets, not results inferred from this file.
|
||||
Installation/service/restore evidence is required before this pre-release can be
|
||||
treated as an accepted delivery; the contract itself does not deploy production.
|
||||
## Directories and authority
|
||||
|
||||
The node input for `generate-configuration` has exactly `schema_version: 1`,
|
||||
`origin` (one HTTPS origin), `worker_id` (canonical nonzero UUID), and
|
||||
`measurement_nonce` (null or a fresh operator-generated SHA-256-sized nonce).
|
||||
It is a 0600 single-link file. Endpoint input is a separate 0600 JSON object
|
||||
with exactly `schema_version: 1`, `database` and `amqp`: database keys are
|
||||
`api`, `coordinator`, `import`, `migration`, `identity`; broker keys are `outbox`
|
||||
and `worker`. Login names and numeric loopback/socket locations are validated by
|
||||
the tool. Every endpoint requires its own operator-supplied private credential;
|
||||
there is no working example password or shared default. Import uses the reachable
|
||||
`/run/postgresql` Unix socket; all other control connections use numeric loopback.
|
||||
| Location | Contents |
|
||||
| --- | --- |
|
||||
| `/opt/kf-onlinejudge/releases` | Installed application versions |
|
||||
| `current` | Explicitly selected application version |
|
||||
| `/etc/kf-onlinejudge` and `/etc/kf-judge` | Private operator and service configuration |
|
||||
| `/var/lib/kf-onlinejudge` | Mutable application data |
|
||||
| `/var/lib/kf-judge` | Protected Sandbox state and runtime images |
|
||||
|
||||
Generated admission uses the actual verified catalogs for C17/C++20, CPython
|
||||
3.13.16 and OpenJDK 21.0.12.1+1-LTS and the unchanged public per-language budgets.
|
||||
The protected GNU legacy image is a separate directory: it retains the original
|
||||
v1 header and identical verified GNU executable/library bytes, while the three
|
||||
v2 catalog identities remain untouched. Shared Worker/task UID/GID pool and
|
||||
execution/prefetch/import slots remain one. No canonical judging report or
|
||||
historical runtime identity is converted by the installer.
|
||||
Backend Alembic is the only schema migration entry point. Database identities are
|
||||
separate for migration, API/outbox, Coordinator, problem import and local account
|
||||
operations. Rust Worker has no database identity; the Root factory has no
|
||||
database, MQ, platform, SSH or GitHub credentials. Sandbox owns privileged
|
||||
execution. Public and admin pages share the HTTPS origin; control interfaces stay
|
||||
internal.
|
||||
|
||||
Comparability defaults to unavailable (`measurement_epoch=null`). A trusted
|
||||
operator may explicitly use `--attest-measurement` only after actual node/service
|
||||
limits and the intended execution environment have been verified. The attestation
|
||||
binds a fresh nonce, worker, source, exact images, budgets, CPU/microcode, kernel
|
||||
and node scheduling snapshot. `check-configuration` refuses an old binding when
|
||||
those values change; it does not manufacture replacement metrics for old reports.
|
||||
Before any service resume after such a change, drain execution, generate/install
|
||||
a new complete private group with a new nonce and independently revalidate the
|
||||
environment. Raw configuration checks are not performance or isolation evidence.
|
||||
Configuration batches have independent hash-bound `cfg-...` identities; files
|
||||
and receipts contain both the source release and batch identifier. A fresh
|
||||
nonce/identity can therefore be installed for the same source without replacing
|
||||
an old configuration. Preparation never selects the new batch automatically.
|
||||
`activate` requires an explicit `--configuration-id`, a fully validated group,
|
||||
all application units inactive, stopped control ports and no retained task
|
||||
resources. Root journals and all old batches remain intact. It binds the code
|
||||
pointer and private batch in `/etc/kf-onlinejudge/active.json`; `check-active`
|
||||
refuses inconsistent pointers, stale hardware bindings or changed bytes.
|
||||
Interruption between the two atomic pointer writes requires operator review;
|
||||
no service starts or claims readiness during that mismatch. A stopped stale
|
||||
batch can be retired without accepting it for execution under a changed kernel.
|
||||
Application services and the task subtree share `kfonlinejudge.slice`, capped at
|
||||
3840 MiB, zero swap, 384 processes/threads and two CPU equivalents. The remaining
|
||||
physical memory is reserved for the kernel and minimal OS. Tasks use
|
||||
`/sys/fs/cgroup/kfonlinejudge.slice/kf-judge-tasks`, separate from the Root
|
||||
supervisor's cgroup. Read back service and task limits on the target node.
|
||||
|
||||
The installation entry points are available with `python3.13 -m scripts.release
|
||||
--help`. Use them in order: verify/preflight, install-files, generate-configuration,
|
||||
install-configuration, explicit DB identity provision, controlled Backend Alembic
|
||||
and account CLI operations, then activate and the separately verified bounded
|
||||
service lifecycle. These operations never contact a package index and do not
|
||||
install onto a business host on their own. OS dependencies (systemd 262, matching
|
||||
glibc ABI bytes, PostgreSQL 18.6 and the fixed broker runtime) must already be
|
||||
present from separately verified offline materials.
|
||||
## Prepare configuration
|
||||
|
||||
Supply two 0600 single-link JSON files to `generate-configuration`:
|
||||
|
||||
| Input | Fields |
|
||||
| --- | --- |
|
||||
| Node | `schema_version: 1`, `origin`, `worker_id`, `measurement_nonce` |
|
||||
| Endpoints | `schema_version: 1`, `database`, `amqp` |
|
||||
|
||||
`origin` is one HTTPS origin. `worker_id` is a canonical nonzero UUID.
|
||||
`measurement_nonce` is null or a fresh operator-generated SHA-256-sized nonce.
|
||||
The database object has `api`, `coordinator`, `import`, `migration` and `identity`
|
||||
keys; the broker object has `outbox` and `worker` keys. Supply a different private
|
||||
credential for every endpoint. Import uses `/run/postgresql`; other control
|
||||
connections use numeric loopback. The tool checks login names and locations.
|
||||
|
||||
The generated admission profile binds C17/C++20, CPython 3.13.16 and OpenJDK
|
||||
21.0.12.1+1-LTS to verified catalogs and the existing per-language budgets. The
|
||||
GNU legacy image retains its v1 header and verified executable/library bytes in
|
||||
a separate directory. Worker, task identities and execution/prefetch/import
|
||||
slots remain one. Historical reports and runtime identities remain unchanged.
|
||||
|
||||
## Select a version
|
||||
|
||||
Configuration batches have content-bound `cfg-...` identities. Preparation keeps
|
||||
earlier batches and does not select a new one. `activate` requires an explicit
|
||||
`--configuration-id`, a fully validated batch, inactive application units,
|
||||
stopped control ports and no retained task resources.
|
||||
|
||||
Selection writes the code pointer and `/etc/kf-onlinejudge/active.json`. A crash
|
||||
between those atomic writes can leave a mismatch; stop and inspect it before
|
||||
starting services. `check-active` rejects inconsistent pointers, changed bytes
|
||||
and stale hardware bindings. Root journals and earlier batches remain intact.
|
||||
A stopped stale batch can be retired without accepting it under a changed kernel.
|
||||
|
||||
## Performance comparability
|
||||
|
||||
Comparability defaults to unavailable (`measurement_epoch=null`). Use
|
||||
`--attest-measurement` after verifying the node's limits and execution environment.
|
||||
It binds a fresh nonce, worker, source, images, budgets, CPU/microcode, kernel and
|
||||
node scheduling snapshot. `check-configuration` rejects a changed binding.
|
||||
|
||||
After an environment change, drain execution, install a complete batch with a new
|
||||
nonce and revalidate before resuming. Earlier reports retain their original
|
||||
measurements. Configuration validation alone does not prove comparable performance
|
||||
or execution isolation.
|
||||
|
||||
## Installation order
|
||||
|
||||
Use `python3.13 -m scripts.release
|
||||
--help` for the command interface. Prepare the OS dependencies and dedicated data
|
||||
volumes, then follow this order:
|
||||
|
||||
1. Verify the bundle and run preflight.
|
||||
2. Install files and runtime images.
|
||||
3. Generate and install a private configuration batch.
|
||||
4. Activate that batch while services and tasks are stopped.
|
||||
5. Install the journal profile and selected dependency snapshots.
|
||||
6. Initialize PostgreSQL, provision DB identities, run Backend Alembic and create
|
||||
application accounts; stop the initialization database before installing units.
|
||||
7. Install ordinary units, the Root factory and the HTTPS snapshot/TLS material.
|
||||
8. Start the bounded service lifecycle and verify readiness and actual execution.
|
||||
|
||||
The tools use offline materials and do not contact a package index.
|
||||
|
||||
See the [operator command reference](../../scripts/release/README.md) for service,
|
||||
HTTPS, backup and recovery operations. Upgrades and restores must preserve
|
||||
immutable problem versions, submitted source, audit and original judging reports.
|
||||
A confirmed consistent backup cut has a zero data-loss target. Recovery from
|
||||
prepared release and backup materials has a 30-minute target, including health
|
||||
and four-language verification. Both targets require measured acceptance results.
|
||||
|
||||
Reference in New Issue
Block a user