Skip to main content
Version: v3.8.0
Not interested in using Kubernetes?

There are two flavours of Control Plane deployments - Remote and Kubernetes. This guide will focus on deploying a Control Plane on a Kubernetes cluster. Go to Remote - Deploy Control Plane to deploy the Control Plane on a Linux host instead. Keep in mind that in such case, it will be necessary to prepare the host for Controller as well.

Also, this guide will use Helm to deploy the Control Plane on the cluster. To use potctl instead, go to Kubernetes - Deploy Control Plane Using potctl.

Kubernetes - Deploy Control Plane Using Helm

In this tutorial, we will install the Datasance PoT Control Plane on Kubernetes using Helm.

The Helm Chart deploys the PoT operator and creates a ControlPlane custom resource instance automatically. The Operator consumes this CRD and creates deployments for the Controller, Router, and (when enabled) NATs, as well as associated services. Image versions (operator 3.8.0, controller v3.8.0, router, NATs) are configurable in the chart values; see the Control Plane YAML Specification for NATs and Router options.

Prerequisites

Add the Helm Repository

Add the Datasance Helm repotsitory to your local index:

helm repo add datasance https://datasance.github.io/iofog-operator/
helm repo update

Install the Chart

Install the Chart while specifying embedded OIDC authentication. See Embedded OIDC Authentication for bootstrap credentials and TLS. Provide values via a values file or --set flags.

Quick Install with Flags

helm install pot-operator datasance/pot -n pot --create-namespace \
--set controlplane.spec.auth.mode=embedded \
--set controlplane.spec.auth.bootstrap.username=admin \
--set controlplane.spec.auth.bootstrap.password=LocalTest12!

Install with Values File

Create a myvalues.yaml file with your configuration:

operator:
image: ghcr.io/datasance/operator:3.8.0
controlplane:
spec:
replicas:
controller: 1
nats: 2
nats:
enabled: true
# Database is optional; if omitted, the controller uses internal SQLite.
# When using SQLite, keep controller replicas at 1.
database:
provider: postgres
host: db
port: 5432
user: pot
password: changeme
databaseName: pot
ssl: false
auth:
mode: embedded
bootstrap:
username: admin
password: LocalTest12!
controller:
publicUrl: https://controller.example.com:51121
consoleUrl: https://console.example.com:8008

Then install using the values file:

helm install pot-operator datasance/pot -n pot --create-namespace \
-f pot-operator-values.yaml

The install creates:

  • CRDs for controlplanes.datasance.com
  • The PoT operator (iofog-operator) Deployment + RBAC + ServiceAccount
  • One ControlPlane instance (toggle with controlplane.create)

Verify Installation

To list all Helm releases, run:

helm list -n pot

The result should look like this:

NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
pot-operator 1 Tue Dec 8 21:34:42 2025 DEPLOYED pot-3.8.0 3.8.0 pot

Configuration

Edit values.yaml or provide your own overrides (e.g. test-values.yaml). Key sections:

  • operator.*: image, replicaCount, resources, scheduling, extraEnv/extraArgs, serviceAccount, RBAC.
  • controlplane.*: metadata and full ControlPlane .spec (auth, database, controller, events, images, services, nats, ingresses, vault, replicas).
  • crds.install: whether to install the ControlPlane CRD.

Required values

Must be set via values or --set:

  • Auth (embedded OIDC): controlplane.spec.auth.mode=embedded, controlplane.spec.auth.bootstrap.username, controlplane.spec.auth.bootstrap.password (≥12 chars, 1 uppercase, 1 special). See Embedded OIDC.
  • Database (required in ControlPlane CRD v3): controlplane.spec.database with at least provider, host, port, user, password, databaseName. For SQLite use provider: sqlite with empty host/port/user/password/databaseName as needed.

