Deploy on Kubernetes
Deploy LicOps on Kubernetes when the workloads you want to gate run in the cluster, or when the cluster is where you already run shared services. You install the Router with one Helm chart, connect it to OpenLM Platform, and optionally install a second chart: an admission webhook that makes the admit, dispatch, and release requests for pods you annotate.
For Slurm or LSF, you don't need Kubernetes. A Docker Compose deployment is simpler. See Deploy OpenLM LicOps.
Before you begin
Confirm these prerequisites:
- A cluster that meets the requirements for Kubernetes, and
kubectland Helm 3 configured for it. - MongoDB 7.x and Redis 7.0 or higher that the cluster can reach, configured as described in System requirements.
- The LicOps Helm charts. OpenLM supplies them in the LicOps deployment bundle:
openlm-routerinstalls the Router, andopenlm-gkeinstalls the admission webhook. Contact OpenLM to get the bundle. - Your cluster's pod network range, its pod CIDR. On many clusters
kubectl cluster-info dump | grep -m1 cluster-cidrprints it.
Create the secrets
The charts read their connection strings and certificate from secrets you create beforehand. They never create these secrets themselves. Run these commands in the namespace you deploy to:
export NS=openlm-licops
kubectl create namespace $NS
kubectl -n $NS create secret generic openlm-generic-mongo-db-credentials \
--from-literal=MONGODB__CONNECTIONSTRING='mongodb://<user>:<password>@<mongo-host>:27017/?authSource=admin'
kubectl -n $NS create secret generic openlm-generic-redis-connection-credentials \
--from-literal=REDIS__CONNECTIONSTRING='<redis-host>:6379,abortConnect=false'
kubectl -n $NS create secret tls openlm-lb-cert --cert=<certificate.pem> --key=<private-key.pem>
The TLS secret openlm-lb-cert is needed only while Traefik serves HTTPS, with traefik.enabled and traefik.tls.enabled both true, which is the default.
Then create the encryption key, once, on the first installation only:
kubectl -n $NS create secret generic openlm-router-platform-encryption \
--from-literal=ADMISSION_PLATFORM_ENCRYPTION_KEY="$(openssl rand -base64 32)"
The key decrypts the OpenLM Platform credentials stored in MongoDB. On an upgrade the secret already exists and this command fails. That is correct, so skip it. Do not delete and recreate the secret to get past the error: that replaces the key, and the stored OpenLM Platform credentials become unreadable.
Pass the key as plain text, exactly as openssl printed it. --from-literal encodes it for you. If you write the secret as a manifest instead, put the key under stringData:, not data:, or it is encoded twice and the first save of the OpenLM Platform connection fails.
Install the Router
Create a values file, licops-values.yaml, that makes the Router a LicOps Router managed from OpenLM Platform:
routerapi:
tag: "1.261006.0752" # olm-routerapi
encryptionKey:
secretName: openlm-router-platform-encryption
admissionController:
proxyProtocol:
trustedCidrs:
- <your-pod-CIDR>
extraEnv:
# Required. The Router takes its configuration and rules from the OpenLM Platform.
- name: licOpsConfiguration__enabled
value: "true"
- name: LICOPSCONFIGURATION_ENABLED
value: "true"
# Required. Declares a LicOps Router. Fixed at the first start.
- name: ROUTER_CONFIG_BOOTSTRAP_MODE
value: loadBalancer
# Keep the background-job dashboard off.
- name: hangfire__dashboard__enabled
value: "false"
routerui:
tag: "1.261008.0932" # olm-routerui
To install the chart, run this command:
helm upgrade --install openlm-router ./licops-deploy/helm/openlm-router \
-n $NS --set namespace=$NS -f licops-values.yaml
Set these values carefully:
--set namespace=$NS: The chart places its resources in the namespace named in its own values,openlmby default, whatever namespace you pass to Helm. Set both to the same namespace.tag: The chart has no default tag. A missing tag renders an image reference ending in a colon, which fails only when the image is pulled.trustedCidrs: The Router uses it to trust the identity the webhook's sidecar sends with each checkout. Set it to your pod CIDR. An empty list stops the Router from starting. A range that does not cover your pod network passes that check with no error, but the Router then does not read the job identity the sidecar sends, so checkouts from those pods are not matched to their jobs.- The
extraEnventries: The chart does not set OpenLM Platform management or the LicOps mode by itself. Without them, nothing you define in LicOps Configuration reaches the Router.
The chart creates two Services: openlm-router-api, the admission API on port 8100, and openlm-router-data, the LicOps listen port 30001. Workloads in the cluster use the API at http://openlm-router-api.<namespace>.svc:8100.
By default the chart routes /router-management and /api/v1 on your Traefik entry point to the Router, for any host name. These paths lead to the administration interfaces of the Router. Allow access to them only from your administration network, and do not publish them to the internet. Set traefik.host to a host name only your administrators use and restrict access to it, or set traefik.enabled=false and reach the Router with kubectl port-forward.
Traefik is optional. With Traefik turned on, the chart expects the entry points web, websecure, and a TCP entry point routertcp on port 30001, and routertcp publishes the LicOps listen port on the load balancer. Without Traefik, both Services are reachable only from inside the cluster.
To confirm the Router started, run these commands. Until you connect the Router to OpenLM Platform, the pod status is Running with 0/1 Ready, so kubectl rollout status does not finish. The API is reachable through the port-forward meanwhile.
kubectl -n $NS get pods
kubectl -n $NS port-forward svc/openlm-router-api 8100:8100
In a second terminal, run this command:
curl http://localhost:8100/api/v1/status
The response reads "status": "unconfigured" with "shape": "serviceManaged", as described in Deploy OpenLM LicOps. The Router is running and is not connected to OpenLM Platform.
Connect the Router to OpenLM Platform
With the port-forward running, connect the Router as described in Configure OpenLM LicOps. Use the REST commands there against http://localhost:8100. If you kept Traefik turned on, you can also open the Router UI at https://<traefik-address>/router-management/.
A port-forward is for your own terminal only and stops when you close it. Workloads in the cluster use the Service address, never localhost.
Install the admission webhook
The webhook is optional. It licenses pods without any change to their images: for every pod you annotate, it calls admit when the pod is created, adds init containers that dispatch and redirect the pod's license traffic, and adds a sidecar that releases the seat when the pod ends. If each job calls the API itself, skip this section and see Kubernetes workloads.
The sidecar and the two init containers, tagged dev-8f79e85, are pre-release builds. The webhook image itself is a numbered release.
helm upgrade --install openlm-gke ./licops-deploy/helm/openlm-gke -n $NS \
--set image.tag=dev-8f79e85 \
--set image.webhookTag=1.260819.1521 \
--set certManager.enabled=false \
--set router.restEndpoint=http://openlm-router-api.$NS.svc:8100 \
--set router.host=openlm-router-data.$NS.svc
- Two tags:
image.tagsets the sidecar and init-container images, andimage.webhookTagsets the webhook. They are released separately. - The certificate: The webhook needs a certificate the Kubernetes API server trusts.
certManager.enabled=falsemakes the chart generate a self-signed certificate that is valid for 365 days. The chart makes a new one each time you run thishelm upgrade --installcommand, and the webhook loads it only when it starts. After every run, restart the webhook withkubectl -n $NS rollout restart deployment/openlm-gke. If the certificate expires, every pod you opted in is rejected. To generate it, the chart pullsalpine/k8sfrom Docker Hub and might installopenssl, so it needs internet access. For production, run cert-manager and pass--set certManager.issuerRef.name=<your-issuer>instead. With neither, the installation fails at once. - The Router addresses:
router.restEndpointandrouter.hostare required. Giverouter.restEndpointthe Service address and port only. The webhook adds the API path itself, so a value that already ends in/api/v1/admission-controllermakes every admit fail and every opted-in pod is rejected.
The webhook is registered with a failure policy of Fail, so while it is unavailable, no pod can be created in a namespace you opted in. That keeps pods from starting without a LicOps seat during a webhook outage. To let pods start without a seat, install with --set webhook.failurePolicy=Ignore. This setting covers the webhook only: when the webhook runs but cannot reach LicOps, it lets pods through unchanged, as described in Kubernetes workloads.
The chart pulls the images olm-pod-sidecar, olm-dispatch-init, and olm-iptables-init.
To opt namespaces and pods in, see Kubernetes workloads.
Upgrade
Change the tags in licops-values.yaml, then run the same helm upgrade --install command. If you installed the admission webhook, upgrade it too: run its helm upgrade --install command again with the new image.tag and image.webhookTag. If you use the self-signed certificate, then restart the webhook with kubectl -n $NS rollout restart deployment/openlm-gke. Skip the encryption-key secret: it already exists and must not change. To list the available builds, see Find the newest build. The configuration and rules live in OpenLM Platform, and the open sessions live in Redis, so they survive the upgrade.
The documentation team might draft this page using a large language model. A technical writer reviews every page and verifies it against the product before publishing it. A human makes the final decision.