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.yaml with the server URL, token, and optional node name and node labels

  • Writing registries.yaml for 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) or k3s; anything else dies before the host is touched.

version

Pinned version string, e.g. v1.28.4+rke2r1 for RKE2 or v1.28.4+k3s1 for K3s. If omitted, the latest stable release is installed. When given, the installed binary's --version is checked against it after the installer ran, and a mismatch dies before the service is started (the K3s install script runs with INSTALL_K3S_SKIP_START).

The version skew rules of "install_server" in Rex::Rancher::Server's version apply 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 pinned version is installed but not restarted onto, with a warning), and to a stopped one against its installed binary. With kubeconfig, 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 --version of rke2-agent.service / k3s-agent.service), or when it is not running its installed binary's, is this run's version; with neither, version applies, or without it the stable channel. A version given 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's hold_running. With kubeconfig the 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's kubeconfig_file saves it). With it, the control plane's version is read through the API before anything is written to the host (the lowest kubeletVersion of 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 is version, or the stable channel's (as for install_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. Without kubeconfig the agent cannot be checked against the control plane: upgrade the servers first and pin version.

install_method

script (default: curl | sh, unchanged) or artifact: download the release artifact for the node's architecture on the host, verify it against the official sha256sum-ARCH.txt (a mismatch dies), and install from it. Requires version. 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-label in config.yaml), as an arrayref of key=value strings. Same as "install_server" in Rex::Rancher::Server's node_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 registries option. Written to registries.yaml in the distribution config directory.

nvidia_runtime_path

If true, and nvidia-container-runtime is on the host's PATH, write a PATH= line to /etc/default/rke2-agent before 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's nvidia_runtime_path; no effect on k3s. Default: 0; "rancher_deploy_agent" in Rex::Rancher turns it on for gpu => 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 (with version), 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, else version.

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.