# Helm Setup

### **Introduction**

This guide deploys Floating Server v2 on a small on-prem Kubernetes cluster (1 server + 2 agents) on the same LAN using k3s, MetalLB (LAN LoadBalancer IPs), and CloudNativePG (PostgreSQL operator). The Floating Server Helm chart is hosted in a Docker Hub OCI registry. By the end, you will have a `LoadBalancer` service with an external LAN IP that you can access from other machines on the network. This setup is a starting point and can be expanded later (for example, by adding more worker nodes, increasing replica counts, or scaling the database).

### Machine setup

Start machines (VMs or physical) on the same LAN:

* 1x Server node (Kubernetes control plane) → call it server
* 2x Agent nodes (Kubernetes workers) → call them agents

If you plan to use **MetalLB in L2 mode**, nodes must be on the same L2 network (bridged networking recommended).

This guide assumes **Ubuntu**.

### 1) Prerequisites on every machine (server + agents)

Run on each node:

```
sudo apt-get update
sudo apt-get install -y curl ca-certificates
```

You can use any Kubernetes distribution (for example **k3s** or **kubeadm**). This guide uses **k3s** in Section 2. If you already have a working Kubernetes cluster and `kubectl` access, you can skip Section 2 and continue with the Helm steps.

### 2) Install k3s (multi-node: 1 server + 2 agents)

#### 2.1 Install k3s on the server node

On the server:

```
curl -sfL https://get.k3s.io | sh -
```

Check it’s running:

```
sudo systemctl status k3s --no-pager
sudo k3s kubectl get nodes -o wide 
```

Get the join token (you will need this on the agents):

```
sudo cat /var/lib/rancher/k3s/server/node-token 
```

#### 2.2 Get the server LAN IP (`<SERVER_IP>`)

On the server, run:

```
ip -4 addr show
ip route
```

Look for a line like:

* `inet 10.0.0.26/24 ...` → your `<SERVER_IP>` is `10.0.0.26`

Also confirm the gateway line exists running `ip route`, e.g.:

* `default via 10.0.0.1 dev eth0`

#### 2.3 Install k3s on each agent node

On each agent, replace `<SERVER_IP>` and `<TOKEN>`:

```
curl -sfL https://get.k3s.io | K3S_URL="https://<SERVER_IP>:6443" K3S_TOKEN="<TOKEN>" sh -
```

Verify the agent service:

```
sudo systemctl status k3s-agent --no-pager
```

#### 2.4 Verify the cluster from the server

On the server:

```
sudo k3s kubectl get nodes -o wide
```

You should see 3 nodes (1 server + 2 agents).

### 3) Set up kubectl + Helm on the server machine

All kubectl/helm commands will be run on the server.

#### 3.1 Configure kubectl for your user

On the server:

```
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER:$USER ~/.kube/config
chmod 600 ~/.kube/config
```

Test:

```
kubectl get nodes -o wide
```

#### 3.2 Install Helm (only if missing)

Check if Helm exists:

```
helm version
```

If it’s not installed:

```
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
```

### 4) Install MetalLB (LoadBalancer support on LAN)

#### 4.1 Install MetalLB

On the server:

```
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
```

Wait for pods, and:&#x20;

```
kubectl -n metallb-system get pods -w
```

#### 4.2 Configure an IP pool on your LAN

MetalLB assigns “external” IPs to `LoadBalancer` Services from an IP pool you provide. The IPs in this pool must:

* be in your LAN subnet
* not be assigned by DHCP (choose a high/unused range)
* not already be in use by another device

If you already know a free IP range on your LAN, you can skip Steps 1–3.

**Step 1: Identify your LAN subnet**

On the server:

```
ip -4 addr show
ip route
```

Example:

* `inet 10.0.0.26/24` → LAN subnet is `10.0.0.0/24`

**Step 2: Pick a “high” unused range**

Picking a high range is usually safe.Examples:

* `LAN 10.0.0.0/24` → choose `10.0.0.220-10.0.0.230`
* `LAN 192.168.1.0/24` → choose `192.168.1.220-192.168.1.230`

**Step 3: Confirm the IPs aren’t already in use**

Test a few candidates:

```
ping -c 1 10.0.0.225
```

If you get replies, that IP is taken → choose a different range.

**Step 4: Create metallb-pool.yaml**

Create `metallb-pool.yaml` with following content, only replace the LAN range.

Example for `10.0.0.220-10.0.0.230`:

```
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: lan-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.0.0.220-10.0.0.230
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: lan-adv
  namespace: metallb-system
spec:
  ipAddressPools:
  - lan-pool
```

Apply it:

```
kubectl apply -f metallb-pool.yaml
```

&#x20;

### 5) Install CloudNativePG (CNPG) operator

On the server:

```
helm repo add cnpg https://cloudnative-pg.github.io/charts
helm repo update
```

```
helm upgrade --install cnpg \
  --namespace cnpg-system \
  --create-namespace \
  cnpg/cloudnative-pg
```

Wait a bit and run:

```
kubectl -n cnpg-system get pods -w
```

### 6) Provision and configure

#### 6.1 Provisioning&#x20;

Follow the provisioning steps. On the server, create a cert directory:

```
mkdir -p ~/certs
```

Copy the provisioning files to the server ([visit Configuration & Provisioning](/floating-server/floating-server-v2/configuration-and-provisioning.md)) :

* `~/certs/private.key`
* `~/certs/certificate-chain.pem`

These filenames must match what the chart expects.

#### 6.2 Create a custom values file

Create:`~/values-floating-server.yaml`The file must follow this template:

```
replicaCount: 3

image:
  repository: licensespring/floating-server-v2
  tag: v2.3.0
  pullPolicy: IfNotPresent

service:
  type: LoadBalancer
  port: 8080
  basePath: ""
  targetPort: 8080
  name: http

labels:
  app: floating-server

postgres:
  clusterName: fsdb
  instances: 3
  imageName: ghcr.io/cloudnative-pg/postgresql:16.3
  storageSize: 10Gi

database:
  name: fsdb
  user: fsuser
  password: ""
  port: 5432
  sslmode: "disable"

config:
  mountDir: /app/config
  filename: default.yaml

cloud:
  useOAuth: false
  apiKey: "REPLACE_ME"
  sharedKey: "REPLACE_ME"


certs:
  mountDir: /opt/server/certs
  # switch to .Files.Get approach. If certs are supplied via files in ~/certs/ (recommended, as explained above), do not paste them here.
  privateKeyPem: |-
    -----BEGIN PRIVATE KEY-----
    ...
    -----END PRIVATE KEY-----

  certificateChainPem: |-
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE----- 
```

Replace:

* `cloud.apiKey`
* `cloud.sharedKey`

### 7) Deploy Floating Server from the Docker Helm registry

#### 7.1 Install/upgrade the chart using your values file

On the server:

```
helm install floating-server-v2 \
  oci://registry-1.docker.io/licensespring/floating-server-v2 --version 0.1.0 \
  -n floating-server --create-namespace \
  -f ~/values-floating-server.yaml
```

### 8) Verify everything is running

#### 8.1 Pods

```
kubectl -n floating-server get pods -o wide
```

#### 8.2 If a pod fails

```
kubectl -n floating-server describe pod <pod-name> | sed -n '/Events:/,$p'
```

#### 8.3 Services / MetalLB IPs

```
kubectl -n floating-server get svc -o wide
```

If your service is LoadBalancer, you should see an `EXTERNAL-IP` from your MetalLB pool.Try opening it from a browser on the same LAN:

```
http://<EXTERNAL-IP>:<PORT>/<BASE-PATH>
```

&#x20;

&#x20;


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.licensespring.com/floating-server/floating-server-v2/helm-setup.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
