Install onto an Existing Kubernetes Cluster
The kubernetes platform installs the same chart every platform installs, with helm,
against your current kube-context, and touches nothing on any host. Everything the k3s
platform automates on the hosts (the node contract) is
yours to implement first; this page is that checklist, then the install.
Before You Start
helmandkubectlon the machine you run from, and a reachable kube-context. The installer refuses an OpenShift cluster and a cluster whose RAN is already managed by the k3s platform.- The Requirements: a schedulable node with an NVIDIA GPU for
the CU planes and the core,
sctpon every node, a default StorageClass, and the privileged namespaces allowed. - The release's installer package, which carries the files the steps below use:
racora-installer-<tag>.tar.gzfrom the release, unpacked toinstaller/(install-racora.sh,platforms/,node-provisioning/,cores/). Take them from the release you install, not from the repository's main branch.
1. Pod Security
If your cluster enforces the baseline Pod Security level by default, exempt the
namespaces centralized-unit, distributed-unit, 5g-core and racora-system before
installing; under restricted, exempt every Racora namespace
(Ports and Privileges says which workload
needs what). The chart creates the namespaces without Pod Security labels; how you exempt
them is your cluster's policy.
2. Radio Hosts
Provision each host that drives a real radio. The provisioner is platform-independent:
curl -sfL https://get.racora.io | INSTALL_RACORA_MODE=provision-rf INSTALL_RACORA_VERSION=vX.Y.Z INSTALL_RACORA_PRO_TOKEN=<token> sh -
INSTALL_RACORA_VERSION pins the provisioner to the release you will install; without it
the scripts come from the repository's main branch. It reboots the host through its phases and writes /etc/racora/node-capabilities. Your
cluster tooling joins the host as a worker. Virtual cells (ruType: dummy) need no
provisioned host.
3. Labels
Apply the node-contract labels from each host's capabilities file, with the labeler from the installer package:
installer/platforms/kubernetes/label-node.sh <node> # reads /etc/racora/node-capabilities over ssh
installer/platforms/kubernetes/label-node.sh <node> <file> # or from a copy of the file
It sets racora.io/rf-ready, racora.io/gpu-ready and racora.io/fronthaul-ready with
--overwrite, so re-running after re-provisioning updates them. The control node must carry
racora.io/gpu-ready=true or CU-IP stays Pending.
4. SCTP on Every Node
sudo modprobe sctp
echo sctp | sudo tee /etc/modules-load.d/racora-sctp.conf
F1-C, E1 and NGAP are SCTP over ClusterIP Services; kube-proxy needs the module.
5. The Control Node and Its GPU
NVIDIA driver and container toolkit, the containerd nvidia runtime handler
(nvidia-ctk runtime configure --runtime=containerd), and the label from step 3. The
chart creates RuntimeClass/nvidia on this platform
(racora-node.nvidia.runtimeClass.create: true); set it to false if the NVIDIA GPU
Operator owns the RuntimeClass, and set racora-node.nodePlugins.nvidia.enabled to false
if the Operator already runs a device plugin, so two plugins do not advertise
nvidia.com/gpu on the node.
6. Placement and Your Values File
The kubernetes overlay clears the control-plane pin (controlPlanePin: false on the CU
planes, the core and the controllers) because control planes built by kubeadm or CAPI
are usually tainted. Pin them yourself to the control node (the three charts take tolerations
for a tainted node, and so does the NVIDIA device plugin that advertises the GPU there,
racora-node.nodePlugins.nvidia.tolerations); CU-CP, CU-UP, CU-IP and an
in-cluster core must share one node, and the controllers belong with them. Keep this, and
everything else you override (a network identity other than the default) in one values
file of your own, my-values.yaml:
racora-cu:
nodeSelector: { kubernetes.io/hostname: <gpu-node> }
tolerations: &control-plane # reused by the two anchors below; drop it, and the nvidia entry, when that node is not tainted
- { key: node-role.kubernetes.io/control-plane, operator: Exists, effect: NoSchedule }
racora-core-open5gs:
nodeSelector: { kubernetes.io/hostname: <gpu-node> }
tolerations: *control-plane
racora-controller:
nodeSelector: { kubernetes.io/hostname: <gpu-node> }
tolerations: *control-plane
racora-node:
nodePlugins:
nvidia:
tolerations: # replaces the default list, so keep its entry
- { key: nvidia.com/gpu, operator: Exists, effect: NoSchedule }
- { key: node-role.kubernetes.io/control-plane, operator: Exists, effect: NoSchedule }
# global:
# network: { plmn: "90170", tacs: [7], slices: [{ sst: 1 }] }
# core: { provider: external, amfAddr: amf.example.net } # external core: the file wins over the overlay on every run
The install and every upgrade start from the chart's defaults, so this file is passed on
every run: RACORA_HELM_EXTRA_ARGS='-f my-values.yaml' to the installer, or
-f my-values.yaml to helm. The registry is the one thing that does not belong in the
file: the installer always passes --set global.systemDefaultRegistry=$RACORA_REGISTRY,
and a --set wins over a file, so a mirror is RACORA_REGISTRY=<registry> for the
installer or --set global.systemDefaultRegistry=<registry> for helm.
7. Storage and Grafana
A default StorageClass for the Open5GS subscriber database. Grafana is a NodePort on
30300 readable by anyone (Read Logs and Traces has the login facts);
beyond a lab keep it private, in my-values.yaml:
racora-monitoring:
grafana:
service: { type: ClusterIP }
anonymousAccess: false
8. The Core's Host Units (Open5GS)
The Open5GS provider needs three host units on the node it runs on. On the k3s platform the installer renders them; here you do, from the installer package:
sudo mkdir -p /opt/racora/core-support
sudo cp installer/cores/open5gs/host/*.sh /opt/racora/core-support/
sudo chmod 755 /opt/racora/core-support/*.sh # the package carries them non-executable
sudo mkdir -p /etc/racora
echo 'RACORA_UE_CIDR=10.45.0.0/16' | sudo tee /etc/racora/core-support.env
for u in egress-nat fix-resolved-loopback nat-sanitize; do
sed 's/@CLUSTER_SERVICE@/kubelet.service/' "installer/cores/open5gs/host/${u}.service" | sudo tee "/etc/systemd/system/${u}.service" >/dev/null
done
sudo systemctl daemon-reload
sudo systemctl enable --now egress-nat.service fix-resolved-loopback.service nat-sanitize.service
The units are templates on @CLUSTER_SERVICE@, the cluster runtime's systemd unit;
their ExecStart points at /opt/racora/core-support/ and egress-nat reads the UE
pool from /etc/racora/core-support.env. What each unit does is on the
Open5GS page. egress-nat.sh waits up to about a minute for a
KUBE-POSTROUTING or FLANNEL-POSTRTG chain (the sign that kube-proxy or flannel has
restored the nat table) and then adds its rule regardless; a CNI that rebuilds the nat
table later can flush it, so check the rule after a CNI restart. An external core needs
nothing here.
9. Install
INSTALL_RACORA_PLATFORM=kubernetes INSTALL_RACORA_VERSION=vX.Y.Z RACORA_HELM_EXTRA_ARGS='-f my-values.yaml' sh installer/install-racora.sh
That is the installer of the release you unpacked, pinned to the same release, so the chart and the overlays match.
Add INSTALL_RACORA_CORE=external INSTALL_RACORA_AMF_ADDR=<amf> for your own core, and
RACORA_REGISTRY=<registry> to pull every image from a mirror
(Use Your Own Registry or Install Offline). The installer runs
the one helm command of the kubernetes platform,
which you can run yourself with the two overlays from the package and your values file;
that page also says what the platform overlay decides.
10. Verify
kubectl get pods -n racora-system # the two controllers and the device plugins
kubectl get deploy -n centralized-unit # cu-cp, cu-up, cuip at 0/0 (dormant)
kubectl get pods -n 5g-core # the core, on the control node
Then declare your first cell. Removing the RAN again is
INSTALL_RACORA_MODE=uninstall on the same platform; the host and cluster scopes
are refused because Racora did not install this cluster
(Uninstall Racora).