WorkflowGen Helm Chart

Overview

This section presents the WorkflowGen Helm chart including usage, configuration options, and examples. Using the WorkflowGen chart simplifies the deployment of WorkflowGen in a Kubernetes cluster by not having to manage many Kubernetes deployment files. You only have to manage one "values" file.

Prerequisites

  • You must have a working Kubernetes cluster with Windows Server 2019 nodes.

  • You must have installed the kubectl command line tool and it must be connected to the cluster.

  • You must have installed the helm command line tool. See the Installing Helm section on the Helm website for instructions on how to install it. Only the Helm version 3.0+ is supported.

Helm chart primer

From the Helm website:

A chart is a collection of files that describe a related set of Kubernetes resources.

These resources are written in YAML in the chart with the help of the Go templating language. This enables the chart to generate valid Kubernetes resource definition files based on values provided by the user of the chart. Therefore, when you use the chart to install or upgrade WorkflowGen, you can provide some values that will help you deploy the correct resources for WorkflowGen.

A chart has a manifest file called Chart.yaml. It has a version for the chart and a version for the application. For example, the chart version of WorkflowGen could be 0.0.3 and its application version 7.18.3. A chart also has a kubeVersion that tells which versions of Kubernetes are supported. In the case of WorkflowGen, only versions 1.14 and higher are supported since it is the first version to include Windows containers support.

You install a chart using the command line. For example:

helm install --set image.tag=7.15.5-win-ltsc2019 release-name ./chart-path

This will install the chart that is at the path ./chart-path in the cluster with the release name release-name. It also sets a the value image.tag to 7.15.5-win-ltsc2019. More information about the install command including its --set parameter can be found in Helm Install on the Helm website.

While useful for a few parameters, setting values from the command line can be cumbersome and prone to errors, which is why you can also set values from a YAML or JSON file. The first thing you need to do is to create the file:

YAML
JSON
YAML
image:
tag: 7.15.5-win-ltsc2019
JSON
{
"image": {
"tag": "7.15.5-win-ltsc2019"
}
}

Then, you can pass that file to the install command:

# YAML
helm install --set-file ./my-values.yaml release-name ./chart-path
# JSON
helm install --set-file ./my-values.json release-name ./chart-path

WorkflowGen values

The following are all of the value names supported by the WorkflowGen chart and their default values. They are accompanied by a brief description.

