vCluster, vCluster Platform, and ingress-nginx are third-party products. SambaNova doesn’t maintain, endorse, or audit them. This reference architecture is provided for informational purposes and may become outdated as they change.
- CPU nodes (x86_64, no RDUs) run the SambaStack platform services (API gateway, UI, authentication, Postgres, Redis), the ingress controller, and tenant DNS.
- RDU nodes run only the model bundle pods.
Tested with: SambaStack 2.3.2, RKE2 v1.35.5 host, vCluster CLI and
vcluster-pro 0.36.4, vCluster Platform 4.12.4 (free plan), tenant Kubernetes v1.35.10, RHEL 8.10 private nodes, containerd v2.1.6 (static build), ingress-nginx chart 4.15.1.The vCluster Platform free plan is capped at 64 CPUs or 32 GPUs across the instance. Larger deployments need a paid plan. See vCluster pricing.vCluster’s standard node bundle for Kubernetes 1.35 doesn’t run on RHEL 8.10. Step 4 builds an RHEL 8 bundle that uses containerd’s static build instead. Validate the bundle on a test node before production.
Architecture
How the pieces work together:- Join.
vcluster token createissues a bootstrap token. Each node runs the join script with the RHEL 8 bundle, which installs kubelet and containerd and joins the node to the tenant API server through the NodePort. - Control traffic. Every connection starts on the node and goes out to the tenant API server. The control plane never dials the node.
- Logs and exec. A konnectivity agent on the node keeps a tunnel open to the konnectivity server in the control plane pod. The API server reaches the kubelet back through that tunnel.
- Pod network. Flannel runs on the tenant’s own pod and service CIDRs. These never touch the host’s network.
- App traffic. DNS sends the tenant’s SambaStack hostnames to the CPU nodes, where ingress-nginx in the host network terminates TLS and routes to SambaStack. SambaStack sends inference requests on to the model pods on the RDU nodes.
- Placement. Node labels keep the two kinds apart. SambaStack’s own services, Postgres, and Redis select
sambanova.ai/role=control-plane, so they run only on CPU nodes. SambaStack’s inference operator places model bundle pods bysnRduArch, so they run only on RDU nodes. - License. The control plane pod gets its private-node entitlement from vCluster Platform on the host cluster.
Prerequisites
Host cluster, set up once:- A host cluster that meets the SambaStack on-prem requirements.
- A CPU node pool labeled
control-plane=sharedfor tenant control planes. - A storage class for tenant control plane state. This reference uses
openebs-hostpath. - An ingress controller and a hostname for vCluster Platform, and egress from the host cluster to
admin.loft.sh. - A way to expose each tenant API: a
LoadBalancerservice, or a NodePort on the host nodes as in this reference.
- CPU nodes: x86_64 (Intel or AMD) servers without RDUs, for the SambaStack platform. Use at least two so the platform survives the loss of one, and size them as in the SambaStack on-prem requirements.
- RDU nodes: the tenant’s RDU servers, for model bundles only.
- Runs RHEL 8.10 and is not a member of the host cluster. A node joins one cluster only.
- cgroup v2 enabled. Kubernetes 1.35 kubelet and kubeadm refuse to run on cgroup v1, which is the RHEL 8 default.
stat -fc %T /sys/fs/cgroup/must printcgroup2fs. - No other kubelet, Docker, or containerd running.
- Outbound TCP to a host node IP on the tenant’s NodePort (API server and konnectivity).
- Access to
github.comto download the Kubernetes bundle and containerd, or both files staged on the node. - If SELinux is
Enforcing: access torpm.vcluster.com, from which the join script installs thevcluster-selinuxpolicy package.
- Unique hostnames and TLS certificates for the tenant’s SambaStack API and UI, as in the on-prem requirements. DNS for those hostnames points at the tenant’s CPU nodes, or at a VIP in front of them.
- SambaStack 2.1.1 or later, which adds the
global.nodeSelectorsetting used to pin the platform to CPU nodes.
kubectl, helm v3.19+, and the vCluster CLI.
Components
Set up a tenant
Commands run from the operator’s machine unless noted. Replacetenant1, vcluster-tenant1, <host-node-ip>, <platform-hostname>, and <node-name> with your values.
Install vCluster Platform (once per host)
Private nodes aren’t in open-source vCluster. They need vCluster Platform. The free plan includes private nodes but is capped at 64 CPUs or 32 GPUs across the instance; check the vCluster pricing page against your node sizes.The install must set Then log in to the Platform UI at
config.loftHost to a hostname that resolves from your machine, from the host nodes, and from pods.platform-values.yaml
https://<platform-hostname> as admin and activate the free plan. vcluster platform start prints the admin password; to read it later, run helm get values loft -n vcluster-platform against the host. Until the instance is activated, vcluster create fails. Log in from the CLI with the external URL, not a local port-forward, so that tenant control planes can reach vCluster Platform:--insecure is for a self-signed Platform certificate. Drop it if the hostname has a trusted certificate.Create the tenant control plane
The settings that carry the design:If the host’s CPU node pool is tainted, add matching
vcluster.yaml
controlPlane.statefulSet.scheduling.tolerations, or the control plane pod stays Pending. CoreDNS stays Pending until the first tenant CPU node is joined and labeled in step 6; that is expected.Prepare the RHEL 8.10 nodes
Do this on every CPU node and every RDU node, as root. First confirm cgroup v2; stop here if it prints Stop any existing container runtime, turn off swap, and load the kernel modules and sysctls. The files under
tmpfs:/etc keep them across reboots:Build the RHEL 8 node bundle
Build the bundle once, on any one of the RHEL 8.10 nodes, as root. It replaces the bundle’s containerd binaries with containerd’s static build of the same version:Copy
/root/kubernetes-v1.35.10-amd64-el8.tar.gz to /root on every other CPU and RDU node. The bundle version must match the tenant’s Kubernetes version (controlPlane.distro.k8s.image.tag); build a new bundle when you upgrade the tenant.Join the nodes
Join the CPU nodes first, then the RDU nodes. Each node joins the same way. From your machine, with the tenant kubeconfig, issue a join token:The command prints a The join ends with
curl ... | sh - join command. vCluster prints it with curl -k, which skips verification of the tenant API server’s certificate. Run it on each node as root, adding --node-name and --bundle-path:This node has joined the cluster. One token joins several nodes until it expires.With SELinux Enforcing, the join installs the vcluster-selinux package from rpm.vcluster.com. On nodes without access to it, install the package first and add --skip-selinux-rpm to the join command.Label the nodes
The labels decide what runs where. CPU nodes get the platform label, and RDU nodes get the RDU label that SambaStack’s inference operator selects:Never put both labels on one node. CoreDNS, which was
Pending, starts on the CPU nodes once they are labeled.Install an ingress controller in the tenant
Private nodes have no host ingress controller, so the tenant needs its own. This install runs ingress-nginx only on the CPU nodes and binds it to ports 80 and 443 of their host network, so DNS for the tenant’s SambaStack hostnames can point at the CPU node IPs.
Any ingress controller that serves the node’s ports 80 and 443 and handles standard
Ingress objects works in place of ingress-nginx.Verify
From the tenant:kubectl logs and kubectl exec work against it.
Install SambaStack in the tenant
Install SambaStack with the standard on-prem quickstart, using the tenant kubeconfig (export KUBECONFIG=tenant1.kubeconfig). SambaNova provides the registry URL, the service-account key and the chart version. Only these settings differ from a normal install.
Node selectors. The node labels from step 6 decide where each pod runs:
global.nodeSelectorsends every SambaStack service (gateway, UI, authentication, inference operator, and the rest) to the CPU nodes labeledsambanova.ai/role=control-plane.- Postgres, Redis, and OpenEBS come from bundled charts that don’t read the global setting, so each gets the same selector in its own section.
- Model bundle pods aren’t affected. SambaStack’s inference operator places them on the RDU nodes labeled
snRduArch=sn40-16.
sambastack.yaml. Requires SambaStack 2.1.1 or later. For the per-service overrides, tolerations, and the other scheduling settings, see the SambaStack Helm values file and the SambaStack v2.1.1 release notes.
sambastack.yaml (tenant additions)
openebs-hostpath class, under /scratch/openebs. With the selectors above, that path is on the CPU nodes, so give them enough disk there, or set openebs.localpv-provisioner.hostpathClass.basePath.
Ingress and DNS. Use the ingress-nginx controller from step 7, which is the tenant’s default ingress class. Point the DNS records for the SambaStack API and UI hostnames at the CPU node IPs, or a VIP in front of them, never at RDU nodes. The hostnames must also resolve from inside the tenant, and the TLS certificate must come from a trusted CA, as the quickstart requires.
After the install, check that the platform pods are on CPU nodes and the model pods on RDU nodes:
KUBECONFIG unset), nothing changes: kubectl -n vcluster-tenant1 get pods still shows only the control plane pod.
Maintain an RDU node
Because the platform runs on CPU nodes, RDU maintenance only affects the model replicas on that node. Plan at least two RDU nodes per model if it must keep serving during maintenance.Ready.
Limitations
- This reference is tested with RHEL 8.10 private nodes only. It isn’t tested with RHEL 10 nodes.
- RHEL 8.10 nodes need the RHEL 8 bundle from step 4. Rebuild it for every tenant Kubernetes upgrade, and validate it on a test node first.
- vCluster’s node-to-node VPN isn’t available on RHEL 8.10 nodes. This reference doesn’t use it.
- The join token expires. Issue a new one for each additional node.
- The tenant API sits on one NodePort of the host nodes. Use a
LoadBalancerservice or a VIP for production. - vCluster Platform must reach
admin.loft.shto validate the free plan, and the free plan’s CPU and GPU caps apply. - Tenant control plane state is on one volume. For production, back it up or run vCluster’s high-availability configuration.
Cleanup
helm uninstall loft -n vcluster-platform.

