Overview

From ISO to running cluster

Every Ruckos machine starts from the same ISO. Once it boots, you decide what it becomes: a hypervisor that runs VMs, or a Kubernetes node. There is no SSH and no package manager. You manage nodes through their API with one of three tools.

  • rctl — the command line. Everything can be done with it, and it scripts well.
  • Ruckos-V — the Windows desktop app for hypervisors, VMs and hypervisor clusters.
  • Lighthouse — the web console for running many Kubernetes clusters from one place.

Get access

Early access

The Ruckos ISO is not public yet. Contact us to sign up for early access and we will send you the download.

Contact us for access

System requirements

Baseline

  • UEFI-capable bare-metal host or VM.
  • A network with DHCP for first boot. Static addresses are set with rctl.
  • A disk for Ruckos. Hypervisors also need a disk or free space for VMs.
  • Active Directory DNS and AD CS for the full Ruckos Cloud platform.
  • Registry access for workload images.

Quick start

Boot, scan, pick a path

  1. Boot each machine from the Ruckos ISO. It comes up in maintenance mode and waits on the network.
  2. Find it from your workstation.
rctl scan

Virtualization

Turn hosts into hypervisors, cluster them, and create VMs.

rctl bootstrap hypervisor 192.168.1.209 --cluster lab rctl bootstrap hypervisor 192.168.1.210 --cluster lab --join 192.168.1.209 rctl vm create 192.168.1.209 --name web1 --cpus 2 --memory 4G --disk 40G --iso ./installer.iso

Ruckos-V does the same steps from a Windows desktop.

Kubernetes

Give each node a role, write the site file, and bootstrap the cluster in one command.

rctl scan --range 192.168.1.0/24 --save rctl assign 192.168.1.48 --role controlplane --cluster prod rctl assign 192.168.1.49 --role worker --cluster prod rctl write-config --site config/site.yaml --cluster prod rctl bootstrap --site config/prod/prod.yaml --type stacked rctl get-nodes --cluster prod

Add rctl bootstrap platform for the full Ruckos Cloud stack, and rctl bootstrap lighthouse to manage it from the web.

Which tool when

Common questions

Which tool should I start with?

Use rctl if you want to script it or work from any operating system. Use Ruckos-V if you run VMs and want a desktop app on Windows. Add Lighthouse once you run more than one Kubernetes cluster and want them in one place.

Can I mix them?

Yes. All three talk to the same node API, so a host you set up with rctl shows up in Ruckos-V, and the other way around. Lighthouse imports the same site file: rctl export-site --site config/site.yaml writes it as JSON, and you import that under Config in Lighthouse.

Do I need Kubernetes to run VMs?

No. A hypervisor runs VMs without Kubernetes. Kubernetes nodes can run as VMs on your hypervisors, or on bare metal.

Stacked or external etcd?

Stacked runs etcd on the control-plane nodes, so you need fewer machines: --type stacked. External runs etcd on its own nodes with --role etcd: --type external. rctl checks that the site file matches the type you pick.

How do I add a node later?

Boot it from the ISO, then rctl scan --save and rctl assign it. For Kubernetes, run rctl write-config --append and rctl bootstrap workers --site <file>. For a hypervisor cluster, run rctl bootstrap hypervisor <ip> --cluster lab --join <host-ip>.

How many hypervisors run the cluster database?

The cluster picks it for you: one host for 1–2 hosts, three for 3–4, five for 5 or more. rctl cluster status shows which hosts they are.

How do I move a VM to another host?

rctl vm move <host-ip> <name> lists the hosts that can take it. Add --to <hostname> to move it, and --live to keep it running while it moves.

How do I take a host out of a hypervisor cluster?

For a host that is running, use rctl cluster leave <host-ip>; its VMs keep running. For a host that is switched off, use rctl cluster remove <host-ip> <hostname> from any live host. In Ruckos-V, both are on the Ruckos Cluster tab in Settings.

Command reference

rctl commands