Optional / common overrides

  • Operator: operator.image (default ghcr.io/datasance/operator:3.8.0), operator.replicaCount, operator.resources, operator.nodeSelector, operator.tolerations, operator.affinity, operator.serviceAccount.create|name, operator.imagePullSecrets
  • ControlPlane metadata: controlplane.create, controlplane.name, controlplane.namespace
  • Replicas: controlplane.spec.replicas.controller, controlplane.spec.replicas.nats (min 2 when NATs enabled)
  • Images: controlplane.spec.images.controller, router, nats, pullSecret
  • Services: controlplane.spec.services.controller|router|nats|natsServer with type, address, annotations, externalTrafficPolicy (e.g. Local or Cluster)
  • NATs: controlplane.spec.nats.enabled, controlplane.spec.nats.jetStream.memoryStoreSize, storageSize, storageClassName
  • Controller: controlplane.spec.controller.logLevel, https, secretName, publicUrl, consoleUrl, trustProxy
  • Ingresses: controlplane.spec.ingresses.controller|router|nats (host, ingressClassName, address, ports)
  • Events: controlplane.spec.events.auditEnabled, retentionDays, cleanupInterval, captureIpAddress
  • Vault (optional): controlplane.spec.vault.enabled, provider, basePath, and provider-specific config (hashicorp, aws, azure, google)

Quick install with flags (example)

helm install pot datasance/pot -n pot --create-namespace \
--set controlplane.spec.auth.mode=embedded \
--set controlplane.spec.auth.bootstrap.username=admin \
--set controlplane.spec.auth.bootstrap.password=LocalTest12! \
--set controlplane.spec.database.provider=sqlite \
--set controlplane.spec.database.host="" \
--set controlplane.spec.database.port=0 \
--set controlplane.spec.database.user="" \
--set controlplane.spec.database.password="" \
--set controlplane.spec.database.databaseName="" \
--set controlplane.spec.database.ssl=false

Example values override

operator:
image: ghcr.io/datasance/operator:3.8.0

controlplane:
create: true
name: pot
spec:
# Database is required in CRD v3. Use sqlite for single-replica or postgres for HA.
database:
provider: postgres
host: db
port: 5432
user: pot
password: changeme
databaseName: pot
ssl: false
ca: ""
auth:
mode: embedded
bootstrap:
username: admin
password: LocalTest12!
controller:
publicUrl: https://controller.example.com:51121
consoleUrl: https://console.example.com:8008
replicas:
controller: 1
nats: 2
images:
controller: ghcr.io/datasance/controller:3.8.0
router: ghcr.io/datasance/router:3.8.0
nats: ghcr.io/datasance/nats:2.14.3
services:
controller:
type: LoadBalancer
router:
type: LoadBalancer
nats:
type: LoadBalancer
natsServer:
type: LoadBalancer
nats:
enabled: true

Lint (local chart)

From the repo root:

helm lint charts/pot

Upgrade

helm upgrade pot datasance/pot -n pot -f myvalues.yaml

For a local chart:

helm upgrade pot ./charts/pot -n pot -f test-values.yaml

Uninstall

helm uninstall pot -n pot

Note: CRDs remain by default after uninstallation. Remove them manually if desired:

kubectl delete crd controlplanes.datasance.com

Connection to Installed Control Plane

Once the installation is complete, you can connect to the Controller using potctl. Make sure the --namespace matches the one used during helm install:

Connect to Installed Control Plane as a KubernetesControlPlane

potctl create namespace pot
potctl connect --email [email protected] --kube ~/.kube/config --namespace pot

Connect to Installed Control Plane as a RemoteControlPlane

potctl create namespace pot
potctl connect --email [email protected] --name pot --ecn-addr <http://controller-endpoint:51121> -n pot

You will need to authenticate using the bootstrap admin credentials configured during installation. See Embedded OIDC Authentication.

Where to go from here?

With the Control Plane running, go to Setup Edgelet nodes to provision Edgelet v1.0.0 on your edge hosts.

Group 3See anything wrong with the document? Help us improve it!