# Default values for WorkflowGen.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# replicaCount Number of replicas to create per deployment of WorkflowGen. Doesn't impact database.
replicaCount: 1
# scalable Deploy WorkflowGen and its database in a scalable architecture.
scalable: true
# tenantName For multi-tenancy, it is recommended to populate this value in a multi-tenant architecture. This name will be put as a prefix for resources' name and the label "workflowgen.com/tenant: tenantName" will be added as a selector label.
tenantName: ""
# workflowgen Configuration related to the WorkflowGen pod.
workflowgen:
# image Configuration related to the image to be used for the WorkflowGen pod.
image:
# repository The repository to use to pull the image.
repository: advantys/workflowgen
# tag The image tag to use.
tag: ""
# pullPolicy The pull policy to adopt for this image.
pullPolicy: Always
# nameOverride Override the name of the chart.
nameOverride: ""
# fullnameOverride Override the name of the WorkflowGen deployment. It is based on the name by default.
fullnameOverride: ""
# runtimeClassName Runtime class to use with the deployment.
runtimeClassName: ""
# strategy The update strategy for the WorkflowGen deployment.
strategy:
type: Recreate
# nodeSelector Node selectors to use for the WorkflowGen pod. WorkflowGen only works on Windows Server.
nodeSelector:
kubernetes.io/os: windows
# annotations Annotations to attach to the WorkflowGen deployment. You can attach annotations to the deployment itself or its template.
annotations: {}
# deployment: {}
# template: {}
# tolerations Tolerations to apply to the WorkflowGen pod.
tolerations: []
# affinity Affinities to apply to the WorkflowGen pod.
affinity: {}
# createConfigMap Create a ConfigMap for WorkflowGen's configuration.
createConfigMap: true
# configMapNameOverride Override the name of WorkflowGen's ConfigMap.
configMapNameOverride: ""
# config The configuration to put in the ConfigMap.
config: {}
# createSecret Create a Secret for WorkflowGen's secret values.
createSecret: true
# secretNameOverride Override the name of WorkflowGen's Secret.
secretNameOverride: ""
# secretMountPath The mount path inside WorkflowGen's containers where to put the secret files.
secretMountPath: C:\secrets
# secret The secret values to put in the Secret object. Values will be automatically endoded in base64.
secret: {}
# license Configuration related to WorkflowGen's license.
license:
# volumeNameOverride Override the name of the license's volume.
volumeNameOverride: ""
# secretName The name of the secret that contains WorkfowGen's license.
secretName: ""
# items The specific items to use from the secret to inject in WorkflowGen's containers.
items: []
# - key: ""
# path: ""
# createDataPvc Create a PersistentVolumeClaim for the data volume of WorkflowGen.
createDataPvc: true
# dataPvcNameOverride Override the name of data's PersistentVolumeClaim.
dataPvcNameOverride: ""
# dataVolumeNameOverride Override the volume name associated to the PersistentVolumeClaim.
dataVolumeNameOverride: ""
# dataPvcSpec The data PersistentVolumeClaim specifications.
dataPvcSpec: {}
# accessModes:
# - ReadWriteMany
# storageClassName: storageclass
# resources:
# requests:
# storage: 4Gi
# additionalVolumes Additional volumes to attach to WorkflowGen's deployment.
additionalVolumes: []
# additionalVolumeMounts Additional volumes to mount in WorkflowGen's container.
additionalVolumeMounts: []
# podSecurityContext The security context of the pod.
podSecurityContext: {}
# fsGroup: 2000
# securityContext The security context of WorkflowGen's container.
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# runAsUserName: ContainerUser
# resources Configuration related to the resources of the container.
resources: {}
# limits:
# cpu: '1'
# memory: 2Gi
# requests:
# cpu: '1'
# memory: 2Gi
# service Configuration related to the service associated with WorkflowGen's deployment.
service:
# type The type of the service.
type: ClusterIP
# port The port exposed from the service.
port: 80
# clusterIP The cluster IP address to use.
clusterIP: ""
# winServices Configuration related to WorkflowGen's Windows Services deployment. Ignored when release not scalable.
winServices:
# nameOverride Override the chart name of this deployment.
nameOverride: ""
# runtimeClassName Runtime class to use with the deployment.
runtimeClassName: ""
# nodeSelector Node selectors to use for the WorkflowGen Windows Services pod. WorkflowGen only works on Windows Server.
nodeSelector:
kubernetes.io/os: windows
# annotations Annotations to attach to the WorkflowGen Windows services deployment.
annotations: {}
# fullnameOverride Override the name of the Windows services deployment.
fullnameOverride: ""
# tolerations Tolerations to apply to the WorkflowGen Windows services pod.
tolerations: []
# affinity Affinities to apply to the WorkflowGen Windows services pod.
affinity: {}
# podSecurityContext The security context of the pod.
podSecurityContext: {}
# fsGroup: 2000
# dirSync Configuration related to the directory synchronization Windows service container.
dirSync:
# securityContext The security context of the directory synchronization Windows service container.
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# runAsUserName: ContainerUser
# resources Configuration related to the resources of the container.
resources: {}
# limits:
# cpu: '1'
# memory: 2Gi
# requests:
# cpu: '1'
# memory: 2Gi
# engine Configuration related to the engine Windows service container.
engine:
# securityContext The security context of the engine Windows service container.
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# runAsUserName: ContainerUser
# resources Configuration related to the resources of the container.
resources: {}
# limits:
# cpu: '1'
# memory: 2Gi
# requests:
# cpu: '1'
# memory: 2Gi
# database Configuration related to the database deployment.
database:
# image Configuration related to the image to be used for the database pod.
image:
# repository The repository to use to pull the image.
repository: advantys/workflowgen-sql
# tag The image tag to use.
tag: ""
# pullPolicy The pull policy to adopt for this image.
pullPolicy: Always
# create Create a database deployment to be used with the WorkflowGen deployment.
create: true
# createConfigMap Create a ConfigMap for the database configuration.
createConfigMap: true
# configMapNameOverride Override the name of the database ConfigMap.
configMapNameOverride: ""
# config The configuration to put in the ConfigMap.
config: {}
# createSecret Create a Secret for the database secret values.
createSecret: true
# secretNameOverride Override the name of the database Secret.
secretNameOverride: ""
# secretMountPath The mount path inside the database container where to put the secret files.
secretMountPath: /mnt/secrets
# secret The secret values to put in the Secret object. Values will be automatically endoded in base64.
secret: {}
# useEnv Indicates to use additional environement variables.
useEnv: false
# env Definition of the environment variables.
env: []
# - name: test
# value: value
# - name: test2
# valueFrom:
# secretKeyRef:
# key: test-key
# name: secret-name
# For MSSQL Linux, you may want to put this here or in the config section:
# - name: MSSQL_PID
# value: Express # You can replace with the edition you want: "Enterprise" or "Developer" or "Express"
# fullnameOverride Override the name of the database deployment.
fullnameOverride: ""
# nameOverride Override the chart name of this deployment.
nameOverride: ""
# args The arguments to pass to the database container.
args: []
# tolerations Tolerations to apply to the database pod.
tolerations: []
# affinity Affinities to apply to the database pod.
affinity: {}
# runtimeClassName Runtime class to use with the stateful set.
runtimeClassName: ""
# nodeSelector Node selectors to use for the database pod.
nodeSelector: {}
# kubernetes.io/os: linux
# annotations Annotations to attach to the database deployment. You can add annotations for the StatefulSet or its template.
annotations: {}
# statefulset: {}
# template: {}
# podSecurityContext The security context of the pod.
podSecurityContext: {}
# fsGroup: 2000
# securityContext The security context of the database container.
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# runAsUserName: ContainerUser
# With MSSQL, you may want to use the mssql (10001) account
# runAsUser: 10001
# runAsGroup: 0
# If you can't configure the volumes with the correct permissions for mssql, you may want to run the container as root:
# runAsUser: 0
# runAsGroup: 0
# resources Configuration related to the resources of the container.
resources: {}
# limits:
# cpu: '1'
# memory: 2Gi
# requests:
# cpu: '1'
# memory: 2Gi
# volumeClaimTemplateSpec PersistentVolumeClaim specification for the StatefulSet PersistentVolumeClaimTemplate.
volumeClaimTemplateSpec: {}
# accessModes:
# - ReadWriteOnce
# storageClassName: default
# resources:
# requests:
# storage: 4Gi
# service Configuration related to the database cluster service.
service:
# type The type of the service.
type: ClusterIP
# port The port exposed from the service.
port: 1433
# clusterIP The cluster IP address to use.
clusterIP: None
# imagePullSecrets Secrets to inject in order to pull images from private repositories.
imagePullSecrets: []
# ingress Configuration related to the ingress rules.
ingress:
# enabled Whether or not to enable the ingress rules defined here.
enabled: true
# annotations Additional annotations to put on the Ingress object.
annotations: {}
# kubernetes.io/ingress.class: nginx
# cert-manager.io/cluster-issuer: letsencrypt
# kubernetes.io/tls-acme: "true"
# hosts List of hosts and routes for routing purposes.
hosts:
- host: chart-example.local
paths: []
# - host: example
# paths: []
# tls List of TLS hosts associated with a secret containing the proper TLS certificates.
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
# hooks Configuration related to the Helm hooks of this chart
hooks:
# preupgrade
preupgrade:
# enabled Enables the use of the pre-upgrade hook which will migrate WorkflowGen's data when upgrading.
enabled: true
# image Configuration related to the image to be used for the pre-upgrade pod.
image:
# repository The repository to use to pull the image.
repository: advantys/workflowgen-upgrade
# tag The image tag to use.
tag: ""
# args The arguments to pass to the migration container.
args: []
# env Definition of the environment variables.
env: []
# - name: test
# value: value
# - name: test2
# valueFrom:
# secretKeyRef:
# key: test-key
# name: secret-name
# connectionStringSecretKey The key to pick for the WFGEN_DATABASE_CONNECTION_STRING environment variable. Defaults to WFGEN_DATABASE_CONNECTION_STRING.
connectionStringSecretKey: ""
# secret The secret values to put in the Secret object for this hook. Values will be automatically endoded in base64.
secret: {}
# runtimeClassName The name of the RuntimeClass to use with this pod.
runtimeClassName: ""
# podSecurityContext The security context for the pod specification.
podSecurityContext: {}
# nodeSelector Node selectors to use for the pre-upgrade pod.
nodeSelector:
kubernetes.io/os: linux
# affinity Affinities to apply to the pre-upgrade pod.
affinity: {}
# tolerations Tolerations to apply to the pre-upgrade pod.
tolerations: []

The chart is divided in groups of configuration:

  • Global

  • WorkflowGen

  • WorkflowGen Windows services

  • Database

  • Ingress

  • Hooks

Global values

Global values control the overall deployment that results from the Helm generation. For example, the scalable value indicates if the resulting deployment should be scalable or not. If true, the resulting deployment will have a separate pod for the WorkflowGen Windows services that will be deployed using the Singleton deployment pattern. The WorkflowGen web services will be deployed with the number of replicas indicated by the replicaCount global value.If false, WorkflowGen web and Windows services will be deployed in a single pod using the Singleton pattern.

To deploy multiple WorkflowGen instances that must be isolated, the use of the tenantName value is recommended because it will prefix each object created by the installation with the name of the tenant and add a selector label named workflowgen.com/tenant=tenantName.

WorkflowGen & Windows services

The WorkflowGen part groups the configuration options related to the WorkflowGen web and Windows services pods when configuring the WorkflowGen product. For infrastructure-related configuration, configuration options are in separate groups in order to be able to properly deploy each part individually but still having the same WorkflowGen-specific configuration.

WorkflowGen configuration

There are two main ways to configure WorkflowGen with the chart: with the values file or by providing your own ConfigMap or Secret.

Helm
Manual
Helm

In your values file, you can use the sub YAML object workflowgen.config and workflowgen.secret to configure WorkflowGen's environment variables. Let's begin with an example:

workflowgen:
config:
WFGEN_APP_SETTING_ApplicationUrl: https://example.com/wfgen
WFGEN_APP_SETTING_ApplicationSerialNumber_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSerialNumber
WFGEN_DATABASE_CONNECTION_STRING_FILE: C:\secrets\WFGEN_DATABASE_CONNECTION_STRING
WFGEN_GEN_APP_SYM_ENCRYPT_KEY: 'N'
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey
secret:
WFGEN_DATABASE_CONNECTION_STRING: 'Server=some.sql.server.com,1433;...'
WFGEN_APP_SETTING_ApplicationSerialNumber: MY-WFG-LIC-NUMBER
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey: 1f73c842692f436b92411641c46fb338

Each key and value in the config part will be added as in a ConfigMap object and will be used by the WorkflowGen deployments. Concretely, the keys and values of the ConfigMap will be injected as environment variables in WorkflowGen's container. Each value must be of the string type. Therefore, YAML boolean values such as true, yes, and Y will be rejected. Use single or double quotes when needed, as in the example.

For secret values, you can do exactly like the config part. You only have to provide the name of the secret and its concrete value. The chart will add them to a Secret object and encode the value in Base64. The Secret object will then get injected as a volume inside WorkflowGen's container. Each key will become a file with its concrete value written inside it. Therefore, you need a corresponding config value that will tell the container to pick up the value in a specific file using the _FILE suffix. For more information about how to configure WorkflowGen including secrets, see the Configuration page in the WorkflowGen Image section. The default location of the secrets inside the container is C:\secrets. You can customize this path by providing the value workflowgen.secretMountPath.

Manual

You also have the option to use your own ConfigMap and Secret objects. Keep in mind that these objects will not be managed by Helm or the WorkflowGen chart. Here's the same example as for the "Helm" method:

Step 1: Create ConfigMap and Secret files

my-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-configmap
data:
WFGEN_APP_SETTING_ApplicationUrl: https://example.com/wfgen
WFGEN_APP_SETTING_ApplicationSerialNumber_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSerialNumber
WFGEN_DATABASE_CONNECTION_STRING_FILE: C:\secrets\WFGEN_DATABASE_CONNECTION_STRING
WFGEN_GEN_APP_SYM_ENCRYPT_KEY: 'N'
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey
my-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
WFGEN_DATABASE_CONNECTION_STRING: U2VydmVyPXNvbWUuc3FsLnNlcnZlci5jb20sMTQzMzsuLi4K
WFGEN_APP_SETTING_ApplicationSerialNumber: TVktV0ZHLUxJQy1OVU1CRVIK
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey: MWY3M2M4NDI2OTJmNDM2YjkyNDExNjQxYzQ2ZmIzMzgK

In the case of the secret, you have to encode the values in base64 yourself. For this, you can use the following code sample:

PowerShell

