To deploy CTP in Kubernetes, follow the process outlined below.
Deploying multiple CTP servers in Kubernetes is not supported with this version. Support is limited to a single instance of CTP running in a Kubernetes cluster.
Prerequisites
First, create a namespace for CTP to run in. For example:
kubectl create namespace parasoft-ctp-namespace
Note: The namespace name "parasoft-ctp-namespace" is used throughout this documentation in command and resource examples. If you use a different name for your namespace, be sure to change any instances of "parasoft-ctp-namespace" in those examples to your namespace name.
Once CTP has been licensed, deleting the namespace will invalidate machine-locked licenses, even if you recreate the same namespace.
A Persistent Volume and Persistent Volume claim for exports storage are needed. They should be provisioned with around 10GB of space (this can be increased or decreased according to your needs) and ReadWriteOnce access mode is recommended. This space will be used for the CTP server.
The default Persistent Volume Claim name 'ctp-exports-storage' can be customized by updating the yaml definition of the CTP server. The example shown below is a configuration to set up an NFS Persistent Volume and Persistent Volume Claim. While the example uses NFS, this is not required; use whatever persistent volume type fits your needs.
Warning: For NFS, the exported directory must have the same UID and GID as the Parasoft user that runs the container. For example, execute the command chown 1000:1000 <shared_path>.
# ==== Persistent Volume for Export Storage ====
apiVersion: v1
kind: PersistentVolume
metadata:
name: ctp-exports-storage
namespace: parasoft-ctp-namespace
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: <path>
server: <ip_address>
---
# ==== PersistentVolumeClaim for CTP exports folder ====
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ctp-exports-pvc
namespace: parasoft-ctp-namespace
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs
resources:
requests:
storage: 10Gi
volumeName: "ctp-exports-storage"
Use the yaml file to create Persistent Volumes and a Persistent Volume claims:
kubectl create -f ctp-pv.yaml
Next, you need to configure your CTP database. If you do not specify otherwise, CTP will create a default HyperSQL database in the /usr/local/parasoft/ctp/hsqldb directory. Alternatively, use the secret below by modifying the db_config_xml string to configure CTP to connect to a different database. Note that if the URL JDBC string is for MariaDB, MySQL, Oracle, or PostgreSQL, then your CTP deployment/pod should be configured with the correct JDBC adapter; if the URL JDBC string is for HyperSQL, it should start up regardless of your CTP deployment/pod configuration.
apiVersion: v1
kind: Secret
metadata:
name: ctp-db-config-secret
namespace: parasoft-ctp-namespace
type: Opaque
stringData:
db_config_xml: |
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<db_config>
<connection>
<mode>JDBC_URL</mode>
<url>jdbc:mysql://mysql-service:3306/em</url>
<username>em</username>
<password>Kxj6+gSI/FcC8QJcg6UDyg==</password>
<type>MySQL</type>
</connection>
</db_config>
</configuration>
A Persistent Volume and a Persistent Volume claim for the database are needed. It should be provisioned with around 50GB of space (this can be increased or decreased according to your needs) and ReadWriteOnce access mode is recommended.
The default Persistent Volume claim names in the examples below can be customized by updating the yaml definition of the CTP server. While the examples use NFS, this is not required; use whatever persistent volume type fits your needs. Be aware that for the external databases the Persistent Volume and Persistent Volume claim mounts are for the database JDBC adapters, not the databases themselves.
Different yaml examples are included for the embedded HyperSQL database and external databases. Use the one that's right for your environment.
Warning: For NFS, the exported directory must have the same UID and GID as the Parasoft user that runs the container. For example, execute the command chown 1000:1000 <shared_path>.
HyperSQL (Embedded)
apiVersion: v1
kind: PersistentVolume
metadata:
name: ctp-hsqldb-storage
namespace: parasoft-ctp-namespace
spec:
capacity:
storage: 50Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: <path>
server: <ip_address>
---
# PersistentVolumeClaim for CTP HyperSQL DB
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ctp-hsqldb-pvc
namespace: parasoft-ctp-namespace
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs
resources:
requests:
storage: 50Gi
External Database (MariaDB, MySQL, Oracle, or PostgreSQL)
# ==== Persistent Volume for JDBC Adapter
apiVersion: v1
kind: PersistentVolume
metadata:
name: ctp-jdbcadapter-storage
namespace: parasoft-ctp-namespace
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: <path>
server: <ip_address>
---
# ==== PersistentVolumeClaim for JDBC Adapter ====
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ctp-jdbcadapter-pvc
namespace: parasoft-ctp-namespace
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs
resources:
requests:
storage: 1Gi
volumeName: "ctp-jdbcadapter-storage"
Use the yaml file to create a Persistent Volume and a Persistent Volume claim:
kubectl create -f ctp-hsqldb.yaml
kubectl create -f ctp-jdbc.yaml
You can configure an OIDC secret for CTP. This step is optional.
apiVersion: v1
kind: Secret
metadata:
name: ctp-oidc-secret
namespace: parasoft-ctp-namespace
type: Opaque
stringData:
oidc_json: |
{
"enabled": false,
"issuerUri": "your issuer uri",
"clientId": "your client id",
"clientSecret": your client secret",
"scopes": ["openid", "profile", "email"],
"claimMappings": {
"username": "preferred_username",
"firstName": "given_name",
"lastName": "family_name",
"email": "email"
},
"adminUsers": ["your admin user"]
}
Then create the secret with the command:
kubectl create -f ctp-oidc-secret.yaml
You also need to create the service account and required permissions.
apiVersion: v1 kind: ServiceAccount metadata: name: parasoft-account namespace: parasoft-ctp-namespace automountServiceAccountToken: true --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: parasoft-read namespace: parasoft-ctp-namespace rules: - apiGroups: - "" resources: - "namespaces" - "pods" verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: parasoft-read-bind namespace: parasoft-ctp-namespace roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: parasoft-read subjects: - kind: ServiceAccount name: parasoft-account namespace: parasoft-ctp-namespace
Use your yaml file to create the service account and required permissions:
kubectl create -f parasoft-permissions.yaml
You should see something similar to the output below in your console:
serviceaccount/parasoft-account created role.rbac.authorization.k8s.io/parasoft-read created rolebinding.rbac.authorization.k8s.io/parasoft-read-bind created
CTP Deployment
Once the prerequisites have been met, you can deploy CTP in Kubernetes. If custom Persistent Volume Claim names were used in previous steps, make sure to update the appropriate 'volumeMounts:name' and 'claimName' fields to match the custom name. Uncomment the sections for the database you are using.
The server EULA must be accepted by setting the ACCEPT_EULA value to "true" in the -env specifier. Additionally, to opt-in to sending anonymous usage data to Parasoft to help improve the product, change the USAGE_DATA value to "true" in the -env specifier.
Note: kind: Deployment is not supported. Use either kind: Pod or kind: StatefulSet, which are supported.
apiVersion: v1
kind: Pod
metadata:
name: ctp-pod
namespace: parasoft-ctp-namespace
labels:
app: ctp
spec:
securityContext:
runAsNonRoot: true
serviceAccountName: parasoft-account
automountServiceAccountToken: true
containers:
- name: ctp
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
image: parasoft/ctp:latest
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8443
# Delete database.properties file to prevent overwriting of db_config.xml on pod startup
command: [ "/bin/bash", "-c" ]
args:
-
cd ctp/webapps/em/WEB-INF/classes/META-INF/spring/ &&
rm database.properties &&
cd /usr/local/parasoft &&
./entrypoint.sh
volumeMounts:
- name: ctp-exports-storage
mountPath: /usr/local/parasoft/exports
# === db_config.xml Secret Volume Mount ===
- name: "ctp-db-config-secret-volume"
mountPath: /usr/local/parasoft/ctp/webapps/em/config/db_config.xml
subPath: db_config.xml
readOnly: true
# - name: ctp-hsqldb-storage
# mountPath: /usr/local/parasoft/ctp/hsqldb
# === DB JDBC Adapter Volume Mount ===
# - name: ctp-jdbcadapter-storage
# mountPath: /usr/local/parasoft/ctp/webapps/em/WEB-INF/lib/<JAR_FILE>
# subPath: <JAR_FILE>
# === OIDC Secret Volume Mount ===
# - name: ctp-oidc-secret-volume
# mountPath: /usr/local/parasoft/ctp/webapps/em/config/oidc.json
# subPath: oidc.json
# readOnly: true
env:
# === USE BELOW TO CONFIGURE ENVIRONMENT VARIABLES ===
# Configures CTP to connect to license server at the specified base URL
- name: LICENSE_SERVER_URL
value: https://licenseserver:8443
# Configures CTP to use basic authentication when connecting to license server
- name: LICENSE_SERVER_AUTH_ENABLED
value: "false"
# Configures CTP to connect to license server as the specified user
# - name: LICENSE_SERVER_USERNAME
# value: admin
# Configures CTP to connect to license server with the specified password
# - name: LICENSE_SERVER_PASSWORD
# value: admin
# Set to true or false to opt-in or opt-out of sending anonymous usage data to Parasoft
- name: USAGE_DATA
value: "false"
# Accepts the End User License Agreement if set to true
- name: ACCEPT_EULA
value: "false"
- name: CATALINA_OPTS
value: "-Dparasoft.cloudvm=true
-Dparasoft.cloudvm.config=Kubernetes"
- name: PARASOFT_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: PARASOFT_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
# === PROBES ===
startupProbe:
httpGet:
path: /em/resources/favicon.ico
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 30
failureThreshold: 3
livenessProbe:
httpGet:
path: /em/resources/favicon.ico
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 30
readinessProbe:
httpGet:
path: /em/healthcheck
port: 8080
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 30
volumes:
- name: ctp-exports-storage
persistentVolumeClaim:
claimName: ctp-exports-pvc
# === db_config.xml Secret Volume ===
- name: "ctp-db-config-secret-volume"
secret:
secretName: "ctp-db-config-secret"
optional: true
items:
- key: db_config_xml
path: db_config.xml
# - name: ctp-hsqldb-storage
# persistentVolumeClaim:
# claimName: ctp-hsqldb-pvc
# === SQL JDBC Adapter Volume ===
# - name: ctp-jdbcadapter-storage
# persistentVolumeClaim:
# claimName: ctp-jdbcadapter-pvc
# === OIDC Secret Volume ===
# - name: ctp-oidc-secret-volume
# secret:
# secretName: ctp-oidc-secret
# optional: true
# items:
# - key: oidc_json
# path: oidc.json
Use the yaml file to create service that can be used to access CTP in Kubernetes:
kubectl create -f ctp-pod.yaml
Create the service that can be used to access the CTP server in Kubernetes. The example shown below exposes it using a node port, which provides a stable endpoint for applications to access.
apiVersion: v1
kind: Service
metadata:
name: ctp-service
namespace: parasoft-ctp-namespace
spec:
selector:
app: ctp
type: NodePort
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30000
- name: https
protocol: TCP
port: 8443
targetPort: 8443
nodePort: 30083
Volume Mount Security Policies (Optional)
If your security policy requires applications to only write to mounted volumes, then you will need to mount the following locations:
/usr/local/parasoft/exports /usr/local/parasoft/ctp/hsqldb /usr/local/parasoft/ctp/logs /usr/local/parasoft/ctp/temp /usr/local/parasoft/ctp/webapps/em/apifiles /usr/local/parasoft/ctp/webapps/em/backups /usr/local/parasoft/ctp/webapps/em/license /usr/local/parasoft/ctp/work/Catalina/localhost/em