NAME
Rex::Rancher::Agent - Rancher Kubernetes agent (worker node) installation
VERSION
version 0.003
SYNOPSIS
use Rex::Rancher::Agent;
# Join an RKE2 cluster as worker
install_agent(
server => 'https://10.0.0.1:9345',
token => 'K10abc123...',
);
# Join a K3s cluster as worker
install_agent(
distribution => 'k3s',
server => 'https://10.0.0.1:6443',
token => 'K10abc123...',
version => 'v1.28.4+k3s1',
node_name => 'worker-01',
);
# With a pull-through registry mirror
install_agent(
distribution => 'rke2',
server => 'https://10.0.0.1:9345',
token => 'K10abc123...',
registries => {
mirrors => { 'docker.io' => { endpoint => ['http://cache.local:5000'] } },
},
);
DESCRIPTION
Rex::Rancher::Agent installs and configures a Rancher Kubernetes worker node for either RKE2 or K3s. It handles:
Writing
config.yamlwith the server URL, token, and optional node name and node labelsWriting
registries.yamlfor private registry mirrors (optional)Running the official distribution installer via
curl | sh, or from a checksum-verified release artifact (install_method => 'artifact')Enabling and starting the agent systemd service, and waiting until it is active (journal tail in the error if it is not)
For RKE2 the installer is fetched from https://get.rke2.io with INSTALL_RKE2_TYPE=agent. For K3s the installer from https://get.k3s.io is used with the K3S_URL environment variable and INSTALL_K3S_SKIP_START: instead of the script's own blocking restart, the agent is restarted with --no-block and waited on for at most 10 minutes, so an agent that cannot reach its server dies with its journal instead of hanging the deploy (with hold_running it is only started unless something changed, as below for RKE2, or the install script rewrote its unit or env file with other content). A running rke2-agent is only started, which leaves it alone, unless its config.yaml, registries.yaml, /etc/default/rke2-agent, containerd drop-ins, NVIDIA runtime or binary changed since it started, or its containerd config is still the output of Rex::GPU 0.001's template: then it is restarted, as described under "Re-runs" and "RKE2 installation" in Rex::Rancher::Server, which also describes the version skew rules that apply to agents as to servers. That bare template (only imports and version = 2) is removed before the agent is (re)started, on RKE2 and K3s, as there; any other template stays. For both distributions the token is read from config.yaml and never passed on the installer command line, where ps would show it. config.yaml and registries.yaml are written 0600 root:root.
Registry configuration uses the same YAML structure and helper as Rex::Rancher::Server, so mirrors configured for the server are directly reusable for agents.
install_agent
Write the agent configuration, optionally write registries.yaml, run the distribution installer, enable and start the agent service, and wait until systemctl is-active reports it active (up to 10 minutes). A service that ends up failed or never gets active dies with the last 50 lines of its journal in the message, after the line "It joins the cluster via SERVER -- check that this node can reach that address": an unreachable server is the most common cause.
Dies before anything is written or installed if the host carries Cilium datapath state from an earlier cluster (the pins in /sys/fs/bpf/cilium, the /run/cilium/cgroupv2 mount or the cilium_host device) but neither RKE2 nor K3s: until a reboot, that state makes every image pull of the new agent stall. The message names what was found and asks for a reboot. With RKE2 or K3s on the host it is not checked. Same check as "install_server" in Rex::Rancher::Server's, see "check_cilium_residue" in Rex::Rancher::Uninstall. It comes after the kubeconfig check (below) and before the version skew rules, which die before anything is written or installed as well.
Required options:
server-
URL of the server to join. For RKE2:
https://SERVER_IP:9345. For K3s:https://SERVER_IP:6443. token-
Node join token. Obtain from the running server with "get_token" in Rex::Rancher::Server.
Optional options:
distribution-
rke2(default) ork3s; anything else dies before the host is touched. version-
Pinned version string, e.g.
v1.28.4+rke2r1for RKE2 orv1.28.4+k3s1for K3s. If omitted, the latest stable release is installed. When given, the installed binary's--versionis checked against it after the installer ran, and a mismatch dies before the service is started (the K3s install script runs withINSTALL_K3S_SKIP_START).The version skew rules of "install_server" in Rex::Rancher::Server's
versionapply to a running agent the same way (a jump of more than one minor or a downgrade dies before anything is installed; the next minor without a pinnedversionis installed but not restarted onto, with a warning), and to a stopped one against its installed binary. Withkubeconfig, the agent is also never brought to a newer minor than the control plane (see there). hold_running-
If true, the agent stays on the version it runs: its own running version (
/proc/PID/exe --versionofrke2-agent.service/k3s-agent.service), or when it is not running its installed binary's, is this run'sversion; with neither,versionapplies, or without it the stable channel. Aversiongiven as well loses to the held one, with a warning that names both. Read before anything is written or installed; the fallbacks, their warnings and the restart only for a changed configuration (K3s included) are those of "install_server" in Rex::Rancher::Server'shold_running. Withkubeconfigthe held version is still checked against the control plane: an agent that runs a newer minor than it dies before anything is installed. kubeconfig-
Local path to a kubeconfig of the cluster (as
rancher_deploy_server'skubeconfig_filesaves it). With it, the control plane's version is read through the API before anything is written to the host (the lowestkubeletVersionof the control-plane nodes, see "control_plane_version" in Rex::Rancher::K8s), and an agent version of a newer minor dies: a kubelet must never be newer than the API server. A newer patch of the same minor is fine. The agent version checked isversion, or the stable channel's (as forinstall_server); when that cannot be resolved, the installed binary is checked before the agent is started, and dies with it installed but not (re)started. An API that does not answer dies before the host is touched. Withoutkubeconfigthe agent cannot be checked against the control plane: upgrade the servers first and pinversion. install_method-
script(default:curl | sh, unchanged) orartifact: download the release artifact for the node's architecture on the host, verify it against the officialsha256sum-ARCH.txt(a mismatch dies), and install from it. Requiresversion. Details, including the RPM-host caveat for RKE2, in "install_server" in Rex::Rancher::Server. node_name-
Override the Kubernetes node name. If omitted, the system hostname is used.
node_labels-
Node labels applied at join time (
node-labelinconfig.yaml), as an arrayref ofkey=valuestrings. Same as "install_server" in Rex::Rancher::Server'snode_labels; like there, labels are only read when the agent registers, not on a re-run against a node that already joined. registries-
Private registry mirror configuration hashref. Same structure as "install_server" in Rex::Rancher::Server's
registriesoption. Written toregistries.yamlin the distribution config directory. nvidia_runtime_path-
If true, and
nvidia-container-runtimeis on the host'sPATH, write aPATH=line to/etc/default/rke2-agentbefore the installer runs, so rke2 finds a host-installed NVIDIA runtime at service start (a running agent is restarted when the file changed). Same behaviour as "install_server" in Rex::Rancher::Server'snvidia_runtime_path; no effect on k3s. Default:0; "rancher_deploy_agent" in Rex::Rancher turns it on forgpu => 1, gpu_setup => 0.
install_agent(
distribution => 'rke2',
server => 'https://10.0.0.1:9345',
token => 'K10abc123...',
);
preflight_agent
my $checked = Rex::Rancher::Agent::preflight_agent(%opts);
# { version => ..., install_method => 'script', server_version => ... }
Everything "install_agent" checks before it writes or installs, with the same options and in the same order, and nothing else: it only reads the host, and with kubeconfig the cluster's API. "install_agent" runs it first thing (after its check for server and token); "rancher_deploy_agent" in Rex::Rancher runs it before it prepares the node, and a caller that prepares the node on its own can do the same, so a refused host is left as it was. Not exported.
- 1. the pure option checks:
install_method(withversion),distribution; - 2. with
kubeconfig, the control plane's version through the API (from this machine, no host involved); an API that does not answer dies; - 3. Cilium datapath state an earlier cluster left on a host without RKE2 or K3s ("check_cilium_residue" in Rex::Rancher::Uninstall), the first read of the host;
- 4. with
hold_running, the agent's own version to hold ("held_version" in Rex::Rancher::Distribution); - 5. the version skew against the running agent or installed binary, and against the control plane's version from item 2 ("check_version_skew" in Rex::Rancher::Distribution), with the held version under
hold_running, elseversion.
Dies as "install_agent" would. Returns a hashref: the version this run installs (held, pinned, or undef for the stable channel), the install_method and the control plane's server_version (undef without kubeconfig).
SEE ALSO
Rex::Rancher, Rex::Rancher::Server, Rex::Rancher::Node, Rex
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/rex-rancher/issues.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <getty@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.