using namespace System.Text
function ConvertTo-Base64String {
[CmdletBinding()]
[OutputType([string])]
param (
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[string]$Value
)
process {
return [Convert]::ToBase64String([Encoding]::UTF8.GetBytes($Value))
}
}
'Server=some.sql.server.com,1433;...' | ConvertTo-Base64String # U2VydmVyPXNvbWUuc3FsLnNlcnZlci5jb20sMTQzMzsuLi4K
'MY-WFG-LIC-NUMBER' | ConvertTo-Base64String # TVktV0ZHLUxJQy1OVU1CRVIK
'1f73c842692f436b92411641c46fb338' | ConvertTo-Base64String # MWY3M2M4NDI2OTJmNDM2YjkyNDExNjQxYzQ2ZmIzMzgK

Bash

echo 'Server=some.sql.server.com,1433;...' | base64 # U2VydmVyPXNvbWUuc3FsLnNlcnZlci5jb20sMTQzMzsuLi4K
echo 'MY-WFG-LIC-NUMBER' | base64 # TVktV0ZHLUxJQy1OVU1CRVIK
echo '1f73c842692f436b92411641c46fb338' | base64 # MWY3M2M4NDI2OTJmNDM2YjkyNDExNjQxYzQ2ZmIzMzgK

Step 2: Create the objects from the files

Then, you have to deploy the objects by using the following command:

kubectl apply -f ./my-configmap.yaml
kubectl apply -f ./my-secret.yaml

Step 3: Reference the objects' names in the chart

The last step is to reference the objects that you've just deployed in your values file before installing:

my-values.yaml
workflowgen:
createConfigMap: false
configMapNameOverride: my-configmap
createSecret: false
secretNameOverride: my-secret

File storage

The chart generates a PersistentVolumeClaim (PVC) object based on values that you've provided. As with the WorkflowGen configuration, you can specify your own PVC outside of the chart and reference it.

Helm
Manual
Helm

In your values file, you can use the sub YAML object workflowgen.dataPvcSpec to configure the PersistentVolumeClaim for WorkflowGen's data (App_Data and wfapps). Let's begin with an example:

workflowgen:
dataPvcSpec:
accessModes:
- ReadWriteMany
storageClassName: azurefile
resources:
requests:
storage: 50Gi

The content of the object is exactly the Kubernetes PersistentVolumeClaim specification. What you write in there will be taken as-is in the object definition.

In this example, the storage class azurefile is specific to Azure Kubernetes Service.

Manual

You also have to option to use your own PVC object. Keep in mind that this object will not be managed by Helm or the WorkflowGen chart. Here's an example:

Step 1: Create the PersistentVolumeClaim definition file

my-wfg-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-wfg-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: azurefile
resources:
requests:
storage: 50Gi

Step 2: Deploy the definition into the cluster

kubectl apply -f ./my-wfg-pvc.yaml

Step 3: Reference the object in your values

The last step is to reference the objects that you've just deployed in your values file before installing:

workflowgen:
createDataPvc: false
dataPvcNameOverride: my-wfg-pvc

License

The license must be stored on the Kubernetes cluster before installing the chart. This is because it's more efficient to store it in a secret and inject it as a volume in the WorkflowGen pods instead of provisioning a file share and connecting it to the pods. For the chart to handle it, you need to specify the secret name where the license is stored and the license item name in the secret. Here's an example:

Step 1: Store your license in the cluster

The secret object must be in the same namespace as the WorkflowGen pods.

kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic

This command will create a secret named wfgen-license-secret with an item named WFG.lic and its value will be the content of the file.

Step 2: Reference this secret in the values file

workflowgen:
license:
secretName: wfgen-license-secret
items:
- key: WFG.lic
path: WFG.lic

For more information about how to inject files from a Secret object into pods, see Secrets in the Kubernetes documentation.

Custom image reference

To use your own WorkflowGen image, you can change the default reference like this:

workflowgen:
image:
reference: mycorporation/workflowgen
tag: 7.18.3-win-ltsc2019

Service

There is a service that is created by the chart with the WorkflowGen pod for its discovery. By default, the chart will create a ClusterIP service that provides a cluster-wide IP address and domain name that you can reference from anywhere in the cluster. This works best with an Ingress controller to route external traffic to it. For more information about Ingress controllers, see Ingress Controllers in the Kubernetes documentation.

You can customize this to automatically create a load balancer instead by providing the following value:

workflowgen:
service:
kind: LoadBalancer

The LoadBalancer type only works with cloud providers. For on-premise clusters, you should use another technique.

Security

There are many security features that are not yet supported or don't work in Windows but do in Linux. It's important to plan the security of the deployments. To know more about unsupported security features on Windows containers in Kubernetes, see Intro to Windows support in Kubernetes (Security section) in the Kubernetes documentation.

The web applications in the WorkflowGen container run as a user that is part of the IIS_IUSRS group. This is important for setting permissions for file storage. If this group doesn't have MODIFY permission on the files volume, the container will fail to write to the volume. Generally, you can set mount options for a persistent volume depending on the storage provider or you can run an init container to set the permissions. For Azure Files, see Dynamically create and use a persistent volume with Azure Files in Azure Kubernetes Service (AKS) to get the mount options.

There are many more options for customizing your Helm release. The majority of them are dependent on your cluster environment. They are all Kubernetes terms, so you can search for them in a search engine and get useful information. The only one that this section will discuss is resources. The resources YAML object allows you to limit and request resource consumption for a given pod. Requests are to help the scheduler to assign pods to nodes. Limits are to limit the amount of resources the pod can use. The following requests and limits are known to work well for WorkflowGen pods:

workflowgen:
resources:
limits:
cpu: '1'
memory: 2Gi
requests:
cpu: '1'
memory: 2Gi
# Used when "scalable: true"
winServices:
dirSync:
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '500M'
memory: 1Gi
engine:
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '500M'
memory: 1Gi

Keep in mind that Windows containers are a lot bigger in terms of storage, CPU, and memory consumption. Therefore, you'll probably need bigger Windows nodes than your Linux ones.

Database

