Deploy with Helm¶
This guide installs Release 2 of the Open Operator Platform (OpenOP) with the umbrella Helm chart oop-platform-chart. It covers two cases:
- a local kind (Kubernetes in Docker) cluster, set up by one script — the quickest way to try the platform;
- an existing Kubernetes cluster.
Both use the same chart. The kind setup is meant for local development, integration testing and demos, not for production. Every option below links to the Helm README, which lists all values.
What gets installed¶
| Component | What it does |
|---|---|
| Open Exposure Gateway (OEG) | Northbound entry point for App Providers (CAMARA APIs) |
| Service Resource Manager (SRM) | Deploys apps on edge clusters and drives the network through TF-SDK control paths |
| Federation Manager (FM) | Federation with other operators (GSMA OPG.04 EWBI) |
| Keycloak | Login and tokens: realm oop (portal users, App Providers, OEG) and realm federation (FM partners) |
| PostgreSQL | One shared instance, one database per component |
| NATS | Message bus between OEG, SRM and FM |
| AI² MCP and AI² AI Agent | CAMARA tools for AI agents, and a natural-language interface backed by Groq |
| Portal | Developer portal (web UI and its backend) |
| Data Lab | Dataspace metadata catalogue. Off by default, see Optional: Data Lab |
Release 2 has no MongoDB and no Artefact Manager: all data lives in PostgreSQL. To move from 1.x, see Upgrading from 1.x.
Prerequisites¶
Software¶
| Tool | Minimum version | Notes |
|---|---|---|
| Docker | 20.x | kind runs Kubernetes nodes in Docker containers |
| kind | 0.20 | Install kind (kind only) |
| kubectl | 1.25 | Install kubectl |
| Helm | v3 | Install Helm |
| Bash | 4+ | Needed by the deploy scripts |
Check your installations:
Hardware¶
For a comfortable local run of the full platform:
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores | 6+ cores |
| RAM | 12 GiB | 16 GiB |
| Disk | 20 GiB free | 30+ GiB free |
Plan for more if you turn on the Data Lab, which adds Elasticsearch and Virtuoso.
Get the charts¶
Clone the Helm repository at the release tag. All commands on this page run from its root, the folder that contains deploy-on-kind.sh:
git clone https://labs.etsi.org/rep/oop/deploy/helm.git
cd helm
git checkout v2.0.0-release
ls deploy-on-kind.sh oop-platform-chart environments/kind
Deploy on kind¶
1. (Optional) Add a Groq API key for AI²¶
AI²'s agent needs a Groq API key for its LLM calls. Create environments/kind/secrets.values.yaml (it is gitignored) before deploying:
Without this file the deploy script warns and carries on; AI² is installed but can't make LLM calls.
You don't need to put any other secret here. Database passwords, Keycloak passwords and client secrets, and the OEG and FM encryption keys are generated on first install and kept across upgrades. See Secrets in the Helm README to pin your own values.
2. Run the deploy script¶
The script runs two steps, which you can also run one at a time:
scripts/kind-bootstrap.sh(once per cluster) — checks thatkindandkubectlare installed, creates the kind clusteroop-clusterfromenvironments/kind/cluster.yaml, waits for the node and creates namespaceoop. If the cluster already exists, it asks whether to delete and recreate it.-
scripts/helm-deploy.sh(safe to re-run) — loadssecrets.values.yamlif it exists, downloads the NATS chart, runs the install below, and prints the access URLs:
After a few minutes all pods should be running.
3. Tell SRM where apps are reached¶
On kind, environments/kind/values.yaml gives SRM a ready-made setup: one Kubernetes control path, k8s-local, that deploys apps into namespace oop-apps of the kind cluster itself, and one zone, kind-local.
The control path's endpoint_host is a placeholder, <IP>. SRM puts this address in the endpoints of deployed apps, so replace it with the address the apps' NodePorts are reached on, usually the kind node's IP:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' oop-cluster-control-plane
Edit endpoint_host under srm.topology in environments/kind/values.yaml, then re-run ./scripts/helm-deploy.sh. To describe your own zones and clusters, see Define edge zones.
How the values files combine¶
Helm merges values files in order; later files win:
oop-platform-chart/values.yaml— base defaults for all components.environments/kind/values.yaml— kind overrides: NodePorts,global.publicHost: localhost, the SRM control path and topology, sample users.environments/kind/secrets.values.yaml— your secrets (gitignored).
The kind NodePorts:
| Component | Value | NodePort |
|---|---|---|
| SRM | srm.service.nodePort |
32415 |
| OEG | oeg.service.nodePort |
32263 |
| Federation Manager | federation-manager.service.nodePort |
30989 |
| Keycloak | global.nodePorts.keycloak |
30081 |
| Portal | global.nodePorts.portal |
30082 |
| Data Lab UI | global.nodePorts.datalab |
30083 |
| AI² MCP / AI Agent | ai2.mcp.service.nodePort / ai2.aiAgent.service.nodePort |
32004 / 32013 |
Changing a NodePort means recreating the kind cluster
Each NodePort must match a containerPort in environments/kind/cluster.yaml. If you change one, update both files, delete the cluster (kind delete cluster --name oop-cluster) and run ./deploy-on-kind.sh again: kind only applies port mappings when it creates a cluster.
Check it worked¶
Pods¶
All pods should reach Running (or Completed for setup jobs).
| Pod name starts with | Component |
|---|---|
oegcontroller |
Open Exposure Gateway |
srmcontroller |
Service Resource Manager |
federation-manager |
Federation Manager |
keycloak |
Keycloak |
postgres |
PostgreSQL |
oop-nats |
NATS |
ai2-mcp, ai2-ai-agent, ai2-redis |
AI² (MCP server, agent, and the agent's session store) |
portal |
Portal |
datalab- |
Data Lab (only when enabled) |
Access URLs¶
On kind:
| Service | URL |
|---|---|
| Portal | http://localhost:30082 |
| OEG API (Swagger) | http://localhost:32263/docs |
| SRM API (Swagger) | http://localhost:32415/docs |
| Keycloak | http://localhost:30081 |
| Keycloak admin console | http://localhost:30081/admin (user admin, password below) |
| Federation Manager (Swagger) | http://localhost:30989/docs |
| AI² MCP (for MCP clients) | http://localhost:32004/mcp |
| AI² AI Agent (Swagger) | http://localhost:32013/docs |
| Data Lab (when enabled) | http://localhost:30083 |
Quick check that OEG is up and can reach its dependencies:
First login¶
Every install creates a platform administrator, oop-admin, with a temporary password; the first login asks for a new one. On kind there are also three sample users in organization dev-org, one per role: dev-provider (App Provider), dev-operator (operator) and dev-admin (platform admin). Read the passwords with:
# Keycloak admin console (user: admin)
kubectl -n oop get secret keycloak-credentials -o jsonpath='{.data.admin-password}' | base64 -d; echo
# oop-admin's first-login password
kubectl -n oop get secret keycloak-credentials -o jsonpath='{.data.initial-admin-password}' | base64 -d; echo
# sample users (kind only)
kubectl -n oop get secret keycloak-credentials -o jsonpath='{.data.dev-user-password}' | base64 -d; echo
Log in to the Portal with one of these users. Roles, API products and organizations are covered in Manage users and access; what to do next is in the Tutorials.
Optional: Data Lab¶
The Data Lab metadata catalogue is off by default. It needs two settings, because the Data Lab and its Keycloak realm dataspace live in different subcharts:
| Setting | What it does |
|---|---|
datalab.enabled=true |
Deploys the Data Lab (piveau hub and search, Virtuoso, Elasticsearch, the Data Lab UI and API) |
keycloak.realms.dataspace.enabled=true |
Creates realm dataspace in Keycloak, which the Data Lab uses for login |
Set both. With only the first, nobody can log in and the Data Lab pods wait for a realm that never comes. With only the second, the realm exists and nothing uses it.
On a running platform (from the helm directory):
helm upgrade oop-platform ./oop-platform-chart -n oop --reuse-values \
--set datalab.enabled=true --set keycloak.realms.dataspace.enabled=true
Or set both to true in your values file. Turning it on in an existing installation restarts Keycloak, which then imports the realm. The Data Lab needs login: it is not deployed when global.auth.enabled=false.
Once the pods are Running, the Data Lab UI is at http://localhost:30083. On kind, the realm has the sample users steward, alice and bob, who share the dev-user-password (see First login).
Set the base URI before the first install
datalab.baseUri mints every catalogue, dataset and distribution URI, and these are persistent identifiers. The default embeds the NodePort address and suits kind only, so set your own before the first install and never change it.
All Data Lab options, and how to reset it, are in the Data Lab section of the Helm README. To use it, continue with Publish a dataset in the Data Lab.
Optional: try OpenOP without login¶
On your own machine you can switch login off for the whole platform:
helm upgrade --install oop-platform ./oop-platform-chart -n oop \
-f environments/kind/values.yaml --set global.auth.enabled=false
Keycloak, Federation Manager and the Data Lab are then not deployed. The chart refuses this setting unless global.publicHost is localhost or 127.0.0.1, because without login anyone who reaches the Portal or OEG can deploy workloads on the cluster.
Deploy on an existing cluster¶
You need kubectl pointing at your cluster and Helm v3. kind and deploy-on-kind.sh are not used.
There is no service account or token to create for SRM, and no values are required to install. From the root of the Helm repository:
helm dependency update ./oop-platform-chart
helm upgrade --install oop-platform ./oop-platform-chart -n oop --create-namespace \
--set global.publicHost=10.20.30.40 # optional, see below
Before you rely on it, go through these points. Each links to the part of the README that explains it:
- Public address. Keycloak's and the Portal's public URLs are built from
global.publicHost. If you leave it empty, it is detected at install from the first node (its ExternalIP, else its InternalIP). Set it when that is not the address users reach, and always when you usehelm templateor GitOps tools such as Argo CD. See Install on another cluster. - What is reachable from outside. Only Keycloak (
30081) and the Portal (30082) get NodePorts by default. To reach OEG, SRM or Federation Manager from outside, set theirservice.typeandservice.nodePort, asenvironments/kind/values.yamldoes. - SRM zones and clusters. SRM has no control paths or topology by default, so it can't deploy anything until you set
srm.topologyandsrm.workloads.namespaces. See Define edge zones and the SRM chart README. - Storage. Choose
postgresql.persistence(size and storage class; runkubectl get storageclassto list yours) before the first install: Kubernetes can't change it in place later. - Federation. Partners must reach FM's callback links: set
federation-manager.publicUrl. See the Federation Manager chart README. - AI². Pass the Groq key with a secrets file (
-f my-secrets.values.yaml), as in step 1.
Put your settings in your own values file (for example environments/my-cluster/values.yaml) and pass it with -f.
Upgrade¶
Re-run ./scripts/helm-deploy.sh, or:
As with the Data Lab, add -f environments/kind/secrets.values.yaml if you created it in step 1.
Generated passwords, client secrets and encryption keys are read back from their Secrets and kept.
Back up the encryption keys
OEG (oegcontroller-keys) and Federation Manager (federation-manager-keys) encrypt secrets they store in the database. Back these Secrets up together with the database and never change them: data encrypted with the old key can't be read with a new one. See Encryption keys.
Upgrading from 1.x¶
An in-place upgrade from 1.x is not supported. 1.x kept its data in MongoDB; 2.0 uses PostgreSQL and does not migrate the old data. Install 2.0 fresh. What changed in each component is in the Release 2.0.0 notes.
On kind, the simplest is to start over, since cluster.yaml changed too:
kind delete cluster --name oop-cluster
sudo rm -rf /tmp/kind-oop # 1.x MongoDB data on the host
./deploy-on-kind.sh
On a cluster you keep, save what you need from MongoDB, uninstall the 1.x release, remove leftover MongoDB volumes and the old oop-user service account, then install 2.0. The exact commands are in Upgrading from 1.x.
Troubleshooting¶
A pod doesn't start or keeps crashing¶
kubectl get pods -n oop
kubectl describe pod <pod-name> -n oop # events, image pulls, resource limits
kubectl logs <pod-name> -n oop # current logs (add -f to follow)
kubectl logs <pod-name> -n oop --previous # logs from before the last crash
For example, for OEG or SRM:
Helm release status¶
Storage¶
If the PostgreSQL claim stays Pending, check that the storage class in postgresql.persistence.storageClass exists in your cluster (kubectl get storageclass).
Using locally built images¶
The charts use pullPolicy: IfNotPresent, so you can load an image you built into the cluster, then set the component's image.tag to your tag:
Behind a corporate proxy or custom CA¶
If your network needs a custom CA certificate, see Mounting CA Certificates on kind in the Helm README.
Cleanup¶
helm uninstall keeps some things on purpose, so a reinstall finds them again: the PostgreSQL and NATS volumes, the Secrets postgres-credentials, keycloak-credentials, portal-credentials, oegcontroller-keys and federation-manager-keys, SRM's app namespaces (e.g. oop-apps) and, if you turned on the Data Lab, its volumes and datalab-credentials. To remove everything on a cluster you keep: