Open5GS — The Reference Core Provider
Open5GS is the default core provider (INSTALL_RACORA_CORE=open5gs,
global.core.provider: open5gs). It is why a fresh install brings up a network that real
phones can attach to with no external dependency. The image is built from unmodified
upstream Open5GS source (AGPL-3.0) in the ocudu repository; the chart is
racora-core-open5gs (values).
What It Deploys
One hostNetwork pod in 5g-core running Open5GS's 5gc entry point (the AMF, SMF,
UPF, NRF, SCP, AUSF, UDM, UDR, PCF, NSSF and BSF), MongoDB and the Open5GS WebUI, a
Service amf exposing NGAP over SCTP on 38412 and GTP-U on 2152, and a
PersistentVolumeClaim open5gs-mongodb for the subscriber database. The claim names no
StorageClass, so the cluster's default one provisions it (k3s ships local-path); a cluster
you run needs a default StorageClass for this provider. The pod is a singleton
rolled with the Recreate strategy: a host-network process cannot be surged. MongoDB binds
127.0.0.1:27017. The WebUI binds port 9999 on the address the node's hostname resolves to:
on a stock Ubuntu host that is the loopback alias 127.0.1.1, so it is reachable from the
control node or over ssh -L 9999:127.0.1.1:9999 <control node>; on a host whose hostname
resolves to a LAN address it listens there, with its own login. ss -ltnp | grep 9999 on
the node shows which.
It is pinned with the CU planes (controlPlanePin: true on the k3s platform; your own
nodeSelector on a cluster you run, see Install onto an Existing Kubernetes Cluster).
The Identity It Serves
The PLMN comes from global.network.plmn: the chart splits it into the image's MCC and MNC.
Tracking areas 7, 8 and 9 and slice sst 1 are fixed in the image's configuration; the
chart refuses a global.network that asks for others at render time, so the mismatch never
reaches NG Setup. The default identity (PLMN 90170, TAC 7, sst 1) is what the reference
deployment runs.
UE Addresses and Egress
The UPF hands attached UEs addresses in ueIpBase.0/24 (default 10.45.0). Internet egress
goes through the control node: the egress-nat host unit masquerades the UE pool
RACORA_UE_CIDR (INSTALL_RACORA_UE_CIDR on the installer, default 10.45.0.0/16, kept
across re-runs). Change ueIpBase and the pool together: set racora-core-open5gs.ueIpBase
in your values (the HelmChartConfig on k3s) and re-run the server install with
INSTALL_RACORA_UE_CIDR=<pool>, which rewrites /etc/racora/core-support.env and restarts
the egress unit; a pool that does not contain the UPF's range gets no egress.
Subscribers
A Subscriber is provisioned into the pod's mongodb by the core
controller, through the provider's adapter: the image's own provisioning helpers, run inside
the pod, upsert the IMSI with its keys, QoS class and DNN (default internet). An IMSI
that is already in the database is adopted: its entry is replaced by what the
Subscriber declares. Deleting a Subscriber removes its entry. The database lives on the open5gs-mongodb claim
(persistence.enabled, default on, helm.sh/resource-policy: keep), so provisioned SIMs
survive pod rolls and upgrades. What an uninstall does with the claim is on Uninstall Racora; a
kubectl -n 5g-core delete pvc open5gs-mongodb wipes it deliberately.
The chart also seeds one bootstrap subscriber at every start (subscriber.* values:
the image's built-in test SIM). It is provider configuration, not a Subscriber resource;
Racora never removes it, and it never conflicts with subscribers you declare.
Back Up and Restore the Database
The Subscriber objects and the Secrets they reference are the record of what you
declared: re-applying them re-provisions every SIM into a fresh database, so keep them
with the rest of your manifests. Entries added through the WebUI live only in the
database, open5gs in the pod's mongodb; the image carries the MongoDB tools, so dump and
restore them through the pod:
kubectl -n 5g-core exec deploy/open5gs -- mongodump --db open5gs --archive > open5gs.archive
kubectl -n 5g-core exec -i deploy/open5gs -- mongorestore --archive --drop < open5gs.archive
Entries added directly through the Open5GS WebUI are left alone as well: the core controller manages only the subscribers it was asked to declare.
What It Needs from the Host
The control node must allow hostNetwork and privileged pods in 5g-core (no baseline or
restricted Pod Security level there), and three host units. The pod runs on the host's
network, so it depends on host-level networking that no chart can set up:
| Unit | When it runs | What it does |
|---|---|---|
fix-resolved-loopback | before the cluster runtime, after network-pre.target | Open5GS creates dummy interfaces lo2 to lo22 with 127.0.0.x/24 addresses, which on the host network take over the addresses systemd-resolved listens on. The unit claims 127.0.0.53 and 127.0.0.54 on lo with /32 masks first, so name resolution keeps working. |
nat-sanitize | before the cluster runtime, and again whenever it restarts | Open5GS's own network setup inserts native nftables masquerade rules without counters on every start, and they accumulate. kube-proxy manages the nat table with iptables-nft and exits on a chain it cannot parse, so the unit removes those rules before kube-proxy starts. |
egress-nat | after the cluster runtime, and again whenever it restarts | adds the source NAT that gives attached UEs internet access: a MASQUERADE for the UE pool leaving through anything but ogstun, plus IP forwarding. It reads the pool from /etc/racora/core-support.env (RACORA_UE_CIDR, the installer's INSTALL_RACORA_UE_CIDR), waits up to about 60 s for a KUBE-POSTROUTING or FLANNEL-POSTRTG chain so its rule lands after the CNI's own, and adds the rule either way. |
The scripts live in /opt/racora/core-support/, the pool in
/etc/racora/core-support.env, and the three .service files are templates on the
cluster runtime's systemd unit (k3s.service on the k3s platform, kubelet.service on a
cluster you run). The k3s platform installs all of it on the control node and records the
units in /etc/racora/install.env, so the uninstall removes exactly those. On a cluster
you run, the steps are on Install onto an Existing Kubernetes Cluster.
On a cluster whose CNI provides neither chain (Cilium with kube-proxy replacement),
egress-nat.sh adds its rule after the wait; a CNI that restores the nat table later can
flush it.
Uninstall
ran scope removes the pod, the Service and the provider declaration with the release, and
the 5g-core namespace with the subscriber claim unless --keep-data keeps it. host scope disables and removes the three
units and the pool file, then runs the provider's teardown, which deletes the ogstun TUN
device, the lo2 to lo22 interfaces and the UE-pool NAT the core left on the host, so a
later install starts clean.