The database part contains the values used to generate the deployment files for the WorkflowGen database StatefulSet and its related objects. It is an optional feature to deploy a database pod along with a WorkflowGen pod. You can disable the creation of the StatefulSet by setting the following values:

database:
create: false

Configuration

There are two main ways to configure the database with the chart: with the values file or by providing your own ConfigMap or Secret.

Helm
Manual
Helm

In your values file, you can use the sub YAML object database.config and database.secret to configure the environment variables of the database. Let's begin with an example:

database:
config:
ACCEPT_EULA: 'Y'
SA_PASSWORD_FILE: /mnt/secrets/SA_PASSWORD
WFGEN_DATABASE_USER_USERNAME_FILE: /mnt/secrets/WFGEN_DATABASE_USER_USERNAME
WFGEN_DATABASE_USER_PASSWORD_FILE: /mnt/secrets/WFGEN_DATABASE_USER_PASSWORD
WFGEN_ADMIN_PASSWORD_FILE: /mnt/secrets/WFGEN_ADMIN_PASSWORD
secret:
SA_PASSWORD: 'strong(!)Pass'
WFGEN_DATABASE_USER_PASSWORD: 'strong(!)Pass'
WFGEN_ADMIN_PASSWORD: 'strong(!)Pass'
WFGEN_DATABASE_USER_USERNAME: WFGEN_USER

Each key and value in the config part will be added as is in a ConfigMap object. It will be used by the StatefulSet. Concretely, the keys and values of the ConfigMap will get injected as environment variables in the database container. Each value must be of the string type. Therefore, YAML boolean values such as true, yes and Y will be rejected. Use single or double quotes when needed just like in the example.

For secret values, you can do exactly like the config part. You only have to provide the name of the secret and its concrete value. The chart will add them to a Secret object and encode the value in Base64. The Secret object will then get injected as a volume inside the database container. Each key will become a file with its concrete value written inside it. Therefore, you need a corresponding config value that will tell the container to pickup the value in a specific file using the _FILE suffix. For more information about how to configure WorkflowGen including secrets, see the Configuration page of the WorkflowGen database section. The default location of the secrets inside the container is /mnt/secrets. You can customize this path by providing the value database.secretMountPath.

The WorkflowGen database image is based on the SQL Server Linux image. It is the recommended image to use for production workloads. The Windows version of the image should only be used for development and test environments.

Manual

You also have the option to use your own ConfigMap and Secret objects. Keep in mind that these objects will not be managed by Helm or the WorkflowGen chart. Here's the same example as for the "Helm" method:

Step 1: Create ConfigMap and Secret files

my-db-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-db-configmap
data:
ACCEPT_EULA: 'Y'
SA_PASSWORD_FILE: /mnt/secrets/SA_PASSWORD
WFGEN_DATABASE_USER_USERNAME_FILE: /mnt/secrets/WFGEN_DATABASE_USER_USERNAME
WFGEN_DATABASE_USER_PASSWORD_FILE: /mnt/secrets/WFGEN_DATABASE_USER_PASSWORD
WFGEN_ADMIN_PASSWORD_FILE: /mnt/secrets/WFGEN_ADMIN_PASSWORD
my-db-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: my-db-secret
type: Opaque
data:
SA_PASSWORD: c3Ryb25nKCEpUGFzcwo=
WFGEN_DATABASE_USER_PASSWORD: c3Ryb25nKCEpUGFzcwo=
WFGEN_ADMIN_PASSWORD: c3Ryb25nKCEpUGFzcwo=
WFGEN_DATABASE_USER_USERNAME: V0ZHRU5fVVNFUgo=

In the case of the secret, you have to encode the values in base64 yourself. For this, you can .use the following code sample:

PowerShell

using namespace System.Text
function ConvertTo-Base64String {
[CmdletBinding()]
[OutputType([string])]
param (
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[string]$Value
)
process {
return [Convert]::ToBase64String([Encoding]::UTF8.GetBytes($Value))
}
}
'strong(!)Pass' | ConvertTo-Base64String # c3Ryb25nKCEpUGFzcwo=
'WFGEN_USER' | ConvertTo-Base64String # V0ZHRU5fVVNFUgo=

Bash

echo 'strong(!)Pass' | base64 # c3Ryb25nKCEpUGFzcwo=
echo 'WFGEN_USER' | base64 # V0ZHRU5fVVNFUgo=

Step 2: Create the objects from the files

Then, you have to deploy the objects by using the following command:

kubectl apply -f ./my-db-configmap.yaml
kubectl apply -f ./my-db-secret.yaml

Step 3: Reference the objects' names in the chart

The last step is to reference the objects that you've just deployed in your values file before installing:

my-values.yaml
database:
createConfigMap: false
configMapNameOverride: my-db-configmap
createSecret: false
secretNameOverride: my-db-secret

File storage

A StatefulSet needs a PersistentVolumeClaim template to generate a volume claim for each of its replicas. You can't use your own PVC this time because it is a template, not a concrete object. This template is part of the StatefulSet specification. Here's an example:

database:
volumeClaimTemplateSpec:
accessModes:
- ReadWriteOnce
storageClassName: default
resources:
requests:
storage: 100Gi

The content of the template is exactly the Kubernetes PersistentVolumeClaim spec. Anything you write will be added to the StatefulSet specification as-is. In this example, the access mode is ReadWriteOnly because the default storage class refers to an Azure Disk. Azure disks can only be bound to a single node and pod at a time. Physical disks are the preferred way to store database files for better performance. For more information about Azure Disks, see Dynamically create and use a persistent volume with Azure disks in Azure Kubernetes Service (AKS) in the Azure Kubernetes Service documentation.

Custom image reference

To use your own WorkflowGen database image, you can change the default reference like this:

database:
image:
reference: mycorporation/workflowgen-sql
tag: 7.18.3-ubuntu-18.04

Service

