Cloning a module
A (source) module instance can be cloned (copied) by the
cluster/clone-module action. This action creates a new module instance
(destination) that is equivalent to the source one.
For example to create a clone/copy of instance dokuwiki1 on node 1, run
api-cli run clone-module --data '{"module":"dokuwiki1","replace":false,"node":1}'
The cluster node where the destination runs can be the same of the source instance or not; generally if the services provided by the instance do not require exclusive access to a particular system resource (i.e. bind a given TCP port number) there should be no limitation on running multiple instances of the same module on the same node. In the end, this kind of limitations must be managed by the module itself.
In a nutshell, clone-module:
- Creates a new module instance for the destination using
cluster/add-module - Starts two parallel subtasks:
transfer-stateon the source instanceclone-moduleon the destination instance
- When both subtasks are succesfully completed and if a full replace
is required, the source instance is removed with
cluster/remove-module - The destination instance has the same MODULE_UUID if replace is required
Modules can implement transfer-state and clone-module to correctly
support module cloning. The core provides a partial implementation of
those actions that is explained in the following sections.
Implementation of transfer-state
The core implementation of the transfer-state action runs a Rsync client
process that transfers the contents of the module volumes and the
AGENT_STATE_DIR (state/) directory to the destination instance. The
action input is like:
{
"replace": true,
"credentials": ["dokuwiki1", "s3cr3t"],
"address": "10.5.4.3",
"port": 20021
}
Any step that runs after 05waitserver can assume the Rsync server
process is ready to receive data.
At step 50sendstate all volume contents are transferred to the
destination with a rsync client that runs in a privileged Podman
container.
This Podman container mounts all module volumes to correctly map numeric UID/GIDs.
Note also that
-
it is possible to run an additional rsync pass before
50sendstate, expecially if there is a lot of data to transfer. Look at the action journal to grasp the rsync client invocation command line -
it is possible to add a Rsync filter to select what files/dirs are transferred: just drop a
state-filter-rules.rsyncin the AGENT_STATE_DIR. Seeman 1 rsyncfor the file syntax
If the transfer is successful the Rsync client sends a “terminate” signal to the server.
The module could add service stop/start steps before and after
50sendstate. Consider the replace input boolean to decide if services
should be left stopped or not.
Implementation of clone-module
The core implementation of the clone-module step runs a Rsync server
that receives volume and state/ directory contents.
The action input could be:
{
"credentials": ["dokuwiki1", "s3cr3t"],
"environment": {
"IMAGE_URL": "ghcr.io/nethserver/dokuwiki:latest",
"MODULE_UUID": "f5d24fcd-819c-4b1d-98ad-a1b2ebcee8cf"
},
"port": 20027,
"volumes": [
"dokuwiki-data"
],
"replace": false
}
Note that the environment object (here partially redacted) is a copy of
the source instance module environment.
At step 05create_volumes the volumes input array is used to re-create
the same set of volumes of the source module, if they are not already
created by create-module.
The 05replace step replaces MODULE_UUID, if the replace flag is
true.
Finally rsyncd runs at step 10recvstate. This step blocks until the
“terminate” signal is received from the client, or the task itself is
canceled.
Additional steps implemented by the module can then adjust the module and finally start its services.