feat(installer): multi-instance install with full env resolution
Все проверки выполнены успешно
CI / test (push) Successful in 1m0s
Docker / Build and publish worker image (push) Successful in 16m19s
Все проверки выполнены успешно
CI / test (push) Successful in 1m0s
Docker / Build and publish worker image (push) Successful in 16m19s
Rework `rsmon-worker install` so one host can run several isolated workers and so the installer consumes the full worker env-var set. - main.go now loads .env before dispatching management commands, so install/deploy read the same environment as the runtime. - New --name flag installs a co-located worker as rsmon-worker-<name> with its own binary (/usr/local/bin/rsmon-worker-<name>), config (/etc/rsmon-worker-<name>), data dir (/var/lib/rsmon-worker-<name>), and systemd unit. Named instances require an explicit WORKER_PORT. - Configuration is resolved flags > --env-file > process env/.env (godotenv) > defaults; the resolved set is written as a stable, systemd-safe 0600 env file. - WORKER_LOGIN/WORKER_PASSWORD default to a generated admin password (printed once) when both are unset; XOR is rejected. - The generated unit is now hardened (After=docker.service, CAP_NET_RAW, ProtectSystem=full, ReadWritePaths=data dir) and parameterized by instance; the Docker unit is namespaced by instance too. - install creates the data + config directories and prints a summary (unit, binary, env file, data dir, console URL, generated password). - New flags: --name, --host, --port, --login, --password/--password-file. - Tests: resolvePaths, validateInstanceName, resolveInstallEnv precedence/XOR/port-required, renderEnvFile, validateEnvValue, plus named-instance unit assertions. End-to-end verified by installing and removing a throwaway --name instance. - docs/install.md documents the tool, config sources/precedence, single- and multi-instance flows, the exact actions performed, the generated unit, options, and uninstall.
Этот коммит содержится в:
251
docs/install.md
Обычный файл
251
docs/install.md
Обычный файл
@@ -0,0 +1,251 @@
|
||||
# Installation
|
||||
|
||||
The `rsmon-worker install` subcommand turns a built binary (or a published
|
||||
Docker image) into a running, enabled systemd service on a Linux host. It is
|
||||
the supported way to deploy the worker: it writes the configuration, the
|
||||
systemd unit, and the data directory, then starts the service.
|
||||
|
||||
> A shell installer that downloads a pre-built binary is planned. Today
|
||||
> `install` copies the binary you invoke it from (or pulls the `--image`
|
||||
> digest), so build first with `make build` and run the resulting
|
||||
> `./bin/rsmon-worker`.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Linux with systemd.
|
||||
- Root (`install must be run as root`). The worker runs as `root` so it can
|
||||
reach the Docker socket for Compose discovery and use `CAP_NET_RAW` for ping
|
||||
checks without extra setup.
|
||||
- For the binary install: the worker binary you want to install.
|
||||
- For the Docker install (`--docker`): the `docker` CLI and an immutable
|
||||
`repository@sha256:<64 lowercase hex>` image digest.
|
||||
|
||||
Host dependencies for browser-backed HTTP checks (Debian/Ubuntu):
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates chromium libcap2-bin tzdata
|
||||
```
|
||||
|
||||
## Configuration sources
|
||||
|
||||
The installer reads the same environment variables the worker runtime reads.
|
||||
Each variable is resolved with this precedence (highest first):
|
||||
|
||||
1. **Explicit flags** (`--url`, `--token`, `--host`, `--port`, `--login`,
|
||||
`--password`, `--name`).
|
||||
2. **`--env-file`** — a strict, systemd-safe `KEY=VALUE` file (validated before
|
||||
anything is written to disk).
|
||||
3. **Process environment**, including a `.env` file in the working directory
|
||||
(loaded automatically at startup via `godotenv`).
|
||||
4. **Built-in defaults** (`RSMON_URL=https://rsmon.ru`, `WORKER_HOST=127.0.0.1`,
|
||||
`WORKER_PORT=27401` for the primary instance).
|
||||
|
||||
`.env` files are loaded before the install command runs, so
|
||||
`sudo rsmon-worker install` from a directory containing a `.env` picks up those
|
||||
values automatically. To override a value, pass the matching flag.
|
||||
|
||||
### Variables
|
||||
|
||||
| Variable | Required | Default | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| `RSMON_URL` | yes | `https://rsmon.ru` | Control-plane base URL. |
|
||||
| `RSMON_TOKEN` | yes | none | Worker bearer token. |
|
||||
| `WORKER_HOST` | no | `127.0.0.1` | Operator-console bind address. |
|
||||
| `WORKER_PORT` | no | `27401` (primary) | Operator-console port. **Required** for named instances. |
|
||||
| `WORKER_URL` | no | none | Public URL advertised to the control plane. |
|
||||
| `WORKER_LOGIN` | no | `admin` (generated) | Operator-console basic-auth login. |
|
||||
| `WORKER_PASSWORD` | no | generated | Operator-console basic-auth password. |
|
||||
| `WORKER_COMPOSE_ENABLED` | no | feature default (on) | Enable Docker Compose discovery/management. |
|
||||
| `WORKER_CLUSTER_*` | no | none | Optional Raft cluster (`ID`, `PORT`, `PEERS`, `DATA_DIR`, `ENABLED`). |
|
||||
| `WORKER_RELEASE_URL` | no | none | Self-update release feed URL. |
|
||||
|
||||
`WORKER_LOGIN` and `WORKER_PASSWORD` must both be set or both be left empty. If
|
||||
both are empty, the installer generates a random password (login `admin`),
|
||||
writes it to the env file, and prints it once. Record it; the operator console
|
||||
requires it for both the browser login and the `/web/api/*` HTTP basic-auth
|
||||
endpoints.
|
||||
|
||||
Values must be systemd-safe: no whitespace, quotes, backslashes, or `$`
|
||||
interpolation inside a value. This keeps the file unambiguous across systemd
|
||||
`EnvironmentFile` and `docker --env-file`.
|
||||
|
||||
## Single-instance install (one worker per host)
|
||||
|
||||
The classic install uses the canonical paths and the default port 27401.
|
||||
|
||||
```bash
|
||||
make build
|
||||
printf '%s\n' 'YOUR_WORKER_TOKEN' > worker-token
|
||||
chmod 600 worker-token
|
||||
sudo ./bin/rsmon-worker install \
|
||||
--token-file worker-token \
|
||||
--port 27401 \
|
||||
--password 'choose-a-console-password'
|
||||
rm worker-token
|
||||
```
|
||||
|
||||
If you keep configuration in a `.env` (recommended for repeatability):
|
||||
|
||||
```bash
|
||||
# .env
|
||||
RSMON_URL=https://rsmon.ru
|
||||
RSMON_TOKEN=...
|
||||
WORKER_PORT=27401
|
||||
WORKER_LOGIN=admin
|
||||
WORKER_PASSWORD=...
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo ./bin/rsmon-worker install
|
||||
```
|
||||
|
||||
Installed layout:
|
||||
|
||||
| Path | Contents |
|
||||
| --- | --- |
|
||||
| `/usr/local/bin/rsmon-worker` | Worker binary. |
|
||||
| `/etc/rsmon-worker/worker.env` | Configuration, mode `0600`. |
|
||||
| `/var/lib/rsmon-worker/` | Data directory (SQLite, webapp state). |
|
||||
| `/etc/systemd/system/rsmon-worker.service` | systemd unit. |
|
||||
|
||||
## Multi-instance install (several workers per host)
|
||||
|
||||
`--name` installs a co-located worker under `rsmon-worker-<name>` with its own
|
||||
binary, config, data, systemd unit, and port. This is how you run a staging
|
||||
build next to production, or isolate tenants on one host.
|
||||
|
||||
```bash
|
||||
sudo ./bin/rsmon-worker install --name edge --port 27403 --password '...'
|
||||
```
|
||||
|
||||
A named instance must have an explicit `WORKER_PORT` (the default 27401 belongs
|
||||
to the primary). The name must be 1–32 chars, lowercase alphanumeric and
|
||||
hyphens, starting and ending alphanumeric.
|
||||
|
||||
Named layout (for `--name edge`):
|
||||
|
||||
| Path | Contents |
|
||||
| --- | --- |
|
||||
| `/usr/local/bin/rsmon-worker-edge` | Binary. |
|
||||
| `/etc/rsmon-worker-edge/worker.env` | Configuration, mode `0600`. |
|
||||
| `/var/lib/rsmon-worker-edge/` | Data directory. |
|
||||
| `/etc/systemd/system/rsmon-worker-edge.service` | systemd unit. |
|
||||
|
||||
Each instance is an independent service (`rsmon-worker.service`,
|
||||
`rsmon-worker-edge.service`, …) and can be managed separately.
|
||||
|
||||
## What the installer does
|
||||
|
||||
For a binary install, `rsmon-worker install` performs these actions in order:
|
||||
|
||||
1. **Validates** the instance name, the `--env-file` (if any), and the resolved
|
||||
`RSMON_URL`/`RSMON_TOKEN`. Nothing on the host changes before validation
|
||||
passes.
|
||||
2. **Resolves** every supported variable with the precedence above and, when
|
||||
`WORKER_LOGIN`/`WORKER_PASSWORD` are both unset, generates a random console
|
||||
password.
|
||||
3. **Copies the binary** from the running executable (or `--binary`) to
|
||||
`/usr/local/bin/rsmon-worker[-<name>]` with an atomic rename.
|
||||
4. **Creates** the data directory (`/var/lib/rsmon-worker[-<name>]/webapp`) and
|
||||
the config directory (`/etc/rsmon-worker[-<name>]`, mode `0750`).
|
||||
5. **Writes the env file** to `<config dir>/worker.env` (mode `0600`), in a
|
||||
stable canonical order.
|
||||
6. **Writes the systemd unit** to
|
||||
`/etc/systemd/system/rsmon-worker[-<name>].service`.
|
||||
7. Runs `systemctl daemon-reload`, `systemctl enable`, and, unless `--no-start`,
|
||||
`systemctl restart` followed by `systemctl is-active --quiet` to confirm the
|
||||
service came up.
|
||||
8. **Prints a summary**: unit name, binary, env file, data dir, console URL,
|
||||
status, and the generated password if one was created.
|
||||
|
||||
### The generated systemd unit
|
||||
|
||||
The unit is a hardened `Type=simple` root service ordered after
|
||||
`network-online.target` and `docker.service`:
|
||||
|
||||
- `ExecStart=/usr/local/bin/rsmon-worker[-<name>]`
|
||||
- `EnvironmentFile=/etc/rsmon-worker[-<name>]/worker.env`
|
||||
- `Environment=HOME=/var/lib/rsmon-worker[-<name>]`
|
||||
- `Environment=RSMON_WEBAPP_DATA_DIR=/var/lib/rsmon-worker[-<name>]/webapp`
|
||||
- `AmbientCapabilities=CAP_NET_RAW` / `CapabilityBoundingSet=CAP_NET_RAW` for
|
||||
ICMP checks.
|
||||
- `PrivateTmp`, `ProtectHome`, `ProtectSystem=full`, and
|
||||
`ReadWritePaths=<data dir>` to constrain writes.
|
||||
- `Restart=always`, `RestartSec=5s`.
|
||||
|
||||
## Docker install
|
||||
|
||||
Installs a systemd unit that runs the published image instead of a local
|
||||
binary. Requires an immutable digest; mutable tags are rejected.
|
||||
|
||||
```bash
|
||||
sudo ./bin/rsmon-worker install --docker \
|
||||
--image 'reg.rsxx.ru/rsmon/rsmon-worker@sha256:<64-hex-digest>' \
|
||||
--token-file worker-token
|
||||
```
|
||||
|
||||
`--name` works with `--docker` too; the container and volume are namespaced by
|
||||
instance (`rsmon-worker-edge`, `rsmon-worker-data-edge`). The container always
|
||||
mounts its data volume at the in-image `/var/lib/rsmon-worker`.
|
||||
|
||||
## Options reference
|
||||
|
||||
```
|
||||
rsmon-worker install [--token TOKEN|--token-file FILE|--env-file FILE]
|
||||
[--name NAME] [--port PORT] [options]
|
||||
```
|
||||
|
||||
| Flag | Purpose |
|
||||
| --- | --- |
|
||||
| `--token`, `--api-key` | Worker API token (`RSMON_TOKEN`). |
|
||||
| `--token-file` | File containing the worker token (avoids shell history). |
|
||||
| `--env-file` | Strict worker env file; validated then used as the config source. |
|
||||
| `--url` | Control-plane URL (`RSMON_URL`). |
|
||||
| `--host` | Console bind address (`WORKER_HOST`). |
|
||||
| `--port` | Console port (`WORKER_PORT`; required with `--name`). |
|
||||
| `--login` | Console login (`WORKER_LOGIN`). |
|
||||
| `--password`, `--password-file` | Console password, or a file containing it. |
|
||||
| `--name` | Instance name for a co-located worker. |
|
||||
| `--binary` | Binary to install (default: this executable). |
|
||||
| `--docker` | Install the prebuilt Docker image (requires `--image`). |
|
||||
| `--image` | Immutable `repository@sha256:<64 hex>` digest. |
|
||||
| `--no-start` | Enable without starting. |
|
||||
|
||||
`--token`/`--token-file` and `--password`/`--password-file` are mutually
|
||||
exclusive within each pair; combining a direct secret with its file form is an
|
||||
error.
|
||||
|
||||
## Post-install operations
|
||||
|
||||
```bash
|
||||
systemctl status rsmon-worker[-<name>]
|
||||
journalctl -u rsmon-worker[-<name>] -f
|
||||
sudo systemctl restart rsmon-worker[-<name>]
|
||||
```
|
||||
|
||||
The public liveness endpoint is `GET /healthz`; probe it with
|
||||
`rsmon-worker liveness`. The operator console is at `http://127.0.0.1:<port>`
|
||||
(loopback by default) and exposes the JSON API under `/web/api/*` using HTTP
|
||||
basic auth.
|
||||
|
||||
### Uninstall
|
||||
|
||||
There is no `uninstall` subcommand yet. To remove an instance manually:
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now rsmon-worker-<name>
|
||||
sudo rm /etc/systemd/system/rsmon-worker-<name>.service
|
||||
sudo rm -rf /etc/rsmon-worker-<name> /var/lib/rsmon-worker-<name> /usr/local/bin/rsmon-worker-<name>
|
||||
sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
## Security notes
|
||||
|
||||
- Keep `/etc/rsmon-worker[-<name>]/worker.env` mode `0600`; the installer writes
|
||||
it that way.
|
||||
- Prefer `--token-file`/`--password-file` or a `.env` over passing secrets as
|
||||
flags, which can leak through shell history and process inspection.
|
||||
- Bind the console to loopback (`WORKER_HOST=127.0.0.1`, the default) or front
|
||||
it with an authenticated TLS reverse proxy.
|
||||
- Each worker should use its own control-plane token.
|
||||
Ссылка в новой задаче
Block a user