There is a service that is created by the chart with the database pod for its discovery. By default, the chart will create a ClusterIP service without a cluster IP address (clusterIP: None). This is called a headless service. It provides a way to get a cluster wide domain name to each pod of the StatefulSet. Therefore, you can refer directly to the database instance of your choice. It is recommended to leave the default values untouched. They are available in case you want to customize the service further. For more information about headless services in Kubernetes, see Service in its documentation.

Additionally, to make domain names predictable, you might want to override the full name of the StatefulSet, because the name is generated based on the chart's name and the release name, and you might not know the release name in advance. In this case, you can do the following:

database:
fullnameOverride: my-database

This will ensure that each pod in the StatefulSet has a unique domain name based on this name. If this release is in the default namespace, the first pod will have the domain name my-database-0.my-database.default.svc.cluster.local. You then reference this domain name in the connection string of the WorkflowGen configuration at port 1433 and it should connect successfully.

Security

Since the database image used is a Linux image by default, all of the security features are available. You can run the database with a non-root user and group. For more information about running the database container as a non-root user, see Configure SQL Server container images on Docker in the SQL Server documentation. Keep in mind that you also have to setup the permissions for the storage to be able to read and write into it. There is a section about this in the same documentation page as the non-root user information. You might want to use an init container to setup the permissions.

For more information about Docker security features, see Docker security in the Docker documentation. To find out how to configure these security features in Kubernetes, see Configure a Security Context for a Pod or Container in the Kubernetes documentation.

There are many more options you can customize your Helm release with. The majority of them are dependent on your cluster environment. They are all Kubernetes terms, so you can search for them in a search engine and get useful information. The only one that this section will discuss is resources. The resources YAML object allows you to limit and request resource consumption for a given pod. Requests are to help the scheduler to assign pods to nodes. Limits are to limit the amount of resources the pod can use. The following requests and limits are known to work well for database pods:

database:
resources:
limits:
cpu: '2'
memory: 4Gi
requests:
cpu: '1'
memory: 2Gi

Since WorkflowGen can only handle a main connection string and a read-only replica, you may want to limit the number of pods in the StatefulSet to two and scale vertically if you need more performance.

Ingress

The ingress section of the values is a simplified view of the complete Ingress object specification. It is optional to generate the Ingress rule object. To disable it, you can add the following values:

ingress:
enabled: false

Otherwise, here's an example of how to use the Ingress section:

ingress:
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt
hosts:
- host: &wfgenHost myinstance.example.com
paths:
- /
tls:
- secretName: tls-secret
hosts:
- *wfgenHost

This is a complete example on how to use it. In this example, there are annotations set to add some information on how to handle them. The ingress.class tells Kubernetes to use the Nginx ingress controller to handle this Ingress rule. The Nginx ingress controller must be installed in your cluster for the routing to work. For more information about the Nginx ingress controller, see the open source community project page or the commercial page. The two have different feature sets and are not developed by the same entity. The cert-manager.io/cluster-issuer annotation is a Cert-Manager specific annotation that tells it to use the letsencrypt cluster issuer for the TLS certificate. See the TLS/SSL page of this section for more information about cert-manager.

The hosts section is a list of domain names and where they lead in the container. In this case, when a user goes to myinstance.example.com, it will be routed to / on the WorkflowGen container which IIS will handle. The tls section tells what secret to use for what host. TLS certificates are stored in this secret.

Hooks

In Helm, there is a concept of hooks that enables the developer to deploy some resources (temporary or permanently) at different event in the lifecycle of a chart.

Pre-upgrade hook

The pre-upgrade hook deploys a Kubernetes Job that will add possible missing files and templates to your WorkflowGen database volume and migrate the database automatically. This deployment only occurs when you use the helm upgrade command. It will wait for the job to finish successfully before upgrading the WorkflowGen and database pods. This hook is optional and you can disable it by using the following values:

hooks:
preupgrade:
enabled: false

This pre-upgrade hook uses the WorkflowGen upgrade image to perform migrations. Here's a complete example to how to configure the hook:

hooks:
preupgrade:
image:
tag: latest-ubuntu-18.04
secret:
WFGEN_DATABASE_CONNECTION_STRING: 'Server=some.sql.server.com,1433;...'
mysecret: something secret
env:
- name: WFGEN_UPGRADE_EXCLUDE_FILES
value: file1,file2
- name: MY_SECRET_ENV
valueFrom:
secretKeyRef:
name: wfgen-migrations-secret # If release name is "wfgen"
key: mysecret
args:
- "-FromVersion"
- "7.14.10"
- "-ToVersion"
- "7.18.2"

There is no default tag specified for the image because both Windows and Linux versions of it are production-ready. For a better experience and performance, it is recommended to use the Linux version. The secret section of this example allows you to specify secret values to be put in a Secret object that will be deployed with the job. It will get deleted when the job is terminated. The name of the secret is generated from the release name. If your release name is wfgen, then the secret name will be wfgen-migrations-secret. The WFGEN_DATABASE_CONNECTION_STRING secret is required. It is automatically injected as an environment variable in the container. To customize the name of the secret to use for the upgrade container'sWFGEN_DATABASE_CONNECTION_STRING environment variable, you can populate the hooks.preupgrade.connectionStringSecretKey value. You can add your own environment variables as well.

The last part consists of the arguments to pass to the container. See Configuration for more information about configuring the WorkflowGen upgrade container.

Common scenarios

Deploying a simple WorkflowGen pod

Overview

Simple WorkflowGen pod deployment

This deployment is meant for a simple installation with a database deployed outside of the cluster. It will deploy a single WorkflowGen pod with all of its services including WorkflowGen Windows services. This diagram shows a high-level view of the objects that will be created when installing the release with the values given in the next part. This architecture is only vertically scalable. You can only scale up the limits of the pod to have a more performant instance.

How to deploy

