| Products | Versions |
|---|---|
| TIBCO Streaming | 11.1 and later |
StreamBase projects follow standard Maven conventions and can be integrated into most enterprise CI/CD platforms and orchestrators (Jenkins, GitLab CI, GitHub Actions, Azure DevOps, etc.). The integration process involves automated builds, testing, containerization, and deployment of fragments and StreamBase Applications.
A typical CI/CD pipeline for StreamBase includes these stages:
These should not be confused with Maven targets or phases, even though specific Maven commands are useful for each stage. For example:
Each stage is typically scripted to conform to the expectations of the build orchestrator, and are integrated into the pipeline by running those scripts.
For example, the Build stage for a Streaming application is simply implemented by the command: mvn install -DskipTests
The Test stage may be: mvn test
The Deploy stage may be a script with steps: mvn deploy -DskipTests cd {deployment environment} cp my_app-ef-application-1.0.0.zip {execution environment} epadmin install node nodename=A.X application=my_app-ef-application-1.0.0.zip adminport=22000 epadmin adminport=22000 start node
Note, the Maven 'deploy' target requires specific configuration in the pom.xml file, for example:
<distributionManagement>
<repository>
<id>releases</id>
<url>https://repo.example.com/releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>https://repo.example.com/snapshots</url>
</snapshotRepository>
</distributionManagement>
When deploying to remote repositories, configure authentication credentials in the local Maven local repository file, settings.xml .
Before setting up your CI/CD pipeline, ensure you have:
pom.xml filesStructure your StreamBase project repository to support CI/CD:
pom.xml defining common build properties and dependenciespom.xmltarget/, .settings/, bin/, and build artifactsREADME.md with build and deployment instructions or make use of the project src/site/site.xml to structure markdown into HTML documentation.Example Version Control repository structure:
my-streambase-project/
├── pom.xml (parent POM of type "pom" with <module> references)
├── README.md
├── .gitignore
├── my-fragment-1/
│ ├── pom.xml (POM with no project <dependencies>)
│ └── ...
├── my-fragment-2/
│ ├── pom.xml (POM with <dependency> on "my-fragment-1")
│ └── ...
└── my-application/
├── pom.xml (POM with <dependency> on "my-fragment-2" but not "my-fragment-1")
├── src/
└── ...
The build stage compiles EventFlow modules, custom Java code, and resolves dependencies.
Execute these Maven goals in sequence for a complete build:
mvn clean -- Remove previous build artifacts from target/ folder and stops and removes test nodesmvn compile -- Compile all sources to classes in target/ foldermvn install -DskipTests -- Combine all artifacts into JAR and ZIP files in the local Maven repository-DskipTests - Use -DskipTests to prevent running tests during this phase (recommended). Remove this flag to run tests so that test failures are logged with the installed version.Combined command for a typical automated CI/CD pipeline: mvn clean install -DskipTests -B -q
-B -- Batch mode (no interactive prompts)-q -- Quiet mode (minimal output)Developers are advised to interactively use: mvn install -DskipTests. This displays any errors, avoids running unnecessary tests, and does not recompile classes that are already built from non-dirtied sources.
This is an example of optional configuration and usage. Other build orchestrators will also have patterns for running Maven or shell scripts which can call Maven to perform the build.
See the Jenkins Pipeline example for Maven here: https://www.jenkins.io/doc/pipeline/examples/#maven-and-jdk-specific-version
Supply the paths to the Streaming JDK and Streaming installed Maven (example): {TIBCO_HOME}/str/11.3/jdk/bin {TIBCO_HOME}/str/11.3/sdk/mvn/bin
To deploy only into the local repository replace the shown 'mvn' command with the combined command shown above: mvn clean install -DskipTests -B -q Otherwise to deploy into a remote repository, use the deploy target as shown in the example. The project POM must supply <repository> configuration and the local Maven settings.xml file must supply authentication credentials to use that repository.
Configure your pipeline to halt immediately on build failure:
target/ directories, and Maven outputInclude automated testing to validate EventFlow logic and custom adapters before deployment.
StreamBase supports JUnit 4 and JUnit 5 for testing custom operators and adapters. Run tests as part of the build: mvn test Or include tests in the install phase: mvn install -B -q (omitting -DskipTests allows tests to run)
Configure your pom.xml to generate test reports:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<reportFormat>plain</reportFormat>
</configuration>
</plugin>
Collect test results from target/surefire-reports/ and make them visible in your CI/CD dashboard.
For EventFlow applications, consider:
The Maven build produces a .zip (StreamBase Application) archive. This is the deployable artifact containing the application and all fragments. After mvn install, the archive is located in the active project at: target/my-application-1.0.0-ep-application.zip
Archive this artifact in your build repository (Artifactory, Nexus, etc.) for later deployment:
For containerized deployments, build Docker container images from the StreamBase Application archive:
Create a Dockerfile in your application project that packages the .zip archive. Reference the Docker Dockerfile guide for details.
Build the image in your CI/CD pipeline:docker build -t my-app:$BUILD_VERSION .
Tag the image for your registry:docker tag my-app:$BUILD_VERSION my-registry.example.com/my-app:$BUILD_VERSION docker tag my-app:$BUILD_VERSION my-registry.example.com/my-app:latest
Push the image(s) to your container registry:docker push my-registry.example.com/my-app:$BUILD_VERSIONdocker push my-registry.example.com/my-app:latest
Ensure your build agent has authenticated access to the container registry before pushing.
For traditional deployments to StreamBase nodes:
epadmin --host targethost --adminport 5005 stop node
epadmin --host targethost --adminport 5005 remove node
.zip archive to the target host (via SCP, artifact repository, etc.) epadmin --host targethost --adminport 5005 install node--application /path/to/app.zip
epadmin --host targethost --adminport 5005 start node
For automated deployment, wrap these commands in a shell script and invoke it from your CI/CD pipeline. Use SSH key-based authentication for epadmin connections.
Please see the documentation and tutorials for creating container images found in the documentation here:
TIBCO Streaming > StreamBase Admin Guide > Cloud
StreamBase Applications encapsulated in containers can be integrated into Kubernetes, with or without Helm control, and can by uploaded to an Image Registry, for example Docker Hub, or to a site-specific image registry.
For current configuration examples, see the Docker sample projects available in Studio by importing samples from:
TIBCO Supported Samples > Docker: Samples
The sample configuration will be more current than the examples shown below for reference.
Product Activation configuration for container deployments is described in the product documentation here:
TIBCO Streaming > Welcome Guide > Activation in TIBCO Streaming and Model Management Server, Streaming Maven Archetypes
For Kubernetes deployments, use the built container image:
# ConfigMap for configuration
#
apiVersion: v1
kind: ConfigMap
metadata:
name: my-streambase-app-configuration
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app-configuration
data:
---
#
# ConfigMap for resources
#
apiVersion: v1
kind: ConfigMap
metadata:
name: my-streambase-app-resources
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app-resources
data:
---
#
# use a cluster role to allow the application to access the Kubernetes API
#
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: my-streambase-app-cr
rules:
- apiGroups: [""]
resources: ["services", "pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
#
# Service account to install and run the pods with
#
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-streambase-app-sa
---
#
# use a cluster role binding to bind the cluster role to the above service account
#
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-streambase-app-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: my-streambase-app-cr
subjects:
- kind: ServiceAccount
name: my-streambase-app-sa
namespace: az-datastreams
---
#
# application cluster as a stateful set
#
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-streambase-app
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app
spec:
selector:
matchLabels:
app: my-streambase-app
serviceName: my-streambase-app
#
# initially 2 eventflow nodes in the cluster
# can be scaled up or down
#
replicas: 2
#
# start all pods at the same time
#
podManagementPolicy: Parallel
#
# Enable rolling updates
#
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: my-streambase-app
app.kubernetes.io/part-of: my-streambase-app
spec:
serviceAccountName: my-streambase-app-sa
securityContext:
fsGroup: 1000
volumes:
- name: configuration
configMap:
name: my-streambase-app-configuration
- name: resources
configMap:
name: my-streambase-app-resources
- name: my-streambase-app-tmp
emptyDir: {}
- name: my-streambase-app-node
emptyDir: {}
containers:
- name: my-streambase-app
#
# docker image to use
#
image: my-registry.example.com/my-app:$BUILD_VERSION
imagePullPolicy: Always
#
# mount the configuration and resources volumes
#
volumeMounts:
- name: configuration
mountPath: /var/opt/tibco/streambase/configuration
- name: resources
mountPath: /var/opt/tibco/streambase/resources
- name: my-streambase-app-tmp
mountPath: /tmp
- name: my-streambase-app-node
mountPath: /var/opt/tibco/streambase/node
#
# Share application logs to docker console
#
tty: true
#
# set Streaming node name
#
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: APPNAME
value: my-streambase-app
- name: STREAMING_NODENAME
value: "$(POD_NAME).$(APPNAME)"
#
# set the application to run as user 1000
#
securityContext:
runAsUser: 1000
readOnlyRootFilesystem: true
#
# use a startup probe to wait for the application to be ready
#
startupProbe:
exec:
command:
- /bin/sh
- -c
- touch /tmp/healthy; cat /tmp/healthy
initialDelaySeconds: 20
failureThreshold: 30
periodSeconds: 10
#
# use healthcheck API for an initial wait until the application is ready
#
readinessProbe:
httpGet:
path: /healthcheck/v1/status
port: 8008
initialDelaySeconds: 60
periodSeconds: 10
#
# use healthcheck API for on-going health
#
livenessProbe:
httpGet:
path: /healthcheck/v1/status
port: 8008
initialDelaySeconds: 240
periodSeconds: 10
#
# set resource limits
#
resources:
limits:
cpu: '4'
memory: 4Gi
requests:
cpu: '2'
memory: 2Gi
#
# attempt tidy-shutdown to remove discovery service objects
#
lifecycle:
preStop:
exec:
command: ["/bin/sh","-c","/opt/tibco/streambase/stop-node"]
kubectl apply-f deployment.yaml
See Kubernetes and EventFlow for more information on Kubernetes deployment.
A Helm deployment of Streaming application images provides greater flexibility in managing local license files.
For helm deployments, use the built container image:
{{- if .Values.containerLicenseDirectory }}
#
# Secret for license files
#
apiVersion: v1
kind: Secret
metadata:
name: my-streambase-app-license-files
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app-license-files
type: Opaque
data:
{{ (.Files.Glob "licenses/*").AsSecrets | indent 2 }}
---
{{- end }}
#
# ConfigMap for license configuration
#
apiVersion: v1
kind: ConfigMap
metadata:
name: my-streambase-app-license-configuration
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app-license-configuration
data:
license.conf: |-
{{ .Files.Get "license.conf" | indent 4 }}
---
#
# ConfigMap for configuration
#
apiVersion: v1
kind: ConfigMap
metadata:
name: my-streambase-app-configuration
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app-configuration
data:
---
#
# ConfigMap for resources
#
apiVersion: v1
kind: ConfigMap
metadata:
name: my-streambase-app-resources
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app-resources
data:
---
#
# use a cluster role to allow the application to access the Kubernetes API
#
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: my-streambase-app-cr
rules:
- apiGroups: [""]
resources: ["services", "pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
#
# Service account to install and run the pods with
#
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-streambase-app-sa
---
#
# use a cluster role binding to bind the cluster role to the above service account
#
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-streambase-app-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: my-streambase-app-cr
subjects:
- kind: ServiceAccount
name: my-streambase-app-sa
namespace: {{ .Release.Namespace }}
---
{{- if eq .Values.cloudPlatform "openshift" }}
#
# On openshift, create an scc allowing the stateful set's pods to run as a specific user
#
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
name: my-streambase-app-scc
annotations:
"helm.sh/hook": "pre-install"
"helm.sh/hook-weight": "0"
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegedContainer: false
readOnlyRootFilesystem: true
allowedCapabilities: null
runAsUser:
type: RunAsAny
seLinuxContext:
type: MustRunAs
fsGroup:
type: RunAsAny
supplementalGroups:
type: RunAsAny
---
#
# CR for using the SCC
#
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:openshift:scc:my-streambase-app-scc
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- my-streambase-app-scc
resources:
- securitycontextconstraints
verbs:
- use
---
#
# Bind the SCC to the service account
#
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:openshift:scc:my-streambase-app-scc
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:openshift:scc:my-streambase-app-scc
subjects:
- kind: ServiceAccount
name: my-streambase-app-sa
namespace: {{ .Release.Namespace }}
---
{{- end }}
#
# application cluster as a stateful set
#
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-streambase-app
labels:
app.kubernetes.io/part-of: my-streambase-app
app.kubernetes.io/name: my-streambase-app
spec:
selector:
matchLabels:
app: my-streambase-app
serviceName: my-streambase-app
#
# initially 1 eventflow nodes in the cluster
# can be scaled up or down
#
replicas: {{ .Values.replicaCount }}
#
# start all pods at the same time
#
podManagementPolicy: Parallel
#
# Enable rolling updates
#
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: my-streambase-app
app.kubernetes.io/part-of: my-streambase-app
spec:
serviceAccountName: my-streambase-app-sa
securityContext:
fsGroup: 1000
volumes:
{{- if .Values.containerLicenseDirectory }}
- name: license-files
secret:
secretName: my-streambase-app-license-files
{{- end }}
- name: license-configuration
configMap:
name: my-streambase-app-license-configuration
- name: configuration
configMap:
name: my-streambase-app-configuration
- name: resources
configMap:
name: my-streambase-app-resources
- name: my-streambase-app-tmp
emptyDir: {}
- name: my-streambase-app-node
emptyDir: {}
containers:
- name: my-streambase-app
#
# docker image to use
#
{{- if .Values.containerRegistry }}
image: {{ .Values.containerRegistry }}/my-streambase-app:0.0.1-SNAPSHOT
{{- else}}
image: my-streambase-app:0.0.1-SNAPSHOT
{{- end }}
imagePullPolicy: Always
#
# mount the configuration and resources volumes
#
volumeMounts:
{{- if .Values.containerLicenseDirectory }}
- name: license-files
mountPath: {{ .Values.containerLicenseDirectory }}
{{- end }}
- name: license-configuration
mountPath: /var/opt/tibco/streambase/license-configuration
- name: configuration
mountPath: /var/opt/tibco/streambase/configuration
- name: resources
mountPath: /var/opt/tibco/streambase/resources
- name: my-streambase-app-tmp
mountPath: /tmp
- name: my-streambase-app-node
mountPath: /var/opt/tibco/streambase/node
#
# Share application logs to docker console
#
tty: true
#
# set Streaming node name
#
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: APPNAME
value: my-streambase-app
- name: STREAMING_NODENAME
value: "$(POD_NAME).$(APPNAME)"
- name: STREAMING_LICENSECONFIGURATION
value: /var/opt/tibco/streambase/license-configuration/license.conf
#
# set the application to run as user 1000
#
securityContext:
runAsUser: 1000
readOnlyRootFilesystem: true
#
# use a startup probe to wait for the application to be ready
#
startupProbe:
exec:
command:
- /bin/sh
- -c
- touch /tmp/healthy; cat /tmp/healthy
initialDelaySeconds: 20
failureThreshold: 30
periodSeconds: 10
#
# use healthcheck API for an initial wait until the application is ready
#
readinessProbe:
httpGet:
path: /healthcheck/v1/status
port: 8008
initialDelaySeconds: 60
periodSeconds: 10
#
# use healthcheck API for on-going health
#
livenessProbe:
httpGet:
path: /healthcheck/v1/status
port: 8008
initialDelaySeconds: 240
periodSeconds: 10
#
# set resource limits
#
resources:
limits:
cpu: '4'
memory: 4Gi
requests:
cpu: '2'
memory: 2Gi
#
# attempt tidy-shutdown to remove discovery service objects
#
lifecycle:
preStop:
exec:
command: ["/bin/sh","-c","/opt/tibco/streambase/stop-node"]
---
#
# Horizontal Pod Autoscaler
#
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-streambase-app-hpa
namespace: {{ .Release.Namespace }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: my-streambase-app
minReplicas: 1
maxReplicas: 3
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
helm install <release-name> ./path/to/chart-directory
After deployment, validate that the application is running correctly:
Use epadmin to verify the node and its engines are running and healthy:
Display node-level information:
epadmin --host targethost --port 5005 display node
Display engine-level information:
epadmin --host targethost --port 5005 display engine
Expected output includes:
RUNNINGRUNNINGRUNNINGFor a failed deployment, the node will show STOPPED or specific engines will be FAILED. Check node logs for error details.
Run lightweight smoke tests to verify application functionality:
Script these tests using the Streaming administration utility (e.g. epadmin --adminport=nodePortNumber enqueue stream ...) or REST API calls, and run them from your CI/CD pipeline after deployment completes.
If post-deployment validation fails, have a rollback plan:
.zip archive and use epadmin to restart the previous versionkubectl rollout undoThis article describes the recommended approach for integrating StreamBase projects into continuous integration and continuous deployment (CI/CD) pipelines, including build automation, testing strategies, and deployment practices.
Contents
Overview
Prerequisites
Version Control Setup
Build Stage Configuration
Testing Strategy
Artifact and Container Management
Deployment Stage
Post-Deployment Validation
Best Practices