Document deployment preflight workflow
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Deployment preflight tests
|
||||
|
||||
Run the deployment preflight on every new node after its qBittorrent and
|
||||
Syncthing stacks are running, but before starting the Archive Control daemon
|
||||
for normal operation or creating any routes/jobs. It is read-only: it does not
|
||||
contact the control daemon, alter Syncthing/qBittorrent state, or print secret
|
||||
contents.
|
||||
|
||||
The script is [`scripts/preflight-deployment.py`](../scripts/preflight-deployment.py).
|
||||
It deliberately takes paths and container names as arguments rather than
|
||||
assuming hostnames, compose project names, mount paths, credentials, or roles.
|
||||
It can therefore be used unchanged on cache and archive nodes.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Run it on the Docker host being checked.
|
||||
- Use Python 3.11 or newer (the script uses the standard-library `tomllib`).
|
||||
- Have Docker CLI access to the daemon.
|
||||
- Have the checkout containing the script available on that host, or copy only
|
||||
this script into the node's compose directory.
|
||||
- Bring up qBittorrent and Syncthing first. Do not start the normal Archive
|
||||
Control daemon yet.
|
||||
|
||||
The disposable client container below uses the exact `archive-client` service
|
||||
image, mounts, environment, and network specified by that node's compose file.
|
||||
Consequently its qB/Syncthing API probes validate the same runtime environment
|
||||
the daemon will use, not the host shell's network namespace.
|
||||
|
||||
## New-node procedure
|
||||
|
||||
The example uses generic names. Replace paths, compose project directories,
|
||||
service names, and real container names for the node being deployed.
|
||||
|
||||
```sh
|
||||
# 1. Bring up only the local dependencies.
|
||||
cd /srv/compose/syncthing-node && docker compose up -d
|
||||
cd /srv/compose/qbittorrent-node && docker compose up -d
|
||||
|
||||
# 2. Create a temporary client from the exact production image/config, without
|
||||
# running the daemon or registering it with control.
|
||||
cd /srv/compose/ArchiveControl-archive
|
||||
docker compose run -d --no-deps --name archive-control-preflight \
|
||||
--entrypoint sleep archive-client infinity
|
||||
|
||||
# 3. Discover the real dependency container names if needed.
|
||||
docker ps --format '{{.Names}}'
|
||||
|
||||
# 4. Run the read-only checks.
|
||||
python3 /path/to/archive-clients/scripts/preflight-deployment.py \
|
||||
--client-config /srv/compose/ArchiveControl-archive/client.toml \
|
||||
--client-container archive-control-preflight \
|
||||
--syncthing-container syncthing-node-syncthing-1 \
|
||||
--qbittorrent-container qbittorrent-node-qbittorrent-1
|
||||
|
||||
# 5. Remove the temporary container, then start the real daemon only after a
|
||||
# successful result.
|
||||
docker rm -f archive-control-preflight
|
||||
docker compose up -d archive-client
|
||||
```
|
||||
|
||||
If the real client configuration is mounted somewhere other than the standard
|
||||
`/etc/archive-control/client.toml`, pass that in-container location explicitly:
|
||||
|
||||
```sh
|
||||
python3 scripts/preflight-deployment.py ... \
|
||||
--container-config /custom/path/client.toml
|
||||
```
|
||||
|
||||
## Required arguments
|
||||
|
||||
| Argument | Meaning |
|
||||
| --- | --- |
|
||||
| `--client-config` | Host path to the exact `client.toml` that will be mounted into the daemon. |
|
||||
| `--client-container` | Running disposable or already-running client container to inspect and probe. |
|
||||
| `--syncthing-container` | Running Syncthing container for this node. |
|
||||
| `--qbittorrent-container` | Running qBittorrent container for this node. |
|
||||
| `--container-config` | Optional `client.toml` path inside the client container; defaults to `/etc/archive-control/client.toml`. |
|
||||
|
||||
## What it checks
|
||||
|
||||
- Each configured qBittorrent and Syncthing API root resolves through Docker
|
||||
mounts to the same host path as the matching client local root.
|
||||
- The client uses one bind mount for its qBittorrent and Syncthing roots, so
|
||||
hard-link staging remains possible rather than silently falling back to a
|
||||
space-consuming copy.
|
||||
- The token, qB password, and Syncthing API-key files are non-empty regular
|
||||
files with no group/world permissions.
|
||||
- The client image can read its configuration and reports usable permissions,
|
||||
sparse-file support, and filesystem capabilities for both roots.
|
||||
- qBittorrent authentication/version compatibility and Syncthing
|
||||
authentication/device identity are healthy from the client container.
|
||||
|
||||
In particular, `syncthing.api_root` must refer to the Syncthing **shared-data
|
||||
mount**, not its configuration volume. For example, if Syncthing mounts its
|
||||
config at `/var/syncthing` and data at `/var/syncthing/Sync`, use
|
||||
`api_root = "/var/syncthing/Sync"` when `local_root` maps that data directory.
|
||||
This prevents a route folder being created in the config volume while the
|
||||
client writes nonce files into the data volume.
|
||||
|
||||
## Failure handling
|
||||
|
||||
Treat a nonzero exit status as a deployment blocker. Correct the compose
|
||||
mounts, `client.toml`, secret permissions, service credentials, or service
|
||||
image/version that the message identifies, then rerun the same command. Do not
|
||||
work around a mapping failure by creating route folders manually: the route
|
||||
provisioner relies on those API/local path mappings being exact.
|
||||
Reference in New Issue
Block a user