First, create the values file:

my-values.yaml
scalable: false
workflowgen:
resources:
limits:
cpu: '1'
memory: '2Gi'
requests:
cpu: '1'
memory: '2Gi'
config:
WFGEN_APP_SETTING_ApplicationUrl: https://example.com/wfgen
WFGEN_APP_SETTING_ApplicationSerialNumber_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSerialNumber
WFGEN_DATABASE_CONNECTION_STRING_FILE: C:\secrets\WFGEN_DATABASE_CONNECTION_STRING
WFGEN_GEN_APP_SYM_ENCRYPT_KEY: 'N'
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey
secret:
WFGEN_DATABASE_CONNECTION_STRING: 'Server=some.sql.server.com,1433;...'
WFGEN_APP_SETTING_ApplicationSerialNumber: MY-WFG-LIC-NUMBER
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey: 1f73c842692f436b92411641c46fb338
license:
secretName: wfgen-license-secret
items:
- key: WFG.lic
path: WFG.lic
dataPvcSpec:
accessModes:
- ReadWriteMany
storageClassName: azurefile
resources:
requests:
storage: 50Gi
service:
type: LoadBalancer
database:
create: false
ingress:
enabled: false

Notes

  • MY-WFG-LIC-NUMBER is a placeholder value. You should replace it with your own serial number.

  • These values will create a LoadBalancer-type service. If you are on a cloud provider, it will deploy a resource in the cloud provider's specific load balancer service (e.g. Azure Load Balancer, AWS Elastic Load Balancer, etc).

  • These values assume that you own the example.com domain name and that it points to the load balancer's public IP address. In this particular case, the HTTPS means that the load balancer should work at network layer 7 and provide TLS termination. For more information about TLS handling in Kubernetes see the TLS/SSL page of this section.

  • The persistent volume claim that will be created assumes that you have a storage class already present in the cluster named azurefile. It is present by default on a Azure Kubernetes Service cluster. See Dynamically create and use a persistent volume with Azure Files in Azure Kubernetes Service (AKS) for more information.

Before installing a release of the chart, you have to create the WorkflowGen license secret object in your cluster. For this particular example, the name of the license file is WFG.lic and the name of the secret object is wfgen-license-secret. Execute the following command to create it:

kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic

With that done, you can now install the release:

helm install -f ./my-values.yaml wfgen https://github.com/advantys/workflowgen-releases/releases/download/7.18.2/workflowgen-0.0.3.tgz

The last argument is the path (or URL) to the WorkflowGen chart. You can use the URL directly or download it and use a local path. From this point, you should have a working WorkflowGen pod in your cluster.

Deploying a scalable WorkflowGen architecture

Scalable WorkflowGen pod deployment

This architecture is best suited for production workloads that have an external database. This deployment enables you to scale WorkflowGen web applications horizontally (by adding replicas), which has many benefits such as increased availability and performance. The WorkflowGen Windows services must be scaled vertically and cannot be scaled horizontally. Make sure to deploy that pod to a node that has sufficient resources.

How to deploy

my-values.yaml
replicaCount: 3
workflowgen:
resources:
limits:
cpu: '1'
memory: '2Gi'
requests:
cpu: '1'
memory: '2Gi'
config:
WFGEN_APP_SETTING_ApplicationUrl: https://example.com/wfgen
WFGEN_APP_SETTING_ApplicationSerialNumber_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSerialNumber
WFGEN_DATABASE_CONNECTION_STRING_FILE: C:\secrets\WFGEN_DATABASE_CONNECTION_STRING
WFGEN_GEN_APP_SYM_ENCRYPT_KEY: 'N'
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey_FILE: C:\secrets\WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey
secret:
WFGEN_DATABASE_CONNECTION_STRING: 'Server=some.sql.server.com,1433;...'
WFGEN_APP_SETTING_ApplicationSerialNumber: MY-WFG-LIC-NUMBER
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey: 1f73c842692f436b92411641c46fb338
license:
secretName: wfgen-license-secret
items:
- key: WFG.lic
path: WFG.lic
dataPvcSpec:
accessModes:
- ReadWriteMany
storageClassName: azurefile
resources:
requests:
storage: 50Gi
service:
type: LoadBalancer
winServices:
dirSync:
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '500M'
memory: 1Gi
engine:
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '500M'
memory: 1Gi
database:
create: false
ingress:
enabled: false

Notes

  • MY-WFG-LIC-NUMBER is a placeholder value. You should replace it with your own serial number.

  • These values will create a LoadBalancer-type service. If you are on a cloud provider, it will deploy a resource in the cloud provider's specific load balancer service (e.g. Azure Load Balancer, AWS Elastic Load Balancer, etc).

  • These values assume that you own the example.com domain name and that it points to the load balancer's public IP address. In this particular case, the HTTPS means that the load balancer should work at network layer 7 and provide TLS termination. For more information about TLS handling in Kubernetes see the TLS/SSL page of this section.

  • The persistent volume claim that will be created assumes that you have a storage class already present in the cluster named azurefile. It is present by default on a Azure Kubernetes Service cluster. See Dynamically create and use a persistent volume with Azure Files in Azure Kubernetes Service (AKS) for more information.

This is the same example as for the simple deployment, except that the scalable property is gone (true by default), the number of replicas is three, and there are resource requests and limits for the Windows services.

Before installing a release of the chart, you have to create the WorkflowGen license secret object in your cluster. For this particular example, the name of the license file is WFG.lic and the name of the secret object is wfgen-license-secret. Execute the following command to create it:

kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic

With this done, you can now install the release:

helm install -f ./my-values.yaml wfgen https://github.com/advantys/workflowgen-releases/releases/download/7.18.2/workflowgen-0.0.3.tgz

The last argument is the path (or URL) to the WorkflowGen chart. You can use the URL directly or download it and use a local path. From this point, you should have a working WorkflowGen pod in your cluster.

