NAME

Rex::Rancher::Server - Rancher Kubernetes server (control plane) installation

VERSION

version 0.001

SYNOPSIS

use Rex::Rancher::Server;

# Install RKE2 server (default)
install_server(
  token   => 'my-cluster-secret',
  tls_san => ['lb.example.com'],
);

# Install K3s server
install_server(
  distribution => 'k3s',
  token        => 'my-cluster-secret',
  tls_san      => ['lb.example.com'],
);

# Join additional control plane node (HA setup)
install_server(
  distribution => 'rke2',
  token        => 'my-cluster-secret',
  server       => 'https://first-server:9345',
);

# Retrieve kubeconfig and join token from a running server
my $kubeconfig = get_kubeconfig('rke2');
my $token      = get_token('rke2');

# Update registry mirrors on an already-running node
update_registries(
  distribution => 'rke2',
  registries   => {
    mirrors => { 'docker.io' => { endpoint => ['http://cache:5000'] } },
  },
);

DESCRIPTION

Rex::Rancher::Server handles control plane installation for both RKE2 and K3s Kubernetes distributions. It provides a unified interface for installing, configuring, and managing server nodes.

RKE2 installation

The official install script at https://get.rke2.io is fetched and run via curl -sfL … | sh -. The service is started with --no-block to avoid systemd's 90-second activation timeout (RKE2's first start pulls many container images). The function waits only until the kubeconfig file appears at /etc/rancher/rke2/rke2.yaml; API readiness is confirmed separately by the caller using "wait_for_api" in Rex::Rancher::K8s.

K3s installation

The official install script at https://get.k3s.io is used with K3S_TOKEN and optionally K3S_URL environment variables. Traefik and ServiceLB are disabled by default to leave room for Cilium and external load balancers.

Config layout

Both distributions use /etc/rancher/<dist>/config.yaml with the same key names (token, tls-san, node-label, cni, etc.). When cilium => 1 (the default), cni: none and disable-kube-proxy: true are written so that Cilium's kube-proxy replacement is used.

Registry mirrors are written to registries.yaml in the same directory.

FUNCTIONS

install_server(%opts)

Write the cluster configuration file, optionally write registries.yaml, install the distribution, start the service, and wait until the kubeconfig file is written to disk by the server process.

Returns 1 on success. Dies if installation fails or the distribution is unknown.

Options:

distribution

rke2 (default) or k3s.

token

Shared secret used for node joining. Auto-generated (48 random base64 chars) if omitted.

server

URL of an existing server node to join. Used for multi-server HA setups (omit for the first/only server). For RKE2 the port is 9345; for K3s it is 6443.

tls_san

Additional TLS Subject Alternative Names for the API server certificate, as an arrayref or a comma-separated string. Include the load balancer address, public IP, or DNS name so that kubeconfig clients can connect.

node_labels

Node labels applied at join time, as an arrayref of key=value strings.

registries

Private registry mirror configuration. Written to registries.yaml in the distribution config directory. Structure:

{
  mirrors => {
    'docker.io' => { endpoint => ['http://registry.internal:5000'] },
  },
  configs => {
    'registry.internal:5000' => {
      auth => { username => 'user', password => 'pass' },
    },
  },
}
cilium

If true (default: 1), set cni: none and disable-kube-proxy: true in the server config, preparing the node for Cilium CNI with full kube-proxy replacement. Set to 0 to keep the distribution's default CNI (Canal for RKE2, Flannel for K3s).

install_server(
  distribution => 'rke2',
  token        => 'my-cluster-secret',
  tls_san      => ['loadbalancer.example.com'],
  node_labels  => ['role=control-plane'],
);

update_registries(%opts)

Update registries.yaml on an already-running node and restart the distribution service to pick up the new registry mirror configuration.

Use this to add or change registry mirrors after the cluster is up — for example, after deploying an in-cluster registry that you want every node to use as a pull-through cache.

Required options:

registries

Registry mirror hashref (same structure as install_server's registries option).

Optional options:

distribution

rke2 (default) or k3s. Controls which service is restarted.

update_registries(
  distribution => 'rke2',
  registries   => {
    mirrors => {
      'docker.io'         => { endpoint => ['http://registry.internal:5000'] },
      'registry.internal' => { endpoint => ['http://registry.internal:5000'] },
    },
  },
);

get_kubeconfig($distribution)

Read the kubeconfig file from the remote server and return its content as a string. The file is read directly via cat over SSH; no SFTP is used.

$distribution defaults to rke2.

Note: RKE2 and K3s both write https://127.0.0.1 as the server address. The caller is responsible for substituting the real server address before saving the kubeconfig for external use. "rancher_deploy_server" in Rex::Rancher performs this substitution automatically.

Dies if the file cannot be read.

get_token($distribution)

Read the node join token from the server and return it as a string (trailing newline stripped).

$distribution defaults to rke2.

The token is stored at:

RKE2: /var/lib/rancher/rke2/server/node-token
K3s: /var/lib/rancher/k3s/server/node-token

Dies if the file cannot be read (e.g. server not yet started).

SEE ALSO

Rex::Rancher, Rex::Rancher::Node, Rex::Rancher::Agent, Rex::Rancher::Cilium, Rex::Rancher::K8s, 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.