Skip to main content
Centiloc Service Documentation
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Single-node Setup with k0s

k0s provides a lightweight Kubernetes distribution that is well suited to a single-node Geocore installation. This guide uses an Ubuntu Server host and follows the recommendations for a single-machine deployment.

Before you begin
Complete the OnPremise prerequisites first. In particular, make sure that you can access the Centiloc Harbor registry and that kubectl and Helm are available on the host.

1. Install k0s

On a clean Ubuntu Server host, install and start a single-node k0s controller:

curl -sSLf https://get.k0s.sh | sudo sh
sudo k0s install controller --single
sudo systemctl daemon-reload
sudo k0s start
sudo k0s kubeconfig admin > ~/.kube/config

Confirm that the node is ready:

kubectl get nodes

The output should show one node with the Ready status:

NAME    STATUS   ROLES           AGE   VERSION
myk0s   Ready    control-plane   1d    v1.28.2+k0s

2. Prepare persistent storage

For a single node, Geocore can deploy PostgreSQL in the cluster. Create a directory on the host for its persistent data:

sudo mkdir -p /opt/geocore/pg/data
sudo chown $USER:$USER -R /opt/geocore
sudo chmod 777 -R /opt/geocore

3. Configure Geocore

Create a myvalues.yaml file. The following sections are intentionally independent: add each one to the same file and replace every placeholder with your own values.

Registry access and core services

Configure the Harbor credentials, the single-node stream settings, the PostgreSQL credentials used by Geocore, and the current Keycloak setting:

global:
  imageCredentials:
    registry: harbor.centiloc.com
    email: <your-email>
    password: <your-password>
    username: <your-username>
  configuration:
    streamTech: "KAFKA"
  keycloak:
    url: ""
  postgresql:
    primary:
      user: "custom_user"
      password: "strong_password"
      dbname: "db_geocore"
    replicas: []

postgresql:
  enabled: true
  auth:
    postgresPassword: "very_strong_password"
  storagePath: "/opt/geocore/pg/data"

kafka:
  enabled: true
  replicaCount: 1
Keycloak is currently unavailable
The current Geocore OnPremise chart does not include Keycloak. Keep global.keycloak.url empty.

MQTT NodePort

MQTT must remain directly reachable by boards. Expose the broker as a NodePort. The following configuration enables TLS by default; replace X.X.X.X with the IP address of the k0s host.

emqx:
  enabled: true
  replicaCount: 1
  allPassword: "very_strong_password"
  service:
    type: NodePort
    nodePorts:
      mqttssl: 30883
      mqtt: 30881
  emqxConfig:
    EMQX_SSL_CLIENT_OPTS__SERVER_NAME_INDICATION: "X.X.X.X"
    # To enable plain TCP instead, comment the line above and uncomment:
    # EMQX_LISTENERS__TCP__DEFAULT__ENABLE: "true"

NTP NodePort

Expose the Geocore NTP service as a NodePort on the same address as MQTT:

ntp:
  service:
    type: NodePort

By default, the service is available on UDP port 30123. Boards require UDP port 123, which is outside Kubernetes’ NodePort range. Redirect UDP port 123 to port 30123 on the host.

Install nftables:

sudo apt-get update
sudo apt install nftables

Identify the host network interface that receives board traffic:

ip -o addr | grep 'k0s_single_machine_cluster_IP' | awk '{print $2}'

Add the following rule to /etc/nftables.conf, replacing your_interface_name with the interface name:

table ip geocore {
    chain prerouting {
        type filter hook prerouting priority mangle; policy accept;
        iifname "your_interface_name" udp dport 123 \
        dup to 127.0.0.1 udp dport set 30123 notrack
    }

    chain input {
        type filter hook input priority mangle; policy accept;
        iifname lo udp dport 123 ip daddr set 127.0.0.1 notrack
    }
}

Apply the configuration:

sudo nft -f /etc/nftables.conf

Optional RS485 support

RS485 support is disabled by default. Enable the gateway agent only if the deployment needs it:

parcontrol3:
  gwagent:
    replicaCount: "1"

4. Access API and Centui

Choose one access method and add its configuration to myvalues.yaml. See Service Exposure for the complete exposure model.

Use the Contour Envoy LoadBalancer when the API and Centui should be available on standard HTTPS ports. The following values configure the TLS setup:

core:
  geo:
    tlsEnabled: true
  centui:
    tlsEnabled: true
    apiURL: "api.k0s.example.test"
    centuiURL: "centui.k0s.example.test"

The apiURL and centuiURL values must exactly match the api.domain and centui.domain values in the Ingress configuration. Point both names to the Contour Envoy address.

Keep the Geocore services as ClusterIP. Expose the Contour Envoy service as a NodePort and point both DNS names, or equivalent client hosts-file entries, to the k0s host IP address.

core:
  geo:
    tlsEnabled: false
  centui:
    tlsEnabled: false
    apiURL: "api.k0s.example.test:30180"
    centuiURL: "centui.k0s.example.test"

After installing Contour with Envoy HTTP NodePort 30180 and the Geocore routes, open Centui at http://centui.k0s.example.test:30180. Centui reaches the Envoy gRPC-Web endpoint at http://api.k0s.example.test:30180.

Follow Install Contour and Envoy and select the plain HTTP routing values in the Ingress guide.

5. Install Geocore

Once myvalues.yaml contains the required sections, install Geocore in the geocore namespace:

helm install geocore oci://harbor.centiloc.com/centiloc/geocore \
  --namespace geocore \
  --create-namespace \
  -f myvalues.yaml

Check that the pods are running:

kubectl get pods --namespace geocore

6. Verify external access

MQTT and NTP are exposed through the NodePorts configured above. Continue with Expose Geocore Services to install Contour, create the mandatory Geocore routes, and publish DNS records. Then open Centui at the configured Envoy address.

Uninstall the cluster

To remove the k0s cluster, follow the official k0s reset instructions.