Skip to content

// installation

Kubernetes

Step 4 of 10 · Path A (bare metal)

Applies to

Product: Server · Audience: Platform Operator

Cluster requirements for basebox, ingress controller, CloudNativePG and the differences between single-node and CPU/GPU-node layouts. At the end of this step your cluster offers everything the basebox umbrella chart requires.

Official documentation: Kubernetes with kubeadm · Calico · CloudNativePG · ingress-nginx

What the chart requires

Requirement Value
Kubernetes 1.23+ (verified: 1.33.7; 1.33+ recommended)
Helm 3.x (verified: 3.20.0)
Ingress controller Any; the chart ships nginx annotations
Storage Dynamic volume provisioning with a default storage class
Databases CloudNativePG operator in the cluster
GPU NVIDIA GPU Operator (or equivalent) on GPU nodes – see NVIDIA / GPU
Registry Pull access to gitea.basebox.health from the nodes' runtime

1. Install Kubernetes (kubeadm)

The verified path with kubeadm, containerd and Calico (Kubernetes 1.33):

1. Add the Kubernetes repository, install and pin the components:

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

2. Disable swap, set kernel modules and sysctl parameters:

sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF
sudo sysctl --system

3. Configure containerd before running kubeadm init – the default configuration has the CRI plugin disabled:

sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
sudo systemctl restart containerd && sudo systemctl enable containerd

4. Initialise the cluster and set up kubeconfig for your user:

sudo kubeadm init --pod-network-cidr=10.244.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

5. Install the network plugin:

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.31.3/manifests/calico.yaml

6. Check: kubectl get nodes shows the node Ready. Then install the GPU Operator – see NVIDIA / GPU → GPU Operator.

Alternative distributions such as k3s work; note the DNS problem with systemd-resolved there – solution in the FAQ.

2. Single node or several nodes

Single node (the reference configurations): control plane and workloads on the same machine. The control-plane taint prevents pods from being scheduled by default. Two paths:

  • Tolerations in the values of the components that need them (GPU Operator; values file under NVIDIA / GPU → GPU Operator) – the clean path for production.
  • Remove the taint – for development/test only:
    kubectl taint nodes --all node-role.kubernetes.io/control-plane-
    

CPU and GPU nodes: the basebox platform runs on CPU nodes, service models and inference on GPU nodes. Label nodes (nvidia.com/gpu: "true", possibly gpu-type) and use nodeSelector/tolerations in the values of the GPU services – examples on the Inference Server and Ragsrv pages. The GPU Operator only needs to work on the GPU nodes.

Separate clusters for platform and inference: Deployment topologies.

3. Ingress controller

The chart configures ingress resources with nginx annotations: 20 MB body for uploads, large buffers for JWT headers, 24-hour timeouts for WebSocket and streaming, buffering off, CORS, cache control. Install ingress-nginx (or a controller that understands these annotations) and note the ingress class (nginx) and the external IP:

kubectl get svc -A | grep -i ingress

The annotations in detail: Helm chart overview → Ingress configuration.

4. Storage class

basebox needs dynamic volume provisioning for the PostgreSQL clusters, media and model caches. For evaluation a local storage class suffices (local-path, default in the quick start); for production a storage class on SSD/NVMe with snapshots or replication. Set it as default or name it in the values (storageClass). Capacity planning: Storage.

kubectl get storageclass

5. CloudNativePG operator

Every basebox service with a database (AISRV, storesrv, ragsrv, Keycloak) gets its own PostgreSQL cluster, managed by CloudNativePG:

helm repo add cnpg https://cloudnative-pg.github.io/charts
helm upgrade --install cnpg \
  --namespace cnpg-system \
  --create-namespace \
  cnpg/cloudnative-pg
kubectl get pods -n cnpg-system

The umbrella chart also contains the operator as a dependency (cnpg-operator.fullnameOverride: cnpg); install it only once – either beforehand as here or via the chart.

6. cert-manager (optional)

For public domains with automatic certificates: install cert-manager and create a ClusterIssuer (e.g. letsencrypt-prod). Not needed with an internal CA or for evaluation – see Networking.

7. Verify

kubectl get nodes -o wide
kubectl get pods -A
kubectl get storageclass
kubectl get svc -A | grep -i ingress
kubectl get pods -n cnpg-system
kubectl get pods -n gpu-operator            # on GPU nodes
kubectl describe nodes | grep -A5 "Allocated resources"

Everything Ready/Running, a default storage class, an ingress IP, GPU resources on the GPU nodes – then the cluster is ready.

Common failure patterns

Symptom Cause Solution
kubeadm init: "unknown service runtime.v1.RuntimeService" containerd CRI disabled Step 1.3, then kubeadm reset and init again
Pods Pending Control-plane taint, no storage class, no GPU Tolerations; kubectl get pvc; check GPU Operator
inference/ragsrv-support: "Temporary error in name resolution" k3s with systemd-resolved Point coredns at an external DNS (FAQ)
Image pull fails on nodes Registry access of the runtime Test the pull from the runtime, not just from the workstation

Back: NVIDIA / GPU · Next: Storage