Run rctl <command> --help for full details and examples. These flags work on every command:

  • -n, --node Node IP or hostname
  • -p, --port ruckos API port (default 8443)
  • -t, --token Bearer token (or set RCTL_TOKEN env var / rctlconfig)
  • --insecure Skip TLS certificate verification (required for first maintenance-mode apply)
  • --rctlconfig Path to rctl client config (default: RCTLCONFIG, ./rctlconfig, ~/.rctl/config)
  • -o, --output Output format: text or json
Discover and configure nodes
rctl scan [--range 192.168.1.0/24]

Scan a network range for ruckos nodes

  • --force With --save: fully overwrite existing JSON files instead of only updating dhcp
  • --range CIDR range to scan, e.g. 192.168.1.0/24 (default: auto-detect from local interfaces)
  • --save Write config/<hostname>.json for each maintenance-mode node found
  • --timeout Per-host timeout in milliseconds (covers TCP connect, TLS handshake and the /healthz and /config replies; a loaded node needs well over 500 ms)
rctl get-config

Fetch the node config and save to config/<hostname>.json

  • --all Scan config/ for maintenance-mode nodes and refresh dhcp field on all of them in parallel
  • --dns Override DNS servers in saved JSON (comma-separated). Falls back to defaults.dns in rctlconfig.
  • --role Override role in saved JSON (e.g. worker, maintenance). Falls back to defaults.role in rctlconfig.
rctl assign <ip> [--role <role>] [--cluster <cluster-name>]

Assign a node's role and cluster

  • --cluster Cluster the node belongs to
  • --role Role the node is for: controlplane, worker, etcd or hypervisor
rctl set-network

Set static network configuration (IP, gateway, DNS) on a node

  • --address Static IP in CIDR notation, e.g. 192.168.1.50/24 (empty string "" clears it to use DHCP)
  • --dns DNS server(s); repeat or comma-separate, e.g. --dns 1.1.1.1,8.8.8.8
  • --gateway Default gateway, e.g. 192.168.1.1
  • --hostname Node hostname
  • --interface Network interface to configure, e.g. eth0 (empty = auto-detect)
  • --reboot Reboot the node after saving so the config is applied immediately
rctl apply-config [file]

Push a node config or bootstrap config to the node

rctl write-config

Write config/<cluster>/<cluster>.yaml from a site template and the node JSON configs

  • --append Append to existing nodes list instead of replacing it
  • --cluster Cluster name for archiving JSONs (required)
  • --site Path to the site template (required; read only, never modified)
rctl export-site

Write site.yaml as JSON for import into Lighthouse

  • --site Path to site.yaml (required)
rctl gen config <cluster-name> <https://cp-ip:6443>