Deploying a scalable WorkflowGen architecture with a database container

Scalable architecture with a database container

This architecture is best suited for the complete automation experience and can help reduce costs by having the container inside the cluster instead of in an external environment. It is a scalable architecture where the WorkflowGen web applications can be scaled horizontally and vertically, the Windows Services can be scaled vertically only, and the WorkflowGen database can be scaled horizontally up to two replicas (read/write and read-only) and vertically.

How to deploy

replicaCount: 3
workflowgen:
resources:
limits:
cpu: '1'
memory: 2Gi
requests:
cpu: '1'
memory: 2Gi
config:
WFGEN_APP_SETTING_ApplicationUrl: http://10.0.1.1/wfgen
WFGEN_DATABASE_CONNECTION_STRING_FILE: C:\secrets\WFGEN_DATABASE_CONNECTION_STRING
WFGEN_APP_SETTING_ApplicationSerialNumber_FILE: C:\secrets\ApplicationSerialNumber
WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey_FILE: C:\secrets\ApplicationSecurityPasswordSymmetricEncryptionKey
WFGEN_MACHINE_KEY_DECRYPTION_KEY_FILE: C:\secrets\WFGEN_MACHINE_KEY_DECRYPTION_KEY
WFGEN_MACHINE_KEY_VALIDATION_KEY_FILE: C:\secrets\WFGEN_MACHINE_KEY_VALIDATION_KEY
secret:
ApplicationSerialNumber: <YOUR_WFG_LIC_KEY>
ApplicationSecurityPasswordSymmetricEncryptionKey: <YOUR_NEW_GUID>
WFGEN_DATABASE_CONNECTION_STRING: 'Server=wfgen-database-0.wfgen-database.default.svc.cluster.local,1433;Database=WFGEN;User ID=WFGEN_USER;Password=strong(!)Pass;'
WFGEN_MACHINE_KEY_DECRYPTION_KEY: '39B3AE9CCCF94AA47D795EC84F7CCB7928F5D59BE2EB2BBA4FE2AC0B3C8D0C85'
WFGEN_MACHINE_KEY_VALIDATION_KEY: '82F6247A5DBF8666FB60B8EFE6483360436F0EC426CC0351A9569C607B46C1FAD6497406DD8B0B519DD83CAA6764904C89999D742638ECE756E7C0B8799B45E9'
license:
secretName: wfgen-license-secret
items:
- key: WorkflowGen.lic
path: WorkflowGen.lic
dataPvcSpec:
accessModes:
- ReadWriteMany
storageClassName: azurefile
resources:
requests:
storage: 50Gi
service:
type: LoadBalancer
winServices:
dirSync:
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '500M'
memory: 1Gi
engine:
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '500M'
memory: 1Gi
database:
fullnameOverride: wfgen-database
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsUser: 0
runAsGroup: 0
resources:
limits:
cpu: '1'
memory: 2Gi
requests:
cpu: '500m'
memory: 1Gi
config:
ACCEPT_EULA: 'Y'
SA_PASSWORD_FILE: /mnt/secrets/SA_PASSWORD
WFGEN_DATABASE_USER_USERNAME_FILE: /mnt/secrets/WFGEN_DATABASE_USER_USERNAME
WFGEN_DATABASE_USER_PASSWORD_FILE: /mnt/secrets/WFGEN_DATABASE_USER_PASSWORD
WFGEN_ADMIN_PASSWORD_FILE: /mnt/secrets/WFGEN_ADMIN_PASSWORD
secret:
SA_PASSWORD: 'strong(!)Pass'
WFGEN_DATABASE_USER_PASSWORD: 'strong(!)Pass'
WFGEN_ADMIN_PASSWORD: 'strong(!)Pass'
WFGEN_DATABASE_USER_USERNAME: WFGEN_USER
volumeClaimTemplateSpec:
accessModes:
- ReadWriteOnce
storageClassName: default
resources:
requests:
storage: 100Gi
ingress:
enabled: false

Notes

  • MY-WFG-LIC-NUMBER is a placeholder value. You should replace it your own serial number.

  • These values will create a LoadBalancer-typer service. If you are on a cloud provider, it will deploy a resource in the cloud provider's specific load balancer service (e.g. Azure Load Balancer, AWS Elastic Load Balancer, etc).

  • These values assume that you own the example.com domain name and that it points to the public IP address of the load balancer. In this particular case, the HTTPS means that the load balancer should work at network layer 7 and provide TLS termination. For more information about TLS handling in Kubernetes see the TLS/SSL page of this section.

  • The persistent volume claim that will be created assumes that you have a storage class already present in the cluster named azurefile. It is present by default on a Azure Kubernetes Service cluster. See Dynamically create and use a persistent volume with Azure Files in Azure Kubernetes Service (AKS) for more information.

  • The persistent volume claim template that is used in the database part uses a storage class called default. It is present by default on a Azure Kubernetes Service cluster and represents the Azure Disks service. See Dynamically create and use a persistent volume with Azure disks in Azure Kubernetes Service (AKS) for more information.

This is the same example as before, except that a database section has been added. The security context specifies that the container should run as root. This should be avoided as a general security good practice. It is there for simplicity. You should always use a different user than root and check the permissions on the volumes, for example with an init container.

Before installing a release of the chart, you have to create the WorkflowGen license secret object in your cluster. For this particular example, the name of the license file is WFG.lic and the name of the secret object is wfgen-license-secret. Execute the following command to create it:

kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic

With this done, you can now install the release:

helm install -f ./my-values.yaml wfgen https://github.com/advantys/workflowgen-releases/releases/download/7.18.2/workflowgen-0.0.3.tgz

The last argument is the path (or URL) to the WorkflowGen chart. You can use the URL directly or download it and use a local path. From this point, you should have a working WorkflowGen pod in your cluster.