Skip to main content

K3s

K3s is a small Kubernetes distribution for your own machines. It brings an ingress controller (Traefik) and a storage class (local-path), so OpenLM Platform needs little around it. Read this page before step 1.

Platform as VM

If you want OpenLM to set up K3s, the data services, and OpenLM Platform for you on a single machine, use Platform as VM instead: a packaged installer with its own guide. This page is for installing the chart on a K3s cluster you run yourself.

Before you start​

Confirm these requirements:

ItemRequirement
MachinesThree machines with 8 vCPU / 32 GiB each for the standard set, or one machine with 24 vCPU / 96 GiB (simpler, but with no room for maintenance). Add 32 GiB and 6 to 8 vCPU if MongoDB, Kafka and Redis run on the same machines. See Sizing.
OSA current 64-bit Linux that K3s supports. RHEL 9-family (RHEL, AlmaLinux, Rocky) is the most tested.
DiskSSD. local-path volumes live under /var/lib/rancher/k3s/storage.
Ports open to users443 (and 80 for the redirect)

Install K3s with a higher pod limit​

K3s allows 110 pods per node by default. OpenLM Platform alone runs about 95, plus the cluster's own, so raise the limit before installing K3s:

sudo mkdir -p /etc/rancher/k3s
printf 'kubelet-arg:\n - "max-pods=250"\n' | sudo tee /etc/rancher/k3s/config.yaml
curl -sfL https://get.k3s.io | sh -

On an existing K3s, add the same lines to /etc/rancher/k3s/config.yaml and restart it (sudo systemctl restart k3s).

On RHEL-family systems with firewalld, let the cluster networks talk to each other:

sudo firewall-cmd --permanent --zone=trusted --add-source=10.42.0.0/16 --add-source=10.43.0.0/16
sudo firewall-cmd --permanent --add-port=443/tcp --add-port=80/tcp
sudo firewall-cmd --reload

With several machines, also open 6443/tcp, 8472/udp and 10250/tcp between them.

More than one machine​

Install the first machine as described in Install K3s with a higher pod limit. It becomes the server. If the machines share a private network, add these lines to its /etc/rancher/k3s/config.yaml before installing, so cluster traffic stays on that network:

node-ip: <this machine's private IP>
node-external-ip: <this machine's public IP> # only if users reach it on another address
flannel-iface: <private network interface, e.g. eth1>

On each further machine, write the same max-pods line plus its own node-ip / flannel-iface, then join it to the server:

# on the server: the join token
sudo cat /var/lib/rancher/k3s/server/node-token
# on the new machine
curl -sfL https://get.k3s.io | K3S_URL="https://<server private IP>:6443" K3S_TOKEN="<token>" sh -

Every machine needs the Node settings.

kubectl from your workstation​

The guide's commands run on your workstation. To reach the cluster from there, add the address you'll use in the server's /etc/rancher/k3s/config.yaml before installing:

tls-san: [<server public IP or name>]

Then copy the cluster's kubeconfig to the workstation and point it at that address:

scp <user>@<server>:/etc/rancher/k3s/k3s.yaml ~/.kube/openlm-k3s.yaml # readable by root: copy it with sudo on the server first
sed -i.bak 's/127.0.0.1/<server public IP or name>/' ~/.kube/openlm-k3s.yaml
export KUBECONFIG=~/.kube/openlm-k3s.yaml
kubectl get nodes

Port 6443 must be open from your workstation to the server. Keep this file safe: it gives full admin access to the cluster.

Ingress​

Use the Traefik that K3s brings as the ingress: set INGRESS_CLASS=traefik in the worksheet. Point your DNS record at the machine's IP (or a load balancer in front of the machines).

HTTPS redirect​

Make Traefik redirect every http:// request to https://. K3s applies any file in its manifests folder automatically:

sudo tee /var/lib/rancher/k3s/server/manifests/traefik-config.yaml >/dev/null <<'EOF'
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
web:
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
EOF

After a minute, check that curl -sI http://$DOMAIN/ | head -1 shows 308.

Storage​

Set STORAGE_CLASS=local-path. The class is built in and needs nothing else. Volumes stay on the node where they were first created, which is fine for the small working volumes of OpenLM Platform.

Node settings​

On every machine, set the file-watch limits:

printf 'fs.inotify.max_user_instances = 8192\nfs.inotify.max_user_watches = 524288\n' | sudo tee /etc/sysctl.d/90-openlm.conf
sudo sysctl --system

DNS inside the cluster​

Pods must reach https://$DOMAIN. On a K3s machine behind a router or NAT, traffic to the machine's public address often doesn't come back. Make the name resolve inside the cluster to Traefik directly, with K3s's CoreDNS extension point:

kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata: { name: coredns-custom, namespace: kube-system }
data:
openlm.override: |
rewrite name exact $DOMAIN traefik.kube-system.svc.cluster.local
EOF
kubectl -n kube-system rollout restart deployment coredns

If the machine's own DNS resolvers only answer over IPv6, pods can't resolve anything outside the cluster. Point K3s at IPv4 resolvers: create /etc/rancher/k3s/resolv.conf with nameserver <IPv4 resolver> lines, add resolv-conf: /etc/rancher/k3s/resolv.conf to /etc/rancher/k3s/config.yaml, and restart K3s.

Values​

K3s needs no values beyond what step 4 gives you. Leave node placement off on a single machine.

Data services​

SQL Server usually runs outside the cluster (Windows or Linux server, or a cloud database). MongoDB, Kafka and Redis can run on the same K3s cluster, installed with their own charts or operators, in their own namespace. Size the machine for them as well.

Checks specific to K3s​

Confirm the K3s settings with these commands:

kubectl get nodes # Ready
kubectl get node -o jsonpath='{.items[0].status.capacity.pods}{"\n"}' # 250
kubectl -n kube-system get pods | grep -E "traefik|coredns" # Running

The documentation team might draft this page using a large language model. A technical writer reviews every page and verifies it against the product before publishing it. A human makes the final decision.