Generate machine configs for a ruckos cluster

  • --ad-domain AD DNS domain for CoreDNS forwarding (e.g. corp.example.com)
  • --cluster-dns Cluster DNS service IP (must match kubelet clusterDNS)
  • --control-plane-vip Optional kube-vip VIP fronting :6443 across all control-plane nodes (bare IP, no scheme/port)
  • --control-plane-vip-interface NIC name kube-vip binds to on control-plane nodes (required if --control-plane-vip is set)
  • --cp-hostname Control plane node hostname (default: <cluster-name>-cp, or from node context)
  • --l2-iface Cilium L2 announcement interface (site networking.l2_announce_iface)
  • --lb-end Cilium LB pool end IP (site networking.lb_pool.end)
  • --lb-start Cilium LB pool start IP (site networking.lb_pool.start)
  • --node-config Path to a saved 'get-config -o yaml' file to use as node context (hostname, etc.)
  • --node-monitor-grace-period kube-controller-manager --node-monitor-grace-period override (e.g. 40s). Empty = Kubernetes default.
  • --oidc-client-id OIDC client ID for kube-apiserver
  • --oidc-issuer-url OIDC issuer URL for kube-apiserver (e.g. https://secrets.owc.cobritek.com/realms/owc)
  • --output-dir Directory to write generated files
  • --pod-cidr Pod CIDR
  • --pod-eviction-seconds kube-apiserver --default-not-ready/unreachable-toleration-seconds override. 0 = Kubernetes default (300).
  • --service-cidr Service CIDR
rctl gen coredns

Generate a CoreDNS manifest (standalone, for kubectl apply)

  • --ad-domain AD DNS domain for CoreDNS forwarding (e.g. corp.example.com)
  • --cluster-dns Cluster DNS service IP
  • --output Write to file instead of stdout
Bootstrap Kubernetes
rctl bootstrap

Bootstrap Kubernetes on ruckos nodes

  • --site Path to site.yaml (one-shot bootstrap)
  • --type etcd topology: stacked or external (one-shot bootstrap)
rctl bootstrap init

Initialize the first control-plane node of a new cluster

  • --ad-domain AD DNS domain for CoreDNS forwarding (e.g. owc.cobritek.com)
  • --cluster Cluster name (output goes to config/<cluster>/)
  • --cluster-dns Cluster DNS service IP
  • --endpoint Kubernetes API endpoint (default: https://<static-ip>:6443)
  • --etcd-endpoints External etcd endpoints (auto-detected from etcd-members.json if omitted; comma-separated https://host:port)
  • --l2-iface Cilium L2 announcement interface (site networking.l2_announce_iface)
  • --lb-end Cilium LB pool end IP (site networking.lb_pool.end)
  • --lb-start Cilium LB pool start IP (site networking.lb_pool.start)
  • --node-monitor-grace-period kube-controller-manager --node-monitor-grace-period override (e.g. 40s). Empty = Kubernetes default.
  • --oidc-client-id OIDC client ID for kube-apiserver
  • --oidc-issuer-url OIDC issuer URL for kube-apiserver (e.g. https://secrets.owc.cobritek.com/realms/owc)
  • --pod-eviction-seconds kube-apiserver --default-not-ready/unreachable-toleration-seconds override. 0 = Kubernetes default (300).
rctl bootstrap join

Join an additional control-plane node to an existing cluster

  • --cluster Cluster name (output goes to config/<cluster>/)
  • --control-plane-vip Control-plane VIP already fronting this cluster (bare IP, no scheme/port) — must match what the cluster was initialized with, so this node's kubeconfigs/cert SANs/kube-vip manifest stay consistent with its peers
  • --control-plane-vip-interface NIC name kube-vip binds to on this node (required if --control-plane-vip is set)
  • --cp1 IP of the existing control-plane node (optional — derived from admin.conf if omitted)
  • --initial-cluster Skip etcd member add and use this peer list directly (e.g. "cp1=https://IP1:2380,cp2=https://IP2:2380")
  • --l2-iface Cilium L2 announcement interface (site networking.l2_announce_iface)
  • --lb-end Cilium LB pool end IP (site networking.lb_pool.end)
  • --lb-start Cilium LB pool start IP (site networking.lb_pool.start)
  • --node-monitor-grace-period kube-controller-manager --node-monitor-grace-period override — must match what the cluster was initialized with
  • --pod-eviction-seconds kube-apiserver --default-not-ready/unreachable-toleration-seconds override — must match what the cluster was initialized with
rctl bootstrap worker

Provision a worker node end-to-end from a saved JSON config

  • --cluster Cluster name (reads worker.yaml from config/<cluster>/)
rctl bootstrap workers [dhcp-ip...]

Provision multiple worker nodes in parallel

  • --cluster Cluster name (reads worker.yaml from config/<cluster>/)
  • --concurrency Max workers to provision (reboot + image preload) at once — higher values reboot more nodes simultaneously, which increases DHCP/ARP/switch contention and the odds of a transient preload failure on some node
  • --site Read worker nodes from site.yaml instead of scanning config/*.json
rctl bootstrap controlplanes

Bootstrap all control-plane nodes from site.yaml

  • --site Path to site.yaml (required)
rctl bootstrap etcd

Bootstrap all etcd nodes from site.yaml

  • --site Path to site.yaml (required)
rctl bootstrap etcd-init

Initialize the first node of a dedicated external etcd cluster

  • --cluster Cluster name (etcd CA saved to config/<cluster>/pki/etcd/)
rctl bootstrap etcd-join

Join a node to an existing dedicated external etcd cluster

  • --cluster Cluster name
  • --etcd1 Static IP of an existing etcd node (auto-detected from etcd-members.json if omitted)
rctl bootstrap addons

Finish the imperative addons once the nodes have applied Cilium (CoreDNS, discovery, CA)

  • --ca AD CS CA for intermediate cert enrollment (e.g. "host\CA-name"). If set, runs 'cert intermediate' + applies issuer after cert-manager is ready.
  • --cluster Cluster name (resolves config/<cluster>/ for admin.conf)
  • --config-dir Directory containing admin.conf (overrides --cluster if set)
  • --github-app-id GitHub App ID for ArgoCD repo access (optional; if provided with --github-app-installation-id and --github-app-key, creates ArgoCD repo secret)
  • --github-app-installation-id GitHub App Installation ID
  • --github-app-key Path to GitHub App private key PEM file
  • --gitops-repo GitOps repo URL (required; set gitops.repo_url in site.yaml)
  • --registry-host Registry host(s) to configure containerd trust for (e.g. registry.owc.cobritek.com)
  • --root-ca-file Path to AD root CA PEM file. When provided, pushes root CA to nodes instead of intermediate — enables full chain verification for all enterprise certs.
  • --skip-node-trust Skip pushing the CA into ruckos node trust
rctl bootstrap storage

Install storage CSI drivers (local-path, NFS)

  • --cluster Cluster name (resolves config/<cluster>/ for admin.conf)
  • --config-dir Directory containing admin.conf (overrides --cluster)
  • --local-device Node-local block device to mount for local-path
  • --local-format Format --local-device before mounting if it is blank
  • --local-fstype Filesystem type for --local-device
  • --local-path Node-local host path for local-path-provisioner
  • --nfs-server NFS server IP or hostname
  • --nfs-share NFS export path from the storage server (e.g. /k8s for a Windows share named k8s)
  • --skip-local Skip local-path-provisioner
  • --skip-nfs Skip csi-driver-nfs
  • --skip-preflight Skip storage node preflight checks
rctl bootstrap platform

Install the full platform stack from site.yaml (addons → ArgoCD → app-of-apps)

  • --site Path to site.yaml (required)
  • --skip-addons Skip addons step (wait for node-applied Cilium, CoreDNS, CA)
  • --skip-app-of-apps Skip app-of-apps step
  • --skip-argocd Skip ArgoCD install step
  • --skip-storage Skip storage step
rctl bootstrap lighthouse

Deploy Lighthouse + Postgres onto a bootstrapped cluster (no platform dependency)

  • --site Path to the site file (required)
rctl bootstrap push-ca

Push the enrolled intermediate CA to all node trust stores

  • --cluster Cluster name (resolves config/<cluster>/ for admin.conf and rctlconfig)
  • --config-dir Directory containing admin.conf and rctlconfig (overrides --cluster)
  • --registry-host Registry host(s) that should use this CA for containerd pulls
  • --root-ca-file Path to AD root CA PEM file. Preferred over --secret: nodes trust the root, enabling full chain verification for all enterprise certs.
  • --secret Kubernetes secret name containing the CA cert (tls.crt key)
  • --secret-namespace Namespace of the CA secret
  • --site Path to site.yaml — if provided, also push CA to non-K8s nodes listed there (e.g. external etcd nodes)
rctl bootstrap push-cp

Low-level: push control-plane PKI and manifests to a node (use 'bootstrap init' for end-to-end provisioning)

  • --cluster-name Kubernetes cluster name
  • --hostname Control plane node hostname (auto-detected from node config if omitted)
  • --l2-iface Cilium L2 announcement interface (site networking.l2_announce_iface)
  • --lb-end Cilium LB pool end IP (site networking.lb_pool.end)
  • --lb-start Cilium LB pool start IP (site networking.lb_pool.start)
  • --out-dir Directory to save admin kubeconfig and CA certs locally
  • --pod-cidr Pod CIDR (for controller-manager)
  • --service-cidr Service CIDR
rctl bootstrap push-worker

Low-level: push worker PKI files to a node (use 'bootstrap worker' for end-to-end provisioning)

  • --cluster-name Kubernetes cluster name
  • --cp Control plane node IP address
  • --out-dir Directory containing cluster CA certs (default: <project-root>/config)
  • --pki-dir Path to cluster PKI directory (default: --out-dir/pki)
  • --worker-name Worker node hostname (auto-detected from node config if omitted)
rctl bootstrap push-files

Push a directory of pre-generated node files to a node

  • --node-dir Directory of files to push (output of 'rctl gen config', node/ subdir)
rctl bootstrap etcd-join-remove

Remove a stale etcd member left by a failed 'bootstrap etcd-join'

  • --cluster Cluster name
  • --etcd1 Static IP of an existing etcd node (auto-detected from etcd-members.json if omitted)
  • --remove Hostname of the etcd member to remove (required)
rctl bootstrap join-remove-member

Remove a stale etcd member left by a failed 'bootstrap join'

  • --cluster Cluster name
  • --cp1 IP of the existing control-plane node (required)
  • --remove Hostname of the etcd member to remove (required)
Hypervisors and VMs
rctl bootstrap hypervisor <node-ip> [--wipe] [--cluster <name> [--join <host-ip>]]

Turn a maintenance node into a hypervisor that runs VMs, or add a VM store

  • --cluster Put the hypervisor in this cluster: a new one, or with --join an existing one
  • --join IP of a host already in the --cluster cluster
  • --wipe Also erase the chosen disk or partition when it is already a VM store (asks first)
rctl vm create <host-ip> --name <name> --cpus <n> --memory <size> --disk <size> [--store <store>] [--iso <file>] [--autostart]

Create a VM and start it

  • --autostart Start the VM whenever the host boots
  • --cpus Number of virtual CPUs
  • --data-disk Add an empty data disk (sdb in the guest), e.g. 10G
  • --disk Disk size, e.g. 40G or 1T
  • --disk-type dynamic or fixed, for the OS disk and the data disk
  • --iso Install ISO on this machine to upload and attach
  • --memory Memory, e.g. 4G or 4096M
  • --name VM name (lowercase letters, digits, dashes)
  • --store VM store (disk) on the host; needed when it has more than one
rctl vm list <host-ip>

List the VMs on a hypervisor node

rctl vm start <host-ip> <name>

Start a VM

rctl vm stop <host-ip> <name> [--force]

Shut a VM down (--force turns it off immediately)

  • --force Turn the VM off immediately
rctl vm set <host-ip> <name> [--cpus <n>] [--memory <size>]

Change a stopped VM's CPUs and/or memory

  • --cpus Number of virtual CPUs
  • --memory Memory, e.g. 8G or 8192M
rctl vm move <host-ip> <name> --to <hostname> [--live]

Move a VM to another host of its Ruckos cluster

  • --live Keep the VM running while it moves (running VM only)
  • --to Hostname of the host to move the VM to
rctl vm delete <host-ip> <name> [--yes]

Delete a stopped VM and its disk

  • --yes Skip confirmation prompt
rctl vm disk add <host-ip> <name> --size <size> [--disk-type dynamic|fixed]

Add an empty data disk to a stopped VM

  • --disk-type dynamic or fixed
  • --size Data disk size, e.g. 20G
rctl vm disk remove <host-ip> <name> --disk <n> [--yes]

Remove a stopped VM's data disk and delete its contents

  • --disk Data disk number (1 = first data disk)
  • --yes Skip confirmation prompt
rctl cluster status <host-ip>

Show the hypervisor cluster a host is in: its hosts, alive or lost, and which run etcd

rctl cluster cpu <host-ip> [model]

Show or set the CPU model VMs of the hypervisor cluster start with

rctl cluster leave <host-ip>

Take the live host at <host-ip> out of its hypervisor cluster

rctl cluster remove <host-ip> <hostname>

Take a lost host out of the hypervisor cluster that the host at <host-ip> is in

rctl disk list <node-ip>

List a node's disks, partitions and free space

rctl disk delete <node-ip> <partition>

Delete a partition so its space is free again

rctl disk remove-store <node-ip> <store>

Take a VM store with no VMs out of use so its partition can be deleted or reused

Certificates
rctl cert request <secret-name>

Request a cert from AD CS and store it as a Kubernetes TLS Secret

  • --ca AD CS CA config string: "host\CA-name"
  • --dns DNS SANs for the certificate (repeatable, or comma-separated)
  • --kubeconfig Path to kubeconfig (defaults to KUBECONFIG env or ~/.kube/config)
  • --namespace Kubernetes namespace for the TLS Secret
  • --template AD CS certificate template name
rctl cert intermediate

Enroll one intermediate CA from AD CS for cert-manager's `ca` issuer

  • --ca AD CS CA config string: "host\CA-name"
  • --cn Common Name (subject) for the intermediate CA
  • --from-cer Assemble the manifest from an already-issued .cer (phase 2, after approval)
  • --issuer-name Name for the generated ca ClusterIssuer
  • --key Private key path (default: <output-dir>/pki/intermediate.key)
  • --manifest Manifest output path (default: <output-dir>/adcs-intermediate-issuer.yaml)
  • --namespace Namespace for the intermediate Secret
  • --output-dir Directory for the saved key and generated manifest
  • --secret-name Name for the intermediate tls Secret
  • --template AD CS subordinate-CA certificate template name
Clusters and node operations
rctl get-clusters

List all known clusters and their live status

rctl get-nodes

List nodes across all clusters (or a specific one)

  • --cluster Filter to a specific cluster (default: all clusters)
rctl nodes get

List cluster nodes with roles and cluster label

  • --cluster Cluster name (reads config/<cluster>/admin.conf)
rctl nodes health <ip1> <ip2> ...

Check health of multiple nodes in parallel

rctl etcd status

Show each etcd member and its health

  • --cluster Cluster name (reads config/<cluster>/)
rctl kubeconfig [dir]

Write the admin kubeconfig for the cluster

  • --from Control plane machine config to extract the kubeconfig from
rctl cluster-info

Show cluster identity information from a node

rctl health

Check node health

rctl version

Show node OS and component versions

rctl logs <service>

Tail logs for a node service (kubelet, containerd, api)

rctl dmesg

Show kernel ring buffer (dmesg) from node

rctl exec -- <command> [args...]

Execute a command on the node

rctl reboot

Gracefully reboot a node

  • --yes Skip confirmation prompt
rctl shutdown

Gracefully power off a node

  • --yes Skip confirmation prompt
rctl render

Render Kubernetes manifests from a deployment descriptor

  • --domain Platform DNS domain
  • --environment Target environment (dev|qa|prod); overrides the descriptor. Set by CI from the branch.
  • --file Path to the deployment descriptor
  • --gitops-root GitOps repo root. When set, writes to <root>/apps/<env>/<appname>/<name>/ and namespaces by appname (overrides --out).
  • --image-tag Image tag to inject; replaces the tag in the descriptor image. Set by CI from the commit SHA.
  • --namespace Target namespace (default: descriptor namespace or name)
  • --out Directory to write rendered manifests
  • --pull-registry Registry host used in rendered manifests for pod image pulls. Nodes pull via this hostname (AD DNS -> registry LoadBalancer .84).
  • --pull-secret imagePullSecret name baked into workloads