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 (Proof of Technology) Control Plane on Kubernetes using Helm.
The Helm Chart deploys the PoT operator (iofog-operator) and creates a ControlPlane custom resource instance automatically. The Operator consumes this CRD and creates deployments for the Controller and Router, as well as associated services.
Prerequisites
- Helm 3 - Helm installation instructions
- Kubernetes 1.22+ - The chart uses
apiextensions.k8s.io/v1CRDs - kubectl - kubectl installation instructions
- A working Kubernetes cluster (GKE, EKS, AKS, Minikube, or any other Kubernetes distribution)
Add the Helm Repository
Add the Datasance Helm repotsitory to your local index:
helm repo add datasance https://datasance.github.io/helm
helm repo update
Install the Chart
Install the Chart while specifying the required authentication configuration. The chart requires Keycloak/OpenID Connect authentication settings. You can provide these values either via a values file or using --set flags.
Quick Install with Flags
helm install pot-operator datasance/pot -n pot --create-namespace \
--set controlplane.spec.auth.url=https://keycloak.example.com \
--set controlplane.spec.auth.realm=pot \
--set controlplane.spec.auth.realmKey=master \
--set controlplane.spec.auth.ssl=true \
--set controlplane.spec.auth.controllerClient=pot-controller \
--set controlplane.spec.auth.controllerSecret=supersecret \
--set controlplane.spec.auth.viewerClient=pot-viewer
Install with Values File
Create a myvalues.yaml file with your configuration:
operator:
image: ghcr.io/datasance/operator:3.5.4
controlplane:
spec:
# 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:
url: https://keycloak.example.com
realm: pot
realmKey: master
ssl: true
controllerClient: pot-controller
controllerSecret: supersecret
viewerClient: pot-viewer
Then install using the values file:
helm install pot-operator datasance/pot -n pot --create-namespace \
-f myvalues.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.5.4 3.5.4 pot
Configuration
The Helm chart supports extensive configuration through values. You can view the complete default values.yaml file.
Required Values
The following authentication values must be set via values.yaml or --set:
controlplane.spec.auth.url- Keycloak/OpenID Connect server URLcontrolplane.spec.auth.realm- Keycloak realm namecontrolplane.spec.auth.realmKey- Realm key (typically "master")controlplane.spec.auth.ssl- Enable SSL (true/false)controlplane.spec.auth.controllerClient- Controller OIDC client IDcontrolplane.spec.auth.controllerSecret- Controller OIDC client secretcontrolplane.spec.auth.viewerClient- Viewer OIDC client ID
Common Configuration Options
Operator Configuration
# Operator image and replicas
--set operator.image=ghcr.io/datasance/operator:3.5.4
--set operator.replicaCount=1
--set operator.imagePullPolicy=Always
# Resource limits
--set operator.resources.requests.cpu=100m
--set operator.resources.requests.memory=128Mi
--set operator.resources.limits.cpu=500m
--set operator.resources.limits.memory=512Mi
# Node scheduling
--set operator.nodeSelector.kubernetes.io/os=linux
--set operator.tolerations[0].key=node-role.kubernetes.io/master
--set operator.tolerations[0].effect=NoSchedule
ControlPlane Metadata
--set controlplane.create=true
--set controlplane.name=pot
--set controlplane.namespace=pot
Database Configuration (Optional)
If omitted, the controller uses internal SQLite (keep controller replicas at 1):
--set controlplane.spec.database.provider=postgres
--set controlplane.spec.database.host=db
--set controlplane.spec.database.port=5432
--set controlplane.spec.database.user=pot
--set controlplane.spec.database.password=changeme
--set controlplane.spec.database.databaseName=pot
--set controlplane.spec.database.ssl=false
Controller Configuration
--set controlplane.spec.replicas.controller=1
--set controlplane.spec.controller.logLevel=info
--set controlplane.spec.controller.https=false
--set controlplane.spec.controller.secretName=tls-secret
Service Configuration
--set controlplane.spec.services.controller.type=LoadBalancer
--set controlplane.spec.services.router.type=LoadBalancer
Ingress Configuration
--set controlplane.spec.ingresses.controller.host=controller.example.com
--set controlplane.spec.ingresses.controller.ingressClassName=nginx
--set controlplane.spec.ingresses.controller.annotations.cert-manager.io/cluster-issuer=letsencrypt-prod
Image Configuration
--set controlplane.spec.images.controller=ghcr.io/datasance/controller:3.5.11
--set controlplane.spec.images.routerAdaptor=ghcr.io/datasance/router-adaptor:3.5.2
--set controlplane.spec.images.router=ghcr.io/datasance/router:3.5.2
--set controlplane.spec.images.pullSecret=my-registry-secret
Events Configuration
--set controlplane.spec.events.auditEnabled=true
--set controlplane.spec.events.retentionDays=14
--set controlplane.spec.events.cleanupInterval=86400
--set controlplane.spec.events.captureIpAddress=true
Complete Values File Reference
For the complete list of all configurable properties, refer to the values.yaml file in the Helm chart repotsitory.
Get Values Configuration File
wget -q -O - "https://raw.githubusercontent.com/Datasance/helm/refs/heads/main/charts/pot/values.yaml" > pot-operator-values.yaml
The values file structure includes:
Global Configuration
nameOverride: "iofog-operator"
fullnameOverride: "iofog-operator"
imagePullSecrets: []
CRD and RBAC
crds:
install: true
rbac:
create: true
Operator Configuration
operator:
replicaCount: 1
image: ghcr.io/datasance/operator:3.5.4
imagePullPolicy: Always
serviceAccount:
create: true
name: "iofog-operator"
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
extraEnv: []
extraArgs: []
ControlPlane Configuration
controlplane:
create: true
name: pot
namespace: ""
annotations: {}
labels: {}
spec:
replicas:
controller: 1
# database:
# provider: postgres
# user: ""
# host: ""
# port: 5432
# password: ""
# databaseName: ""
# ssl: false
# ca: ""
auth:
# REQUIRED: set all auth fields (Keycloak / OpenID Connect Client identity)
url: ""
realm: ""
realmKey: ""
ssl: ""
controllerClient: ""
controllerSecret: ""
viewerClient: ""
events:
auditEnabled: true
retentionDays: 14
cleanupInterval: 86400
captureIpAddress: true
images:
# pullSecret: ""
controller: "ghcr.io/datasance/controller:3.5.11"
routerAdaptor: "ghcr.io/datasance/router-adaptor:3.5.2"
router: "ghcr.io/datasance/router:3.5.2"
services:
controller:
type: LoadBalancer
# address: ""
# annotations: {}
router:
type: LoadBalancer
# address: ""
# annotations: {}
controller:
# pidBaseDir: ""
# ecnViewerPort: 0
# ecnViewerUrl: ""
https: false
# secretName: ""
logLevel: "info"
# ingresses:
# controller:
# annotations: {}
# ingressClassName: ""
# host: ""
# secretName: ""
# router:
# address: ""
# messagePort: 5671
# interiorPort: 55671
# edgePort: 45671
See the complete values.yaml file for all available options and their default values.
Upgrade
To upgrade an existing installation:
helm upgrade pot-operator datasance/pot -n pot -f myvalues.yaml
Uninstall
To uninstall the PoT Control Plane:
helm uninstall pot-operator -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 foo.bar@example.com --kube ~/.kube/config --namespace pot
Connect to Installed Control Plane as a RemoteControlPlane
potctl create namespace pot
potctl connect --email foo.bar@example.com --name pot --ecn-addr <http://controller-endpoint:51121> -n pot
You will need to authenticate using your Keycloak credentials configured during installation.
Having our Control Plane up and running, we can now go to Setup Agents guide to deploy our Agents and finalize the ECN deployment.