Installation on On-premises / vanilla Kubernetes
Overview
This guide covers the installation of CAST Imaging on an on-premises (or otherwise non-managed) Kubernetes cluster (i.e. a “vanilla” Kubernetes distribution that you operate yourself) using Helm charts.
The same CAST Imaging Helm chart is used for both cloud-managed clusters (EKS / AKS / GKE) and on-premises clusters. The main differences are:
- The
K8SProvidervariable invalues.yamlmust be set toK8S. - The cluster does not provide managed storage classes, load balancer integration, or ingress controllers out of the box. You are responsible for selecting, installing, and operating these building blocks on your cluster (CSI storage drivers, a load-balancer implementation, an ingress / gateway controller, etc.). The CAST Imaging chart simply consumes whatever you have installed.
This page focuses on the on-premises specifics. For everything else (Keycloak parameters, initial start-up configuration, authentication, start/stop scripts, external PostgreSQL, storage locations, etc.) the chart behaves identically to the cloud-managed variants and the same documentation applies.
Requirements
- Access to Docker Hub registry - CAST Imaging Docker images are available as listed in the table below
- A clone of the latest release branch from the Git repository containing the Helm chart scripts:
git clone https://github.com/CAST-Extend/com.castsoftware.castimaging-v3.kubernetessetup(to clone an older release, add the “-b x.x.x” flag with the desired release number). - A valid CAST Imaging License
- A working Kubernetes cluster with, at minimum:
- CSI storage drivers installed by your cluster administrator, exposing at least one block / disk storage class and one shared file storage class. CAST Imaging is agnostic to the specific driver: any conformant CSI driver works (e.g.
local-path-provisioner,rook-ceph,longhorn,nfs-csi,vsphere-csi, etc.). Setting this up is the cluster administrator’s responsibility. - (Optional but recommended) a load-balancer implementation such as MetalLB if you want services of type
LoadBalancerto receive an external IP. Without one, services will remain in<pending>state for their external IP and you will need to expose them via NodePort or a reverse proxy. Setting this up is the cluster administrator’s responsibility. - (Optional) an ingress / gateway controller (NGINX Ingress, NGINX Gateway Fabric, Istio, etc.) if you want HTTPS access. See Step 3.
- CSI storage drivers installed by your cluster administrator, exposing at least one block / disk storage class and one shared file storage class. CAST Imaging is agnostic to the specific driver: any conformant CSI driver works (e.g.
- Optional setup choices:
- Use an external PostgreSQL instance (a PostgreSQL instance is provided as a Docker image and will be used by default)
Docker images
CAST Imaging is provided in a set of Docker images as follows:
Installation process
Before starting the installation, ensure that your Kubernetes cluster is running, all the CAST Imaging docker images are available in the registry and that helm and kubectl are installed on your system.
Step 1 - Cluster prerequisites
- Make sure your Kubernetes cluster is up and that
kubectlis configured to point at it:
kubectl get nodes
-
Install
kubectl(if not already installed) - see https://kubernetes.io/docs/tasks/tools/ -
Install
helm:- Binary download: https://github.com/helm/helm/releases
- Documentation: https://helm.sh/docs/intro/quickstart
-
Ensure your cluster administrator has installed and tested:
- At least one CSI block / disk storage class: note its name (referred to below as
<your-disk-storage-class>). - If you plan to run multiple
analysis-nodeinstances: a shared file storage class supportingReadWriteMany. Note its name (referred to below as<your-file-storage-class>). If you will only run a single analysis node, you can reuse the disk storage class. - (Optional) a load-balancer implementation (e.g. MetalLB) and/or an ingress / gateway controller.
- At least one CSI block / disk storage class: note its name (referred to below as
You can list the storage classes available on your cluster with:
kubectl get storageclass
Step 2 - Prepare and run the CAST Imaging installation
-
Review and adjust the parameter values in the
values.yamlfile (located at the root of the cloned Git repository branch) in between the section separated with # marks. -
Set the
K8SProvider:option toK8S:
K8SProvider: K8S
- Storage classes: disable storage-class creation by the chart and point CAST Imaging at the storage classes already installed on your cluster:
CreateStorageClass: false
DiskClassName: <your-disk-storage-class> # e.g. local-path, longhorn, rook-ceph-block, ...
FileClassName: <your-file-storage-class> # e.g. nfs-csi, rook-cephfs, ... (or the same as DiskClassName if you only run one analysis-node)
- Run
helm-install.bat|sh(depending on your base OS) located at the root of the cloned Git repository branch
Keycloak component parameters
CAST Imaging uses the Keycloak system to manage all authentication requirements (see Authentication for more information). You should take note of two parameters that you may wish to customize before running the installation:
KeycloakAdminPassword: <default-password>
KCADMIN_USERNAME: kcadmin
-
KeycloakAdminPassworddefines the password for the Keycloakadmin“service” account used for intra-component communication. By default this password is set to “admin” (encrypted in base64). Update this if you wish to change this password e.g. by runningecho -n "my-new-password" | base64to generate a new encrypted password. This password can also be updated post install (see below). -
KCADMIN_USERNAMEdefines the name of the account (kcadminby default with password “admin”) used to login in to the Keycloak UI to administer authentication. Updatekcadminto your preferred account name. Note that this change can only be done BEFORE a new installation.
Step 3 - Configure network settings for console-gateway (main entrypoint) and extendproxy (optional) services
By default, with CreateLoadBalancer: true and none of the ingress/gateway flags enabled, the chart deploys the console-gateway service as a Kubernetes Service of type LoadBalancer, accessible over HTTP on port 8090. For this to result in an actual external IP, a load-balancer implementation such as MetalLB must be available on the cluster. Without one, the service’s external IP stays <pending>; you can still reach the service via NodePort or by port-forwarding for testing.
If you want HTTPS access, use one of the three options below (they are the same as for cloud-managed Kubernetes). Choose one of the three options below (Gateway API, NGINX Ingress, or Istio). All three options share a common Final steps subsection at the end.
The instructions for installing each ingress / gateway implementation are generic Kubernetes instructions and apply identically on cloud and on-premises clusters. No cloud-specific load-balancer annotations are needed here: the load-balancer behaviour in front of the ingress / gateway is provided by your on-premises load-balancer implementation (e.g. MetalLB).
Option A: If you want to use a Gateway API implementation
Modern, vendor-neutral Kubernetes ingress using the Gateway API standard.
The Gateway API is the modern, vendor-neutral successor to the Kubernetes Ingress API. CAST Imaging provides a GatewayAPI.yaml template that creates the Gateway and HTTPRoute resources needed to expose console-gateway-service and (optionally) extendproxy. The template has been tested with NGINX Gateway Fabric (NGF), but the Gateway / HTTPRoute resources are portable to any conformant implementation (Istio, Envoy Gateway, etc.).
- Set
UseGatewayAPI: trueinvalues.yaml:
UseGatewayAPI: true
- Install the Gateway API CRDs on the cluster (if not already installed):
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml
- Install a Gateway controller. For NGINX Gateway Fabric:
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway
Verify the installation:
kubectl get gatewayclass
kubectl get pods -n nginx-gateway
-
Configure the
Gatewayresource invalues.yaml. Two options are supported:- Option 1 - Create a new Gateway dedicated to CAST Imaging (default):
Gateway: create: true className: nginx # Use "nginx" for NGF, or the gatewayClassName of your controller- Option 2 - Attach to an existing shared Gateway already deployed on the cluster:
Gateway: create: false name: my-shared-gateway namespace: my-gateway-namespaceWhen attaching to an existing Gateway, it must already define listeners named
https(andhttps-extendifExtendProxy.enableistruewith a different hostname for the extend proxy). The shared Gateway’s listener must also allow routes from the CAST Imaging namespace (allowedRoutes.namespaces.from: Allor a matchingSelector). -
Create TLS Secret(s) using the certificate files associated to the DNS name(s) you are planning to use. The secrets must be created in the CAST Imaging namespace (Gateway listeners read certificates from the Gateway’s own namespace, unless a
ReferenceGrantis used):
kubectl create secret tls tls-secret-cast --cert=my-cert-folder\myhostname.com\fullchain.pem --key=my-cert-folder\myhostname.com\privkey.pem -n castimaging-v3
# Optional (only needed if you are deploying ExtendProxy):
kubectl create secret tls tls-secret-cast-extend --cert=my-cert-folder\myextendhostname.com\fullchain.pem --key=my-cert-folder\myextendhostname.com\privkey.pem -n castimaging-v3
# (fullchain.pem <=> tls.crt ; privkey.pem <=> tls.key)
If you are deploying ExtendProxy (optional) and want to use the same hostname for both services, just create the 2 secrets using the same certificate files.
Note on NGINX Gateway Fabric body size limits: The standard Gateway API has no portable equivalent to the NGINX Ingress
proxy-body-sizeannotation. WhenGateway.classNameisnginxorngf, the chart additionally createsClientSettingsPolicyresources (an NGF-specific extension) to raise the client body size limit for the main route and theextendproxyroute. These policies are applied via Helmpost-install/post-upgradehooks so they reconcile after their target HTTPRoutes. Other Gateway implementations (Istio, Envoy Gateway, etc.) handle body size limits through their own native resources, and these policies are not rendered.
➡️ Continue with the Final steps (Gateway API, Istio or NGINX Ingress) subsection below.
Option B: If you want to use a Kubernetes NGINX Ingress
Traditional Kubernetes Ingress backed by the NGINX Ingress controller.
- Set
CreateIngress: trueinvalues.yaml:
CreateIngress: true
- Install the Ingress driver on the cluster:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace
On an on-premises cluster, the
ingress-nginxcontroller is itself exposed via aLoadBalancerservice by default. Make sure your cluster provides a load-balancer implementation (e.g. MetalLB), otherwise the controller’s external IP will stay<pending>. Alternatively, expose it viaNodePortby passing--set controller.service.type=NodePortto thehelm installcommand above.
- Create TLS Secret(s) using the certificate files associated to the DNS name(s) you are planning to use:
kubectl create secret tls tls-secret-cast --cert=my-cert-folder\myhostname.com\fullchain.pem --key=my-cert-folder\myhostname.com\privkey.pem -n castimaging-v3
# Optional (only needed if you are deploying ExtendProxy):
kubectl create secret tls tls-secret-cast-extend --cert=my-cert-folder\myextendhostname.com\fullchain.pem --key=my-cert-folder\myextendhostname.com\privkey.pem -n castimaging-v3
# (fullchain.pem <=> tls.crt ; privkey.pem <=> tls.key)
If you want to use the same hostname for both services, just create the 2 secrets using the same certificate files.
➡️ Continue with the Final steps (Gateway API, Istio or NGINX Ingress) subsection below.
Option C: If you want to use an Istio Ingress Gateway
Service-mesh-based ingress using Istio.
- Set
CreateIstioGateway: trueinvalues.yaml:
CreateIstioGateway: true
Note that Istio may be already installed on your cluster. Please check with your administrator.
- Install Istio on the cluster (Linux/Mac):
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH
istioctl install --set profile=default -y
- Install Istio on the cluster (Windows - PowerShell using Chocolatey):
choco install istioctl
istioctl install --set profile=default -y
- Install Istio on the cluster (Windows - PowerShell using manual download and install of a specific version)
$ISTIO_VERSION="1.28.4" # Check https://github.com/istio/istio/releases for latest
Invoke-WebRequest -Uri "https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istio-$ISTIO_VERSION-win.zip" -OutFile "istio.zip"
Expand-Archive -Path "istio.zip" -DestinationPath "." -Force
cd "istio-$ISTIO_VERSION"
$env:PATH = "$PWD\bin;$env:PATH"
istioctl install --set profile=default -y
On an on-premises cluster, the
istio-ingressgatewayis exposed via aLoadBalancerservice by default. Make sure your cluster provides a load-balancer implementation (e.g. MetalLB), otherwise the gateway’s external IP will stay<pending>. Alternatively, edit theistio-ingressgatewayservice to useNodePort.
- Optional - If you want to use a specific Istio Gateway already deployed on your cluster, set the gateway name in ExistingIstioGatewayName:
UseIstioGateway: true
ExistingIstioGatewayName: "some-namespace/my-gateway"
- Create TLS Secret(s) using the certificate files associated to the DNS name(s) you are planning to use (to be created in the istio-system namespace):
kubectl create secret tls tls-secret-cast --cert=my-cert-folder\myhostname.com\fullchain.pem --key=my-cert-folder\myhostname.com\privkey.pem -n istio-system
# Optional (only needed if you are deploying ExtendProxy):
kubectl create secret tls tls-secret-cast-extend --cert=my-cert-folder\myextendhostname.com\fullchain.pem --key=my-cert-folder\myextendhostname.com\privkey.pem -n istio-system
# (fullchain.pem <=> tls.crt ; privkey.pem <=> tls.key)
If you want to use the same hostname for both services, just create the 2 secrets using the same certificate files.
➡️ Continue with the Final steps (Gateway API, Istio or NGINX Ingress) subsection below.
Final steps (Gateway API, Istio or NGINX Ingress)
Common steps that apply to Options A, B, and C above.
Optional - When Gateway API, Istio or NGINX Ingress is implemented to access the console-gateway service with a certificate that cannot be verified (e.g., self-signed certificate or internal CA), the certificate will need to be stored in CAST auth-service to avoid certificate validation errors:
- set:
UseCustomTrustStore: trueinvalues.yaml - Insert the encoded certificate:
- directly inside the
auth.caCertificatevariable invalues.yaml - or using
helm upgrade ... --set-file auth.caCertificate=ca.crt ...to override the variable value with theca.crtfile content
- directly inside the
UseCustomTrustStore: true
auth:
caCertificate: |
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
If you are also deploying ExtendProxy (optional), choose one of the two sub-options below:
- Set hostnames in values.yaml - same-hostname-option: use the same hostname for all services
FrontEndHost: https://myhostname.com
ExtendProxy
enable: true
exthostname: myhostname.com
Exposed URLs will be:
https://myhostname.com (or https://myhostname.com/mycontext if ContextUrl is enabled)
https://myhostname.com/extendproxy
- Set hostnames in values.yaml - different-hostname-option: use a different hostname for each service:
FrontEndHost: https://myhostname.com
ExtendProxy
enable: true
exthostname: myextendhostname.com
Exposed URLs will be:
https://myhostname.com (or https://myhostname.com/mycontext if ContextUrl is enabled)
https://myextendhostname.com/extendproxy
- Apply the
helmchart changes by runninghelm-upgrade.bat|sh(depending on your base OS) located at the root of the cloned Git repository branch. - Create a DNS record pointing at the reverse proxy external IP address.
To retrieve the external IP:
# For NGINX Gateway Fabric, use this command:
kubectl get svc -n nginx-gateway
#
# For an NGINX Ingress, use this command:
kubectl get ingress -n castimaging-v3
#
# For an Istio Ingress, use this command:
kubectl get service istio-ingressgateway -n istio-system
Step 4 - Install Extend Local Server (optional)
To install Extend Local Server:
- In
values.yaml(located at the root of the cloned Git repository branch), setExtendProxy.enabletotrueand update theExtendProxy.exthostnamevariable with the DNS name. In case you want to access it thru its Load Balancer (set “CreateLoadBalancer: true”), use the LoadBalancer external IP address instead or the DNS name (kubectl get service -n castimaging-v3 extendproxyto get the IP):
ExtendProxy:
enable: true
exthostname: myextendhost.com # or LoadBalancer external IP address
- Run
helm-upgrade.bat|sh(depending on your base OS) located at the root of the cloned Git repository branch. - Review the log of the
extendproxypod to find the Extend Local Server administration URL and API key (these are required for managing Extend Local Server and configuring CAST Imaging to use it - you can find out more about this in Extend Local Server). You can get theextendproxypod name by runningkubectl get pods -n castimaging-v3then runkubectl logs -n castimaging-v3 castextend-xxxxxxxxto display the log. - In Console System Settings, use this value for the “CAST Extend URL”: http://extendproxy:8085
Step 5 - Initial start up configuration
License and Extend API key steps can be skipped if values were provided for these helm chart variables:
- ImagingLicenseType
- ImagingLicense
- ExtendApiKey
If not, when the install is complete, browse to the public/external URL and login using the default local admin/admin credentials. You will be prompted to configure:
- your licensing strategy. Choose either a
Named Applicationstrategy (where each application you onboard requires a dedicated license key entered when you perform the onboarding), or aContributing Developersstrategy (a global license key based on the number of users):

- CAST Extend settings / Proxy settings (if you chose to install Extend Local Server (see Step 4 above) then you now need to input the URL and API key so that CAST Imaging uses it).

As a final check, browse to the URL below and ensure that you have at least one CAST Imaging Node Service, the CAST Dashboards and the CAST Imaging Viewer components listed:
https://<public or external URL>/admin/services

Step 6 - Configure authentication
Out-of-the-box, CAST Imaging is configured to use Local Authentication via a simple username/password system managed by Keycloak. Default login credentials for CAST Imaging are provided (admin/admin) with the global ADMIN profile so that installation can be set up initially.
CAST recommends configuring CAST Imaging (via the Keycloak component) to use your on-premises enterprise authentication system such as LDAP or SAML Single Sign-on instead before you start to onboard applications. To access the Keycloak UI to configure your authentication system, use the kcadmin account. See Authentication for more information.
Updating the Keycloak admin service account password post installation
Out-of-the-box Keycloak is provisioned with a service account used for intra-component communication with the credentials admin/admin. If you need to change this password post-installation, follow the steps below:
Change the password via the UI
- Navigate to the Keycloak account security page using the following URL (replace
<public-external-url>with your installation’s external URL):
https://<public-external-url>/auth/realms/master/account/account-security/signing-in
- Log in with the default credentials (
admin/admin) - Update the password through the account settings interface
Update the password in the Helm Chart
After changing the password in the Keycloak UI, you must update the Helm chart configuration to match.
- Encode your new password in base64 format. On a Linux machine, run:
echo -n "my-new-password" | base64
The -n flag prevents adding a newline character to the encoded output.
- In your cloned Git repository containing the CAST Imaging Kubernetes installation files, open:
values.yaml
- Locate this line:
KeycloakAdminPassword: <default-password>
- Replace the defined password with your base64-encoded password:
KeycloakAdminPassword: <your-base64-encoded-password>
- Example: If your base64 output is
bXktbmV3LXBhc3N3b3Jk, the line should read:
KeycloakAdminPassword: bXktbmV3LXBhc3N3b3Jk
Apply changes
Run Util-ScaleDownAll.bat and helm-upgrade.bat to restart CAST Imaging and apply the changes.
How to start and stop CAST Imaging
Use the following script files (located at the root of the cloned Git repository branch) to stop and start CAST Imaging:
Util-ScaleDownAll.bat|shUtil-ScaleUpAll.bat|sh
Storage class selection
The FileClassName you set in values.yaml must point to a storage class backed by a CSI driver supporting ReadWriteMany (RWX) access mode, so that analysis-nodes and console-service can share files. Examples of RWX-capable on-premises options include NFS-based CSI drivers, CephFS (via Rook), GlusterFS, etc. A standard block-storage driver (e.g. local-path-provisioner, plain iSCSI) only supports ReadWriteOnce (RWO) and will not work for multiple analysis nodes.
Use an external PostgreSQL instance
If you do not want use the PostgreSQL instance preconfigured in this helm chart, you can disable it and configure an external PostgreSQL instance instead.
-
Setup your external PostgreSQL database
- PostgreSQL 15 - 8GB RAM minimum recommended
- Define a superuser authenticated by password
-
In
values.yaml:- Set
CastStorageService.enabletofalse(will disable the embedded PostgreSQL installation) - Set
CustomPostgres.enabletotrue - Set
CustomPostgres.hostandCustomPostgres.portto match your custom database host name and port number - Set
CustomPostgres.adminloginandPostgresDbPasswordto match the superuser login name and password of your custom database
- Set
-
Proceed with the CAST Imaging installation described above
Kubernetes storage location information
For information about storage locations used across the containers in a CAST Imaging Kubernetes deployment (for example persistent volumes, ConfigMap-backed configuration files, Secrets, and ephemeral (in-memory) volumes), see Kubernetes storage location information.