Only this pageAll pages
Powered by GitBook
1 of 27

7.14 to 7.22

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

WorkflowGen Image

Loading...

Loading...

Loading...

Loading...

Loading...

WorkflowGen Database Image

Loading...

Loading...

Loading...

WorkflowGen Upgrade Image

Loading...

Loading...

Kubernetes

Loading...

Loading...

Loading...

Loading...

Loading...

WorkflowGen for Docker

This guide provides instructions on how to set up, configure, deploy, and manage WorkflowGen integrations with Docker and Kubernetes.

Getting Started

Overview

This section presents how to quickly run the WorkflowGen container with a minimal architecture on your local machine.

There are known limitations when using Hyper-V isolation with the WorkflowGen container in WorkflowGen versions 7.19.2 and earlier. It's recommended to use process isolation exclusively. This limitation no longer applies as of WorkflowGen version 7.20.0.

Global prerequisites

  • Make sure to have a valid WorkflowGen license.

  • If you're using Windows Server, make sure that it's Windows Server 2019, and use the tag that corresponds to that version. For example, for Windows Server 2019, use the tag that ends with ltsc2019.

Docker manual local machine deployment

Architecture overview

At the end of this section, the following architecture will be deployed on your local machine:

Inside the Docker engine on your machine, you'll have a running WorkflowGen server and a WorkflowGen database. Both of these will use volumes mapped to your local machine to persist data files.

Prerequisites

Make sure to have installed Docker on your machine.

For Windows 10 Pro

Follow the instructions in the guide to install Docker for Windows. You must be using Windows containers, so you need at least Windows 10 Pro.

For Windows Server

Do not install Docker for Windows on Windows Server. It is designed for development only.

If you've provisioned a virtual machine on your cloud provider where the template indicates something like Windows Server with Containers, it's probably safe to assume that Docker is already installed. Execute docker version on the machine to verify that it is. If so, you can skip the installation process.

Follow the instructions in the guide to install Docker on Windows Server.

For this setup, it's recommended to use WorkflowGen's database Docker image. You can also use a SQL database installed on your local machine.

Run the database container

To download the database image into your local machine, open PowerShell and enter the following:

  • Don't forget to use the correct tag for your version of Windows.

  • The Windows version of the advantys/workflowgen-sql image is designed for development or testing only. It is not suited for production workloads. Instead, consider using the Linux version of the image (e.g. advantys/workflowgen-sql:7.18.2-ubuntu-18.04).

For WorkflowGen to work, you need to run the database before running WorkflowGen. Before creating the container, create a Docker volume in order to externalize the database files (.mdf and .ldf). This will ensure that the data are still there after the deletion of the container.

The physical location of the volume can be obtained using the following command:

Typically, it will be stored in C:\ProgramData\Docker\volumes\sqldata\_data. Make sure that the container has write access to this directory (see the Microsoft article for information).

You're now ready to run the database container. To do this, execute the following command:

This last command will set the passwords of the SA database user, the WFGEN_USER database user, and the wfgen_admin WorkflowGen account asstrong(!)Pass. Per the nature of Docker, the SA_PASSWORD and ACCEPT_EULA environment variables come from the microsoft/mssql-server-windows-express base container and are not directly handled by the WorkflowGen container.

Run the WorkflowGen container

Enter the following to download the WorkflowGen image:

Don't forget to use the correct tag for your version of Windows (see above).

For this container, you need two volumes in order to correctly persist the WorkflowGen data:

  • WorkflowGen licenses (licenses)

  • WorkflowGen's data (data), which contains the following:

    • The App_data folder (appdata

You now need to copy your WorkflowGen license into the licenses volume. To do this, execute the following command:

This way, the WorkflowGen container will be able to pick it up via the volume. You also need an encryption key for the container; use the following command to generate one:

To run the actual container, replace <YOUR_WFG_LIC_KEY> with your WorkflowGen license key and <YOUR_NEW_GUID> with the GUID that you generated in the last step, then execute the following command:

When the container is ready, open a browser and go to http://localhost:8080/wfgen, where you'll be prompted for WorkflowGen authentication. By default, the container is configured with the application authentication method.

Shut down the containers

Once you're done with this environment, you can shut down containers by stopping them. They can be restarted later.

  • Any environment variable defined will be reapplied after restarting a container. Therefore, any changes made to a web.config file without environment variables will not be carried between restarts or re-runs.

  • This action keeps data in the container's file system between restarts. If you add a file that isn't in a volume, it will be kept after restarting.

Remove the containers

To completely remove containers, there's only one command to execute:

This will remove the database and WorkflowGen containers including, any manual change in the container's file system that is not part of a volume. Even if the containers are gone, the data in the volumes are retained and can be used by other containers. For example, you could launch three other WorkflowGen containers that use the same volumes and they will all get the exact same files at the mount point of the volume.

Docker Compose local machine deployment

This section describes the recommended way to easily deploy a local development environment without having to enter a lot of commands. You can find out more about Docker Compose in the Docker documentation at .

Architecture overview

At the end of this section, the following architecture will be deployed on your local machine:

Inside the Docker engine on your machine, you'll have a running WorkflowGen server and a WorkflowGen database. Both of these will use volumes mapped to your local machine to persist data files.

Prerequisites

For Windows 10 Pro

Follow the instructions in the guide to install Docker for Windows. You must be using Windows containers, so you need at least Windows 10 Pro.

For Windows Server

Do not install Docker for Windows on Windows Server. It is designed for development only.

If you've provisioned a virtual machine on your cloud provider where the template indicates something like Windows Server with Containers, it's probably safe to assume that Docker is already installed; execute docker version on the machine to verify that it is. If so, you can skip the installation process.

Follow the instructions for Windows Server in the guide to install Docker on Windows Server.

On Windows Server only, you also need to install the Docker Compose tool, since it's not installed by default. Follow the instructions for Windows Server in the guide. To verify that Docker Compose is properly installed, run the following command:

For this setup, it's recommended to use WorkflowGen's database Docker image. You can also use a SQL database installed on your local machine.

Create the license volume

Before creating the services, you need to create the license volume externally from the composition in order to have the licenses present at the time of container creation. To do this, execute the following command:

Then, you need to copy your license file to the licenses directory. The following command will show you where the license will be stored:

To copy your license, execute the following command:

Create the symmetric encryption key

This value should be generated by you. A simple GUID will suffice since it has sufficient entropy not to be guessed:

Create the environment files

For each service that you'll create (one for WorkflowGen and one for the database), you'll need a file that contains all of the environment variables for that service.

Database

Use the following file as a template:

Save it as database.env using the path where you'll put the Compose file.

WorkflowGen

Use the following file as a template:

Replace <YOUR_WFG_LIC_KEY> with the value of your WorkflowGen license key. Replace <YOUR_NEW_GUID> with the symmetric encryption key that you have generated earlier.

Save this file as workflowgen.env using the path where you'll put the Compose file.

Deploy the services

To deploy services with Docker Compose, you need a Compose file that describes them. Use the following Compose file for this example:

Save this file as docker-compose.yml using the path where you put your environment variable files, then execute the following command:

Wait a few minutes for the containers to get started, then open a browser and navigate to http://localhost:8080/wfgen, where you will be prompted for authentication. Enter the credentials (username wfgen_admin and password strong(!)Pass) and it should display the WorkflowGen home page.

)
  • Workflow applications (wfapps)

  • Docker Desktop
    Docker Desktop
    Persistent Storage in Containers
    Global prerequisites
    Overview of Docker Compose
    Docker Desktop
    Docker Desktop
    Install Docker Compose
    docker image pull advantys/workflowgen-sql:7.18.2-express-win-ltsc2019
    docker volume create sqldata
    docker volume inspect -f "{{.Mountpoint}}" sqldata
    docker container run -it `
      --env ACCEPT_EULA=Y `
      --env 'SA_PASSWORD=strong(!)Pass' `
      --env WFGEN_DATABASE_USER_USERNAME=WFGEN_USER `
      --env 'WFGEN_DATABASE_USER_PASSWORD=strong(!)Pass' `
      --env 'WFGEN_ADMIN_PASSWORD=strong(!)Pass' `
      -v sqldata:C:\wfgen\sql `
      --name wfgen_sql `
      --hostname database `
      advantys/workflowgen-sql:7.18.2-express-win-ltsc2019
    docker image pull advantys/workflowgen:7.18.2-win-ltsc2019
    "licenses", "wfgdata" | ForEach-Object { docker volume create $_ }
    Copy-Item C:\Path\To\WorkflowGen.lic $(docker volume inspect -f "{{.Mountpoint}}" licenses)
    [guid]::NewGuid().ToString('N')
    # fda7a6a81db2428b8885bd1210522755
    docker container run -it `
      --env 'WFGEN_APP_SETTING_ApplicationUrl=http://localhost:8080/wfgen' `
      --env 'WFGEN_APP_SETTING_ApplicationSerialNumber=<YOUR_WFG_LIC_KEY>' `
      --env 'WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey=<YOUR_NEW_GUID>' `
      --env 'WFGEN_DATABASE_CONNECTION_STRING=Data Source=database,1433;Network Library=DBMSSOCN;Initial Catalog=WFGEN;User ID=WFGEN_USER;Password=strong(!)Pass;' `
      -p 8080:80 `
      -v wfgdata:C:\wfgen\data `
      -v licenses:C:\wfgen\licenses:RO `
      --name wfgen `
      advantys/workflowgen:7.18.2-win-ltsc2019
    # Stopping the containers
    "wfgen", "wfgen_sql" | ForEach-Object { docker container stop $_ }
    
    # Starting the containers
    docker container start wfgen_sql
    # Wait for the database to be ready and then start the WorkflowGen container
    docker container start wfgen
    
    # Restarting the containers
    "wfgen_sql", "wfgen" | ForEach-Object { docker container restart $_ }
    "wfgen", "wfgen_sql" | ForEach-Object { docker container rm -f $_ }
    docker-compose version
    docker volume create licenses
    docker volume inspect -f "{{.Mountpoint}}" licenses
    Copy-Item C:\Path\To\WorkflowGen.lic $(docker volume inspect -f "{{.Mountpoint}}" licenses)
    [guid]::NewGuid().ToString('N')
    # fda7a6a81db2428b8885bd1210522755
    SA_PASSWORD=strong(!)Pass
    WFGEN_DATABASE_USER_USERNAME=WFGEN_USER
    WFGEN_DATABASE_USER_PASSWORD=strong(!)Pass
    WFGEN_ADMIN_PASSWORD=strong(!)Pass
    WFGEN_APP_SETTING_ApplicationUrl=http://localhost:8080/wfgen
    WFGEN_APP_SETTING_ApplicationSerialNumber=<YOUR_WFG_LIC_KEY>
    WFGEN_APP_SETTING_ApplicationSecurityPasswordSymmetricEncryptionKey=<YOUR_NEW_GUID>
    WFGEN_DATABASE_CONNECTION_STRING=Data Source=database,1433;Network Library=DBMSSOCN;Initial Catalog=WFGEN;User ID=WFGEN_USER;Password=strong(!)Pass;
    version: '3.8'
    services:
      workflowgen:
        image: advantys/workflowgen:7.18.2-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        ports:
          - '8080:80'
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      database:
        image: advantys/workflowgen-sql:7.18.2-express-win-ltsc2019
        env_file:
          - '.\database.env'
        volumes:
          - 'sqldata:C:\wfgen\sql'
    
    volumes:
      wfgdata:
      licenses:
        external: true
      sqldata:
    
    Set-Location C:\Path\To\ComposeFile
    docker-compose up

    TLS/SSL

    Manual

    In Kubernetes, there are tools to help you manage certificates and achieve a TLS connection. This is easier than making a custom architecture using the reverse proxy method. You can read more about managing certificates with Kubernetes at the following link:

    • Manage TLS Certificates in a Cluster

    Using cert-manager

    is a cloud native application that manages certificates for you. It includes mechanisms to ask for Let's Encrypt certificates automatically and get certificates from , or you can use your own certificates generated by a certificate authority (CA) or a self-signed certificate.

    TLS/SSL

    Overview

    This section presents ways to configure a secure connection (HTTPS) to the WorkflowGen container using a certificate. With Docker, containers run on an internal network, and only exposed ports will be available publicly. Therefore, you can't set up a TLS connection on one container only; you have to do it for all the containers, but this method doesn't scale well.

    Use an Nginx container

    This method uses the Nginx web server as a reverse proxy configured with a TLS connection that will redirect all traffic to the WorkflowGen container(s). This method can be applied regardless of whether you have orchestration or not.

    See the following pages for more information:

    • Let's Encrypt With Docker

    • Secure services with TLS

    Use Traefik

    Traefik is a reverse proxy that handles routing, TLS termination, and load balancing, among other things. It's available as a container and you can use it in front of the WorkflowGen container. For more information about Traefik, see its documentation page.

    Use Azure Application Gateway

    In Azure, you can use the Application Gateway service in order to get a TLS connection for domains that you own. See the Overview of TLS termination and end to end TLS with Application Gateway Microsoft article to get you started.

    Kubernetes

    For more information and recommendations about TLS/SSL handling in Kubernetes, see the TLS/SSL page in the Kubernetes section.

    cert-manager
    HashiCorp Vault

    Business Continuity & Disaster Recovery

    Overview

    This section contains pointers to get started with different solutions for creating backups and recovering from an unforeseen data loss.

    In production, you should be using an orchestrator like Docker Swarm, Kubernetes, or Kubernetes in Azure Kubernetes Service.

    SQL Server Hosting Options

    Overview

    This section explains the recommended configurations for the database in production.

    Deploying a database

    Multitenancy

    Overview

    This section presents how to achieve multitenancy with WorkflowGen images and Kubernetes. By the nature of containers and tools present in Kubernetes, a single cluster can have multiple instances of WorkflowGen with relative isolation from one another. The best isolation can be achieved with multiple clusters.

    As reference for best practices, see the following links to Google Kubernetes Engine and Azure Kubernetes Service documentation:

    File Management

    Overview

    This section shows which persistent data are exposed and where. It also recommends some ways to persist, share, and back up the data. For backup strategies and recommendations, see the section.

    Custom Domain Names

    Overview

    This section describes some ways to configure domain names in Docker.

    To configure a domain name in a WorkflowGen container, you can pass the WFGEN_APP_SETTING_ApplicationUrl=https://somedomain.com/wfgen

    WorkflowGen files

    SMB file shares

    You should have at least three different storage shares to handle WorkflowGen persistent files. If you used custom SMB file shares, you should have a strategy to back up the disks for the file share. If a problem occurs, you can restore a backup. Don't forget to restore the database data to the exact time as the file share backup.

    Azure Files

    For Azure Files, see the following documentation on backups and restorations:

    • Back up Azure file shares

    • Azure storage disaster recovery planning and failover

    Azure Disks

    For Azure Disks, see the following documentation on backups and restorations:

    • Backup and disaster recovery for Azure managed disks

    Database

    On-premise database

    See the Operations section in the WorkflowGen Technical Guide for information on backup and restoration of on-premise databases.

    Azure SQL

    See the following Microsoft documentation on business continuity with Azure SQL:

    • Overview of business continuity with Azure SQL Database

    Kubernetes

    Creating backups and recovering with them in Kubernetes can be complicated, but tools exist to help manage this. Here's an article about backups with Kubernetes:

    • Kubernetes: Backups and recovery

    There are two main tools for backup and recovery:

    • Velero

    • kube-backup

    Azure Kubernetes Service

    As with other Azure Services, Microsoft provides guides for backups and restorations:

    • Best practices for business continuity and disaster recovery in Azure Kubernetes Service (AKS)

    Azure SQL

    See the following documentation for Azure SQL setup:

    • Azure SQL Database Configuration

    On-premise

    See the following documentation about the requirements for on-premise databases:

    • Suggested Hardware Configurations

    Container-based

    WorkflowGen has a production-ready database image based on the Microsoft SQL Server image for Linux. It has the same options as the Microsoft image with some additional features such as automatic creation of the WorkflowGen database and setting the wfgen_admin username and password. The image is available on Docker Hub:

    • advantys/workflowgen-sql - Docker Hub

    For more information about the WorkflowGen database image, see Configuration in the WorkflowGen Database Image section.

    Persistent data in WorkflowGen database

    Persistent data is different depending if you use the Linux version or the Windows version.

    Linux

    The Linux version has a more managed way to persist the database's data. Instead of only persisting the .mdf and .ldf file of the WorkflowGen database, you instead persist all of the SQL Server state data, including the master database files. For more information on how to persist the data in the Linux, see Configure SQL Server container images on Docker in the official Microsoft documentation for SQL Server.

    Windows

    Since the Windows version's base image hasn't been updated by Microsoft for quite some time, WorkflowGen's database files have to be persisted manually. Therefore, the database container has a defined volume that will contain only the WorkflowGen database files. As well, it's recommended to use SQL Server's contained database feature to keep the credentials at the database level instead of at the SQL Server system level. For more information about the contained database feature, see contained database authentication Server Configuration Option in the official Microsoft documentation.

    Name

    Description

    C:\wfgen\sql

    This path contains the .mdf and .ldf files of the WorkflowGen database.

    Particularity of Windows Containers

    Volumes are handled differently with Windows Containers compared to Linux Containers. The permission model changes and is different depending on whether you use process isolation or Hyper-V isolation. Before continuing with the procedures in this section, you should read the Microsoft documentation on container storage.

    Business Continuity & Disaster Recovery
    environment variable.

    Internal domain names

    In Docker, there is an internal DNS that handles domain names for containers and machines. You can easily configure an internal domain name for each container just by passing simple parameters. See the following link for more information:

    • Container networking

    Public-facing domain name

    For domain names that are public, you'll typically need an external service (e.g. NameCheap or AWS Route 53) that sells domain names, and then configure that service to point to the public IP of the public-facing containers.

    Obtaining a public IP address

    All you need to do is to expose the port of the container (or service) you need and it will be available publicly.

    You need to configure the front-facing nodes manually with the IP address that you own. There's no load balancer created automatically.

    This will expose the container port 80 to the host's port 80. The public IP is that of the Docker host.

    docker container run `
        # ...
        -p 80:80 `
        # ...
        advantys/workflowgen:7.18.3-win-ltsc2019
    Cluster multi-tenancy
  • Best practices for cluster isolation in Azure Kubernetes Service (AKS)

  • Security concerns

    Before beginning with the recommended architectures, it is important to note some security concerns that derive from using Windows containers. The WorkflowGen image is a Windows container image. Some security features present in Linux containers are not necessarily available in Windows containers, such as AppArmor and SELinux profiles and Linux capabilities. See Intro to Windows support in Kubernetes for all of the current limitations.

    The important thing in multitenant clusters is isolating tenants from one another and limiting possible actions in case of intrusion. You can achieve a good isolation level with network policies on Kubernetes. These are specifications that require third-party software to be installed to enforce those policies. At this time, only the Calico project has a Windows support (see Calico for Windows for more information).

    For in-container security, at this time, only runAsUserName is available to run the container instance as a different username than ContainerAdministrator (see Configure RunAsUserName for Windows pods and containers for more information). It's not necessary for the WorkflowGen container since the web applications run as a user of the IIS_IUSRS group.

    Recommendations

    • Make sure that the WorkflowGen Windows Services pod has inbound traffic denied. It should not be public facing.

    • Make sure that the WorkflowGen database pods are not public facing. They are only used by the WorkflowGen container.

    • The WorkflowGen web applications' pods should only be publicly available through HTTPS. HTTP is highly discouraged. However, you should not be able to access WorkflowGen at all from inside the cluster, even in HTTPS.

    • Every WorkflowGen pod in a namespace should not be able to contact other pods in other namespaces. Be sure to have a network policy for this.

    • In general, you should always deny any inbound traffic unless you explicitly need it.

    Architecture

    Multitenant architecture

    The basic idea behind multitenancy is to have reproducible deployment. This schema shows two identical deployments but in different namespaces. Each has its own data, configuration, and license. Isolation between the namespaces should be enforced by network policies. Optionally, you might want to use an Ingress controller with cert-manager to manage routing and certificates easily.

    This architecture also applies to multicluster (multiregion) environments. The only thing that will change is how you route to the correct instance. The same security concerns apply.

    Main Architecture Description

    Overview

    This section contains details on the recommended architecture to use when deploying WorkflowGen for Docker. The following schema illustrates all of the components in action:

    As shown, all runtime components are inside one or more Docker hosts. You can use as many web application containers as you want for higher availability and better performance, but you can only have one instance of each WorkflowGen Windows Service. You also don't have to use the database container; if you want, you can externalize the database to a cloud provider such as Azure SQL or your own on-premise SQL Server.

    As usual, you can configure the SMTP service that you want to use with WorkflowGen's container. There is no special setup needed for this.

    All persistent data is externalized. The licenses used for WorkflowGen, the application data (App_Data), and the workflow applications (wfapps) are all persisted into a distinct shared space (wfgdata in the diagram). For example, this could be a file share, an Azure Files file share or Azure Disk disk, or any other service that is capable of acting as directory on a Docker host.

    As well, in this diagram, the database files are in a Docker volume. This volume should be a disk, such as a local disk on the Docker host whose backups you can control, or something like an Azure Disk disk so that you can take snapshots. In the case of the database, it's important to have a disk to maintain good performance. For optimal results, you should externalize the database. See the SQL Server Hosting Options page for more details.

    WorkflowGen services

    This section describes each of the WorkflowGen container's runtime environments. Keep in mind that all environments are packaged in a single image.

    Web applications

    When you run the container's web applications, the following components are running:

    • User Portal

    • Administration Module

    • All APIs:

      • GraphQL

      • SOAP

      • SCIM v2

      • Webhooks

      • OpenID Connect authentication

    • ASP.NET web forms

    • Workflow applications (.NET assemblies)

    These are all of the components that you need to make every web service and graphical interface work.

    Windows Services

    When you run the container's Windows Services, the following components are running:

    • Directory synchronization service

    • Engine service

    File storage

    These are shared spaces between the containers where data that should be persistent and that can't be in the database are located. A shared space for WorkflowGen licenses is required because a license can't be stored directly into an image. Instead, it's retrieved at runtime from the container and placed at the correct location inside the container.

    The WorkflowGen App_Data folder should be shared between the containers. It contains the following pieces of information that WorkflowGen needs to work properly:

    • Design time process files

    • Runtime process files

    • Log files

    • Workflow application temporary files

    • Customized User Portal menus

    • Process templates

    • Mail templates

    The wfapps IIS web application is also shared among the containers because the web forms contained at this location are ASP.NET files generated at design time; this is why they're considered as storage. The App_Data and wfapps folders are grouped in the same shared space called wfgdata.

    Database container and storage

    In this architecture, the WorkflowGen database is containerized and its data is stored in a shared space, preferably backed by a high performance disk as well. You can add other containerized databases as read replicas with their own shared space for their data. For more details about the database container or database management with containers, see the SQL Server Hosting Options section.

    SMTP service

    WorkflowGen relies on an SMTP gateway to send email notifications. A SMTP server or service with a low network latency and a high availability is recommended.

    Usage

    Overview

    This page presents the common use cases of the WorkflowGen upgrade image. This image is available as Linux and Windows containers, and is meant to be a single use container that runs until completion. You should delete it once you're done with it.

    Upgrade steps

    The first thing to know about the upgrade container is the steps it takes to upgrade your installation. Every step, except for the acquisition of the update package, is done within a transaction, which means that any error will revert all changes previously made. In the case of files, they will be restored from a backup done prior to the operation.

    Step 1: Get the update package

    Depending on if the upgrade container is online or offline, this step gets the update package of the ToVersion parameter. If the container is online, it will try to get the update package from the updatepackages volume first. If not found, the container will download it from the workflowgen-releases GitHub repository. If the container is offline, it will try to get the update package from the updatepackages volume. If it can't, it will write an error message and exit.

    You have to provide your own WorkflowGen update packages when using the container offline. By default, when you mount the updatepackages volume, the container expects the following file structure:

    As you can see, the structure expected has only folders at the top level with the exact version of WorkflowGen. Inside them is an archive called update.zip, which is the WorkflowGen official update package. You need only to have the ToVersion update package when you run the container.

    Optionally, if the update package is located elsewhere within the volume, you can specify the file name and path in the WFGEN_UPGRADE_UPDATE_PACKAGE_FILE_NAME environment variable. For example, you could specify the value 7.15.2.zip if ToVersion is 7.15.2 and the directory structure is flat. You could also specify the value workflowgen/updates/7.15.2/update.zip if the update package is further down the directory tree.

    For more information about environment variables, see the Configuration page of this section.

    Step 2: Merge new App_Data files into existing App_Data folder

    Before this operation, a backup will be made of all the folders and files from within the bind mount and temporarily copied to a path inside the container. At all times, the Files, LogFiles, and Ws folders are ignored, including during the merge operation. The container will then merge the App_Data files from the update package into your App_Data folder that you have linked to the container through the data bind mount. The merge is additive only, which means that any file that don't exist in the update package will be kept as-is.

    Step 3: Merge new wfapps files into existing wfapps folder

    In the same manner as the App_Data merge operation, the wfapps folder will also be merged with your wfapps provided in the data bind mount. This operation is also additive only.

    Step 4: Migrate the database if needed

    The upgrade container will then apply any SQL migration files found in the update package that satisfy the condition fv<x≤tvfv < x \le tvfv<x≤tv where xxx is the version of the SQL migration file, fvfvfv is the FromVersion value and tvtvtv is the ToVersion value.

    Online example

    This is the simplest use of the upgrade container. For example, if you want to upgrade WorkflowGen from version 7.14.6 to 7.18.2 and the container has access to the Internet, you would call it like this:

    In this example, the container will download the update package from the 7.18.2 version, merge the App_Data and wfapps files in /mnt/data/appdata and /mnt/data/wfapps respectively and apply any database migrations using the SQL scripts in the update package.

    You can ignore files and folders with environment variables when the container merges files. For more information, see the Configuration page of this section.

    Offline example

    If the container doesn't have access to the Internet, you can pass the WorkflowGen update package yourself. Make sure that it is the exact version of the ToVersion argument passed to the container. You would call the container like this:

    In this example, there are two changes compared to the online example. First, a bind mount has been added for provisioning update packages. The container will first look in it to find an update package. Second, the -Offline flag has been passed to the container. This flag tells the container to not try to download the update package if it doesn't find the package in the bind mount. In other words, the container will not attempt any network-related access.

    The path and name of the update package can be modified with environment variables. For more information, see the Configuration page of this section.

    # "wfgdata" groups appdata and wfapps folders
    docker container run -i --name wfgen-upgrade `
        --env 'WFGEN_DATABASE_CONNECTION_STRING=Server=someserver,1433;...' `
        --mount "type=bind,src=C:\path\to\your\wfgdata,dst=/mnt/data" `
        advantys/workflowgen-upgrade:latest-ubuntu-18.04 `
        -FromVersion 7.14.6 -ToVersion 7.18.2
    
    # When has terminated, you can analyse the container or review the logs.
    # Then, remove the container.
    docker container rm wfgen-upgrade
    # "wfgdata" groups appdata and wfapps folders
    docker container run -i --name wfgen-upgrade \
        --env 'WFGEN_DATABASE_CONNECTION_STRING=Server=someserver,1433;...' \
        --mount type=bind,src=C:\path\to\your\wfgdata,dst=/mnt/data \
        advantys/workflowgen-upgrade:latest-ubuntu-18.04 \
        -FromVersion 7.14.6 -ToVersion 7.18.2
    
    # When has terminated, you can analyse the container or review the logs.
    # Then, remove the container.
    docker container rm wfgen-upgrade
    # "wfgdata" groups appdata and wfapps folders
    docker container run -i --name wfgen-upgrade `
        --env 'WFGEN_DATABASE_CONNECTION_STRING=Server=someserver,1433;...' `
        --mount "type=bind,src=C:\path\to\your\wfgdata,dst=/mnt/data" `
        --mount "type=bind,src=C:\path\to\packages,dst=/mnt/updatepackages" `
        advantys/workflowgen-upgrade:latest-ubuntu-18.04 `
        -FromVersion 7.14.6 -ToVersion 7.18.2 -Offline
    # "wfgdata" groups appdata and wfapps folders
    docker container run -i --name wfgen-upgrade \
        --env 'WFGEN_DATABASE_CONNECTION_STRING=Server=someserver,1433;...' \
        --mount type=bind,src=C:\path\to\your\wfgdata,dst=/mnt/data \
        --mount type=bind,src=C:\path\to\packages,dst=/mnt/updatepackages \
        advantys/workflowgen-upgrade:latest-ubuntu-18.04 \
        -FromVersion 7.14.6 -ToVersion 7.18.2 -Offline
    updatepackages/
        7.14.0/
            update.zip
        7.15.0/
            update.zip

    File Management

    Overview

    This section shows which persistent data are exposed and where. It also recommends some ways to persist, share, and back up the data. For backup strategies and recommendations, see the Business Continuity & Disaster Recovery section.

    Persistent data in WorkflowGen

    There are three elements that must be persisted in WorkflowGen: the App_Data folder, the wfapps web application folder, and the SQL data. The first two are grouped in the same file share for simplicity and ease of use. To deploy a database, see the section.

    The other two are files from WorkflowGen, and the reasons they must be persisted through a file share is explained in the section.

    Additionally, you must have a file share with a valid WorkflowGen license in it so that the container can pick it up. Those folders must be exposed to the WorkflowGen containers through volumes. For more information about Docker volumes, see the Docker article.

    Particularity of Windows Containers

    Volumes are handled differently with Windows Containers compared to Linux Containers. The permission model changes and is different depending on whether you use process isolation or Hyper-V isolation. Before continuing with the procedures in this section, you should read the Microsoft documentation on .

    Essentially, you must ensure that WorkflowGen containers can read and write to the wfgdata volume and read from the licenses volume. The group in the container that will access the volumes is named IIS_IUSRS.

    Recommended ways to persist

    Local file system path on the Docker host

    This is the simplest way to persist WorkflowGen files with the containers. It consists of creating a local volume or using a bind mount on your Docker host that will retain the files after a container is removed. Volumes are the preferred way to persist files versus bind mounts because they're managed by Docker. This method doesn't scale well across multiple Docker hosts, however, so other methods should be considered in this case.

    Volumes

    To create a volume for each data path in the container, execute the following command:

    Then, you need to copy (or move) your license file to the licenses volume by executing the following command:

    Now, you can run WorkflowGen container with those volumes to persist the data.

    📌 Example of a run command

    You have now successfully persisted WorkflowGen's files.

    Bind mounts

    Remember that you manage bind mounts manually. They are specific paths on the Docker host that you control. To use bind mounts as volumes, you only need to pass the paths when you execute the run command like so:

    Network file share

    You can use an SMB file share with Windows Containers such as Azure Files. Concretely, you connect the share to the Docker host and then mount it like a bind mount to containers; this is called an SMB mount. You can read more about SMB mounts in the Microsoft documentation.

    Using an orchestrator

    Kubernetes

    In Kubernetes, you'll use a Persistent Volume object to specify a place where Kubernetes will put data from pods. For more information about persistent volumes, see the page on the Kubernetes website.

    Concretely, for WorkflowGen, you'll have to configure a volume that can handle the permission ReadWriteMany for the WorkflowGen data volume because multiple pods at the same time will access this volume to read and write data. Typically, to do this, you'll have to create a storage claim on the cluster like so:

    In this example, the claim references a Storage Class, but you can reference a persistent volume directly, or other cloud-specific storage services depending on the cloud provider. Here, the azurefile storage class is provided by Azure Kubernetes Service. The allocation of the storage will be done automatically by the service. It will create a storage account with a file share that has 50 GB capacity.

    Pickup directory

    If you configure WorkflowGen to use a pickup directory for notifications, you'll also need to specify a volume in order to expose the notifications to other services that will process them.

    The default path for the pickup directory is C:\inetpub\mailroot\Pickup. You can change it by supplying the WFGEN_APP_SETTING_ApplicationSmtpPickupDirectory environment variable with any path inside the container. Then, you'll need to create a volume for the files like so:

    You can now map this volume to the configured pickup directory:

    At this point, you could deploy another container with your service to take care of the notifications and bind the same volume to share the notification files.

    Update Management

    Overview

    This section presents how to manage WorkflowGen updates and deploy them safely in your environments.

    You can use the WorkflowGen upgrade container to automatically apply files and database operations when upgrading from one version to another. For more information about the upgrade container, see the Configuration page in the WorkflowGen Upgrade Image section.

    Prerequisites

    • Back up all of the file shares.

    • Back up the database.

    For more information about business continuity and disaster recovery, see the section.

    Manual update

    Step 1: Execute all required actions

    These actions can include moving, deleting, or adding some files around in the file shares, updating some configuration in your orchestrator or configuration files, adding secrets, adding or removing services, etc. The actions are detailed in the (choose the version to which you want to upgrade).

    Only execute the actions that concern the files in the file shares. Any actions pertaining to files or services in WorkflowGen's container must be ignored. These will already be done once the new version of the image is in place. For example, don't stop the IIS service, since it's useless with a Docker container.

    Step 2: Upgrade the database

    See the section in the (choose the version to which you want to upgrade).

    If you're using the WorkflowGen database image, after upgrading the database, you need to update the container as well:

    Step 3: Custom WorkflowGen image actions

    Skip this step if you don't have a custom WorkflowGen image. See the section for more information.

    Execute any actions on your image's files

    If you have a custom WorkflowGen image, you have to perform the actions required for the web.config files if you have custom web.config files. Carefully read the section in the to see if you need to change anything in your files.

    Update the WorkflowGen version in your Dockerfile

    Your Dockerfile should be based on the WorkflowGen image (FROM instruction). Update the version number of the WorkflowGen image, build your image, and push it to your container registry. For example, if your version of WorkflowGen is 7.16.0 and you want to update to 7.16.1, execute the following change on the FROM instruction line:

    Then, build your custom WorkflowGen image:

    Finally, push the image to your container registry:

    Step 4: Roll the update to your containers

    In production, you should use an orchestrator and therefore use the mechanism for rolling updates provided by that orchestrator.

    Since containers are stateless, updating them is as simple as replacing currently running ones with the new version. To do this:

    1. Pull the new version of the container.

    2. Remove containers with the old version.

    3. Run containers with the new version.

    For example, if you want to update to WorkflowGen version 7.16.1:

    Name

    Description

    C:\wfgen\data

    This path contains all of the WorkflowGen data, including the App_Data folder and all the workflow applications created within WorkflowGen (e.g. in the wfapps folder).

    The wfapps\webforms folder is mounted as a web application in IIS.

    C:\wfgen\licenses

    This path contains custom licenses that you want for WorkflowGen. The container will take the first one that it detects. It's recommended to put only one license in this directory to avoid licensing problems.

    If you don't have a trial license, don't forget to set the WFGEN_CONFIG_ApplicationSerialNumber environment variable according to your license.

    SQL Server Hosting Options
    Architecture
    Use volumes
    Windows Server Container Storage
    Windows Service Container Storage
    Persistent Volumes
    Business Continuity and Disaster Recovery
    WorkflowGen Upgrade Guide
    Upgrade the WorkflowGen database
    WorkflowGen Upgrade Guide
    Custom WorkflowGen Image
    Update configuration files
    WorkflowGen Upgrade Guide
    "wfgdata", "licenses" | ForEach-Object { docker volume create $_ }
    Copy-Item C:\Path\To\WorkflowGen.lic $(docker volume inspect -f "{{.Mountpoint}}" licenses)
    docker container run `
        # ...
        --mount "type=volume,src=wfgdata,dst=C:\wfgen\data" `
        --mount "type=volume,src=licenses,dst=C:\wfgen\licenses,readonly" `
        # ...
        advantys/workflowgen:7.18.3-win-ltsc2019
    docker container run `
        # ...
        --mount "type=bind,src=C:\some\path\to\wfgdata,dst=C:\wfgen\data" `
        --mount "type=bind,src=C:\some\path\to\wfgen\licenses,dst=C:\wfgen\licenses,readonly" `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: wfgdata-pvc
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: azurefile
      resources:
        requests:
          storage: 50Gi
    
    docker volume create pickup
    docker container run `
        # ...
        --env WFGEN_APP_SETTING_ApplicationSmtpDeliveryMethod=PickupDirectory `
        --env WFGEN_APP_SETTING_ApplicationSmtpPickupDirectory=C:\inetpub\mailroot\Pickup `
        --mount "type=volume,src=pickup,dst=C:\inetpub\mailroot\Pickup" `
        # ...
        advantys/workflowgen:7.18.3-win-ltsc2019
    - FROM advantys/workflowgen-sql:7.18.2-ubuntu-18.04
    + FROM advantys/workflowgen-sql:7.18.3-ubuntu-18.04
    - FROM advantys/workflowgen:7.16.0-win-ltsc2019
    + FROM advantys/workflowgen:7.16.1-win-ltsc2019
    Set-Location C:\Path\To\Custom\Context
    docker image build `
        # ...
        -t mycorporation/workflowgen:7.16.1-win-ltsc2019 `
        # ...
        .
    # Docker Hub is the default container registry
    docker image push mycorporation/workflowgen:7.16.1-win-ltsc2019
    # 1. Pull the new version of the container.
    # For custom images, use the name of your account instead of "advantys".
    docker pull advantys/workflowgen:7.16.1-win-ltsc2019
    
    # 2. Remove the containers with the old version.
    # This code loops through all containers whose name contains "wfgen"
    docker container ls --format name=wfgen -q `
        | ForEach-Object { docker container rm -f $_ }
    
    # 3. Run containers with the new version
    docker container run `
        # ...
        advantys/workflowgen:7.16.1-win-ltsc2019

    Log Gathering & Application Metrics

    Overview

    This section presents what is logged in the WorkflowGen image and how. It also shows pointers to configure centralized logging with some services and orchestrators.

    WorkflowGen doesn't come with metrics generation out-of-the-box. Nevertheless, you can configure some existing software or services with WorkflowGen's container in order to get more valuable metrics for monitoring performance and traffic.

    Log sources

    When deploying WorkflowGen, many applications provide logs through different streams. This table lists the different log sources and their streams:

    As you can see, there are many log sources and not all are handled directly by the container. Some of them need to be managed manually.

    WorkflowGen web application logs

    These logs are written in files in the App_Data folder, which is exposed through a volume. For more information about exposed volumes, see the section.

    In order to centralize these logs in a logging service or system, you need to develop your own script or application that will periodically read the logs in the App_Data volume and push them to the service. Concretely, this is done by developing a Singleton container that has access to the WorkflowGen data volume. In Kubernetes, you would deploy this container inside a pod that has only one replica to avoid problems with concurrency.

    WorkflowGen Windows Services logs

    These logs are written to the Windows Events API and are retrieved by the WorkflowGen container only when the start mode is win_services, dir_sync, or engine. In any other case, it's the IIS logs that are redirected to the standard output and the Windows Services logs are discarded.

    To get all the logs from WorkflowGen, you should use the architecture that separates each start mode into its own container. For more information, see the section.

    IIS logs

    IIS logs are written in multiple files inside the WorkflowGen container. You don't have to manually manage them. The container reads the logs and directs them to the standard output of the container. The standard output of each container is picked up by the Docker logging system.

    There are many Docker logging drivers to indicate to Docker where to put these logs. By default, they are written on the host in JSON format at the C:\ProgramData\Docker\logs path. The rest of this section provides more information about the Docker logging system and how to use it to centralize logs.

    In Kubernetes, you can configure your own logging agent or use the default one provided. For more details about logging in Kubernetes, see its page. Many cloud providers offer a centralized service to visualize logs from pods in their Kubernetes service. Refer to your cloud provider's documentation for details.

    iisnode logs

    These logs are disabled by default and can be enabled by setting the following environment variables for the WorkflowGen container:

    It's recommended to activate these logs in a development environment only because they can be exposed through HTTP.

    As shown, the logging is done on a per application and per container basis. To get these logs from the container, you have to use volumes and a custom application to centralize the logs, or build your own image based on the WorkflowGen image that will redirect those logs in some way to the container's standard output. For more information about making a custom WorkflowGen image, see the section.

    Capturing logs and metrics

    In order to centralize logs outside of a Docker host, you first need to choose a logging system or service. Once this is done, you need to use your orchestrator's specific method to link the service to the logs.

    Kubernetes

    Kubernetes has a similar functionality available to manage logs for containers. See the following link for more information:

    You can also use Azure Monitor with your Kubernetes Cluster. See the following link for more information:

    Azure Kubernetes Service

    The Azure Kubernetes Service documentation recommends using Azure Monitor for containers. See its documentation page for more details:

    Other monitoring services

    Prometheus

    This software can help you reduce costs related to monitoring applications using a cloud service. Prometheus can be deployed as a container inside your cluster alongside WorkflowGen. You'll need to add a utility to the WorkflowGen container, so you'll need to make a custom WorkflowGen image. For more information about making a custom WorkflowGen image, see the section.

    Here are some links to the Prometheus documentation and Dockerfile examples to help you get started with application metrics with Prometheus:

    Grafana

    Grafana can help you visualize metrics coming from the cluster. It also has a paid cloud service. Here are some links to get you started:

    In-container IIS log gathering

    If you prefer to gather only IIS logs directly from the container, Azure Application Insights provides a PowerShell tool called Application Insights Agent that's installed directly in the container. See for more information. You'll need to create your own image that incorporates this tool inside the container. For more information about custom WorkflowGen images, see the section.

    This approach should be considered only if your Kubernetes cluster is not managed by Azure Kubernetes Service and you want Application Insights to gather the logs. Otherwise, use the default logging agent or something like an ELK stack (ElasticSearch, Logstash and Kibana) or EFK stack (ElasticSearch, fluentd, and Kibana).

    Custom Image

    Overview

    This section shows how to create your own custom WorkflowGen image in order to customize WorkflowGen's files and DLLs.

    Prerequisites

    Source

    Streams

    WorkflowGen web applications

    Logs written in the App_Data folder

    WorkflowGen Windows Services

    Logs written through the Windows Events API

    Internet Information Services (IIS)

    Logs written in files in the container

    iisnode

    Logs written in multiple files in each Node.js application's folder inside the container

    File Management
    Recommended Architectures
    Logging Architecture
    Custom Image
    Logging Architecture
    Monitor your Kubernetes cluster performance with Container insights
    Overview of Container insights in Azure Monitor
    Custom Image
    dockersamples/aspnet-monitoring
    Installation
    dockersamples/aspnet-monitoring
    Installing using Docker
    Deploy Azure Monitor Application Insights Agent for on-premises servers
    Custom Image
    WFGEN_IISNODE_AUTH_loggingEnabled=true
    WFGEN_IISNODE_GRAPHQL_loggingEnabled=true
    WFGEN_IISNODE_SCIM_loggingEnabled=true
    WFGEN_IISNODE_HOOKS_loggingEnabled=true
    
    # Also specify these values to expose the logs through HTTP
    WFGEN_ENABLE_IISNODE_OPTION_AUTH=exposelogs
    WFGEN_ENABLE_IISNODE_OPTION_GRAPHQL=exposelogs
    WFGEN_ENABLE_IISNODE_OPTION_SCIM=exposelogs
    WFGEN_ENABLE_IISNODE_OPTION_HOOKS=exposelogs
  • Windows 10 Pro with Docker Desktop for Windows installed and Windows Containers enabled OR

  • Windows Server 2019 with Docker Enterprise installed

  • Description

    WorkflowGen's image provides a useful variant named advantys/workflowgen:7.18.3-win-ltsc2019-onbuild that can be used to easily customize any file contained in C:\inetpub\wwwroot or C:\Program Files\Advantys\WorkflowGen. All you need to do is create your own image with a Dockerfile that inherits from the onbuild variant and put the customized files in the Docker build context.

    Simple example

    Here's a simple example that replaces the web.config file, customizes the banner, and adds a custom library.

    The .\inetpub\wwwroot and .\Program Files\Advantys\WorkflowGen paths must exist in order for the build to succeed. They don't have to have files in them, so they can be empty.

    Step 1: Add your modified files at the root of the context

    Here's the file tree of the context directory from which you'll build your custom WorkflowGen image:

    Step 2: Add a Dockerfile to the context directory

    File tree:

    Here's the content of the Dockerfile:

    Step 3: Build your custom WorkflowGen image

    Build with Docker Compose

    With Docker Compose, you can specify the build parameters in a declarative format in order to integrate the Docker build process with the run. For example, you could have the following Compose file named docker-compose.yml in your context directory:

    (This file is from the Getting started section.)

    The important section is the build object in the workflowgen service object.

    Then, to build and tag automatically, you could run the following command:

    Docker Compose will then build and tag your image with the tag present in the image property. If you want to immediately update your Compose deployment on your local machine or immediately execute this deployment after the build, execute the following command, which will build your container in addition to running the services after the build:

    To push the image using Docker Compose, execute the following command:

    You now have a customized WorkflowGen image. For more information on updating your container when a new WorkflowGen version is available, see the Update Management section.

    Example with legacy custom WorkflowGen web application/procedure

    Let's say in addition to DLLs and custom banners you have an ASP.NET 2.0 web application to add to the wfapps folder and configure in IIS. You would perform the same steps as before, but also add a custom Docker CMD script that will configure the application in IIS.

    Multiple PowerShell scripts come with the WorkflowGen image and have different purposes:

    • docker-entrypoint.ps1: This is the main script that gets executed when you run a container. It handles the parsing of environment variables, configuration of authentication methods, etc.

    • monitor-services.ps1: This script handles the monitoring of processes (IIS and Windows services), as well as gathering the logs of the container and redirecting them to the standard output.

    • healthcheck.ps1: This handles the periodic check that indicates if WorkflowGen is working properly or not. This is defined in the WorkflowGen Dockerfile and is handled by the Docker engine.

    • *.psm1: Various developed PowerShell modules available in the image.

    • ServiceMonitor.exe: Binary executable provided by Microsoft. This is the main executable used by the monitoring script to check the state of a service. (You can find more information about ServiceMonitor on its GitHub page at ).

    • set-state.ps1: Sets the state of the container, such as bringing the website offline or online.

    By creating your own WorkflowGen image in Docker, you can replace any script with your own that does something else completely, and it's a best practice to do so if the stock scripts don't do what you want. In the case of this example, the stock scripts don't take care of setting the added web application as in IIS; you need to develop your own script for this. Here's the one that you'll use in this example:

    Replace <YOUR_WEB_SERVICE_NAME> with the name of your web service that you added in the wfapps folder.

    In this script, note the following:

    1. You're checking for the start service type and checking if you've already added the web service as a web application in IIS.

      Rationale This is because the entrypoint script is re-run between restarts of the container. Therefore, this script will also be re-run after a restart. When restarting a container, the IIS configuration stays and the ConvertTo-WebApplication command will cause the start procedure to fail when trying to add an already-added web application. Consequently, you have to check that you haven't already added the application.

      Also, you're checking if the container is running in web applications mode. When it isn't, you don't need to add your web service in IIS because there will be only Windows services that will run.

    2. You're checking for arguments and executing them if there are some. If not, you start to monitor the container's services.

      Rationale

      This is a general good practice in a Docker container. For example, if you're debugging the container and only want to prompt a PowerShell command line after the start sequence, you would pass powershell as an argument to the run command like so:

      The powershell argument will be executed by the Invoke-Expression command and a new PowerShell command prompt will be displayed. If no arguments are passed, the default behavior is to start monitoring the services. Since the image already has a script for that, you only need to execute it.

    Your Dockerfile will then be as follows:

    After that, you'll perform the same build and push steps as the previous example.

     context-dir\
          inetpub\
              wwwroot\
                  web.config
                  wfgen\
                      web.config
                      bin\
                          MyCustomLib.dll
                      ws\
                          bin\
                              MyCustomLib.dll
                      App_Themes\
                          Default\
                              portal\
                                  banner\
                                      banner.htm
          Program Files\
              Advantys\
                  WorkflowGen\
                      Services\
                          Bin\
                              MyCustomLib.dll
     context-dir\
          Dockerfile
          inetpub\
              wwwroot\
                  web.config
                  wfgen\
                      web.config
                      bin\
                          MyCustomLib.dll
                      ws\
                          bin\
                              MyCustomLib.dll
                      App_Themes\
                          Default\
                              portal\
                                  banner\
                                      banner.htm
          Program Files\
              Advantys\
                  WorkflowGen\
                      Services\
                          Bin\
                              MyCustomLib.dll
     #escape=`
     FROM advantys/workflowgen:7.18.3-win-ltsc2019-onbuild
    
     # You can add any instructions in order to install other services or tools, etc.
     # You also can add other files at any other location in the container.
     Set-Location C:\Path\To\context-dir
     docker image build -t mycorporation/workflowgen:7.18.3-win-ltsc2019 .
    
     # Optionally, you can push your custom image to your container registry
     docker image push mycorporation/workflowgen:7.18.3-win-ltsc2019
     version: '3.7'
     services:
       workflowgen:
         build:
           context: .
           dockerfile: .\Dockerfile
         image: mycorporation/workflowgen:7.18.3-win-ltsc2019
         restart: always
         env_file:
           - '.\workflowgen.env'
         ports:
           - '8080:80'
         volumes:
           - 'wfgdata:C:\wfgen\data'
           - 'licenses:C:\wfgen\licenses:RO'
         depends_on:
           - database
       database:
         image: advantys/workflowgen-sql:7.18.3-express-win-ltsc2019
         env_file:
           - '.\database.env'
         volumes:
           - 'sqldata:C:\wfgen\sql'
     
     volumes:
       wfgdata:
       licenses:
         external: true
       sqldata:
     
     docker-compose build workflowgen
     docker-compose up --build
     docker-compose push workflowgen
    <#
    .SYNOPSIS
        Add the custom web application to IIS.
    .NOTES
        File name: custom-web-app-install.ps1
    #>
    #requires -Version 5.1
    Import-Module IISAdministration
    Import-Module C:\Const.psm1 -Variable Constants
    Import-Module C:\Utils.psm1 -Fonction "Get-EnvVar"
    
    $wfgenStartService = (Get-EnvVar "WFGEN_START_SERVICE" -DefaultValue "all").ToLower()
    $isWebServices = $wfgenStartService -eq $Constants.SERVICE_ALL -or
        $wfgenStartService -eq $Constants.SERVICE_WEB_APPS
    
    if ($isWebServices -and (Get-WebApplication -Site "wfgenroot" -Name "wfgen/wfapps/<YOUR_WEB_SERVICE_NAME>").Count -le 0) {
        Write-Host "CONFIG: Adding mywebapp to IIS ... " -NoNewLine
        ConvertTo-WebApplication -PSPath "IIS:\Sites\wfgenroot\wfgen\WfApps\<YOUR_WEB_SERVICE_NAME>" | Out-Null
        Write-Host "done" -ForegroundColor Green
    }
    
    if ($args.Count -gt 0) {
        Invoke-Expression ($args -join " ")
    } else {
        . C:\monitor-services.ps1
    }
    #escape=`
    FROM advantys/workflowgen:7.18.3-win-ltsc2019-onbuild
    
    SHELL ["powershell", "-Command"] 
    
    COPY .\custom-web-app-install.ps1 C:\
    CMD C:\custom-web-app-install.ps1
    microsoft/IIS.ServiceMonitor
     docker container run -it `
         # ...
         mycorporation/workflowgen:7.18.3-win-ltsc2019 C:\custom-web-app-install.ps1 powershell

    Configuration

    Overview

    This section explains how to completely configure a WorkflowGen database container. Everything is configurable via an environment variable.

    • This image is based on (SQL Server 2017) for the Windows LTSC 2019 version, and on (SQL Server 2019) for the Linux (Ubuntu 18.04) version.

    • To support Windows LTSC 2019, the base image has been rebuilt using the and hosted on Advantys' Docker Hub repository. Therefore, the actual base image is .

    • The Windows version of this image is intended for development and testing only. For production workloads, use the Linux version.

    Environment variables

    Variables specific to the base images

    Some variables are available in the base images that provide functionalities related to SQL Server. For the Linux version, see the Docker Hub page and the Microsoft article. For the Windows version, see the Docker Hub page.

    Some environment variables in the base images are required. For example, you have to provide a value for the SA_PASSWORD environment variable.

    Variables specific to WorkflowGen

    The WorkflowGen database container adds special environment variables to enable additional features related to WorkflowGen. The following table provides descriptions for each of them:

    Format-based environment variables

    Secrets

    When using an orchestrator such as Kubernetes, you'll probably want to secure secrets using their built-in secret management tools. Follow the specific guide for your orchestrator to know how to create a secret.

    For Kubernetes, see .

    It's recommended to inject secrets into WorkflowGen containers as files because they won't be exposed as environment variables and they'll be removed from the container when it's stopped or removed.

    Secrets management is only possible using an orchestrator.

    In order to get the secret value in the file, you need to suffix any environment variable you want to get the value of in this way with _FILE and set its value to the path of the file containing the secret. The container will then get the value in the file at the specified path and set the environment variable without the suffix with that value.

    For example, let's say you want to set sa account password in SQL Server to strong(!)Pass using the environment variable SA_PASSWORD, but you want to use a secret for the value. All you have to do is suffix the environment variable name with _FILEso that it becomes SA_PASSWORD_FILE. Then, set the value of this variable to the path of the file containing the password.

    📌 Example with Docker Swarm orchestrator

    For Kubernetes, you would create a ConfigMap that complements your secret like this:

    Then, you would map the ConfigMap as environment variables and mount the secret as a volume like this:

    Using an orchestrator

    Kubernetes

    Kubernetes also has a built-in object called ConfigMap to manage pod configuration. See the Kubernetes article for more information and how to use it. You should use this object to configure environment variables for WorkflowGen.

    You can also manage sensitive information by protecting it further in the orchestrator in a secure area. See the Kubernetes article for more information and instructions on how to use it. You should use this object to protect sensitive information such as the WorkflowGen license key, usernames, passwords, cryptographic keys, API keys, etc.

    Using an external configuration manager

    Some popular configuration managers support Docker containers out-of-the-box. Here are a few links to their specific documentation to get you started:

    Chef

    Ansible

    Puppet

    About security features

    The Linux version of the database has some security features that can be used to improve the overall security of the database. For more information on security features in SQL Server for Linux, see in the Microsoft SQL Server documentation.

    The Windows version of the container doesn't have the security features of the Linux version. It's advised to use the Windows version only for development and testing purposes.

    Performance & high availability

    You can configure replication with this container, but you'll have to make a custom image. For more information about making a custom image, see the page of this section. For more information about configuring replication in SQL Server, see in the Microsoft documentation.

    Use with Kubernetes

    You should always deploy the database container within a StatefulSet so that each container has its own separated storage. It also ensures that each container has a unique DNS name inside the cluster so that it can be found easily by other containers. You can also configure each of the instances based on an incremental identifier so that you can set a read/write instance and several read-only instances. Here's an example of a simple StatefulSet deployment with the WorkflowGen database container:

    You can use this example as a starting point to configure multiple database containers. For more information about StatefulSets, see in the Kubernetes documentation. You might need custom code to be able to configure multiple instances properly. See the page of this section for more information about how you can add custom code to the container.

    The username of the WorkflowGen administrative user

    Default value: wfgen_admin

    WFGEN_ADMIN_PASSWORD

    Required variable

    The password of the WorkflowGen administrative user

    WFGEN_AUTH_APPLICATION

    Indicates if the authentication method of WorkflowGen is applicative or not

    Possible values: Y (default), N

    Variable

    Description & values

    WFGEN_DATABASE_NAME

    The name of the WorkflowGen database

    Default value: WFGEN

    WFGEN_DATABASE_CONTAINMENT

    Sets the WorkflowGen database to contain database users for more portability (see contained database authentication Server configuration option for more information)

    Possible values: Y (default), N

    WFGEN_DATABASE_USER_USERNAME

    The username of the database user that has access to the WorkflowGen database

    Default value: WFGEN_USER

    WFGEN_DATABASE_USER_PASSWORD

    Required variable

    The password of the database user that has access to the WorkflowGen database

    WFGEN_DATABASE_FILE_PATH

    Do not modify for Linux version

    Internal path to the .mdf and .ldf database files inside the container

    Default value:

    • Windows: C:\wfgen\sql

    • Linux: /var/opt/mssql/data

    microsoft/mssql-server-windows-express
    mcr.microsoft.com/mssql/server
    open sourced Dockerfile
    advantys/mssql-server-windows-express
    mcr.microsoft.com/mssql/server
    Deploy and connect to SQL Server Linux containers
    microsoft/mssql-server-windows-express
    https://kubernetes.io/docs/concepts/configuration/secret/
    Configure a Pod to Use a ConfigMap
    Secrets
    Docker Cookbook
    Chef and Kubernetes
    Ansible and Docker
    How to run Puppet in Docker
    Configure SQL Server container images on Docker
    Custom Image
    Configure a SQL Server Availability Group for read-scale on Linux
    StatefulSets
    Custom Image

    WFGEN_ADMIN_USERNAME

    # Create the secret for the license serial number
    'strong(!)Pass' | docker secret create SA_PASSWORD -
    
    # Create the container service in Docker Swarm
    docker service create `
        # ...
        --env WFGEN_APP_SETTING_ApplicationSerialNumber_FILE=/run/secrets/SA_PASSWORD `
        --secret SA_PASSWORD `
        # ...
        advantys/workflowgen-sql:7.18.3-ubuntu-18.04
    # Create the secret for the license serial number
    echo 'strong(!)Pass' | docker secret create SA_PASSWORD -
    
    # Create the container service in Docker Swarm
    docker service create \
        # ...
        --env WFGEN_APP_SETTING_ApplicationSerialNumber_FILE=/run/secrets/SA_PASSWORD \
        --secret SA_PASSWORD \
        # ...
        advantys/workflowgen-sql:7.18.3-ubuntu-18.04
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: database-config
    data:
      SA_PASSWORD_FILE: /mnt/secrets/SA_PASSWORD
    ---
    apiVersion: v1
    kind: Secret
    type: Opaque
    metadata:
      name: database-secret
    data:
      # "c3Ryb25nKCEpUGFzcwo=" is the base64-encoded value of "strong(!)Pass"
      SA_PASSWORD: 'c3Ryb25nKCEpUGFzcwo='
    
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: wfgen-database
    spec:
      selector:
        matchLabels:
          # ...
      template:
        metadata:
          labels:
            # ...
        spec:
          containers:
            - name: database
              image: advantys/workflowgen-sql:7.18.3-ubuntu-18.04
              # ...
              envFrom: # ConfigMap as environment variables
                - configMapRef:
                    name: database-config
              # ...
              volumeMounts:
                # ...
                - mountPath: /mnt/secrets # Mount Secret as a volume
                  readOnly: true
                  name: secrets
          volumes:
            # ...
            - name: secrets # Mount Secret as a volume
                secret:
                  secretName: database-secret
    apiVersion: v1
    kind: Service
    metadata:
      name: database
    spec:
      type: ClusterIP
      clusterIP: None
      ports:
        - port: 1433
          targetPort: mssql
          protocol: TCP
          name: mssql
      selector:
        app.kubernetes.io/name: workflowgen
        app.kubernetes.io/component: database
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: database
    spec:
      replicas: 1
      serviceName: database
      selector:
        matchLabels:
          app.kubernetes.io/name: workflowgen
          app.kubernetes.io/component: database
      template:
        metadata:
          labels:
            app.kubernetes.io/name: workflowgen
            app.kubernetes.io/component: database
        spec:
          terminationGracePeriodSeconds: 10
          nodeSelector:
            kubernetes.io/os: linux
          containers:
            - name: database
              image: advantys/workflowgen-sql:7.18.3-ubuntu-18.04
              imagePullPolicy: Always
              securityContext:
                runAsUser: 0
                runAsGroup: 0
              resources:
                requests:
                  memory: "1Gi"
                  cpu: "500m"
                limits:
                  memory: "2Gi"
                  cpu: "1"
              envFrom:
                - configMapRef:
                    name: database-config
              ports:
                - name: mssql
                  containerPort: 1433
              livenessProbe:
                initialDelaySeconds: 30
                timeoutSeconds: 5
                exec:
                  command:
                    - pwsh
                    - -NoLogo
                    - -NoProfiles
                    - /usr/local/bin/healthcheck.ps1
              readinessProbe:
                initialDelaySeconds: 20
                timeoutSeconds: 5
                exec:
                  command:
                    - pwsh
                    - -NoLogo
                    - -NoProfiles
                    - /usr/local/bin/healthcheck.ps1
              volumeMounts:
                - mountPath: /var/opt/mssql
                  name: sqldata
                - mountPath: /mnt/secrets
                  readOnly: true
                  name: secrets
          volumes:
            - name: secrets
                secret:
                  secretName: database-sec
      volumeClaimTemplates:
        - metadata:
            name: sqldata
          spec:
            accessModes:
              - ReadWriteOnce
            storageClassName: default
            resources:
              requests:
                storage: 100Gi

    Recommended Architectures

    Overview

    This section presents the recommended container architecture for WorkflowGen in order to run the web portals and Windows services. There will be many references to the image configuration properties; see the Configuration section for information on these.

    This section is only about container architecture. SQL data and volumes should always be used regardless of the architecture.

    See the section for information on SQL database deployments, and the section for information on volume deployment.

    Single container

    This is the simplest architecture you can run with WorkflowGen: a single container without replicas that runs both web applications and Windows Services. Therefore, you would set the WFGEN_START_SERVICE environment variable to all. This architecture is well suited to development and test environments, but it can also be considered when the performance with a single container fits the product usage. You can't replicate the container because there should only be one instance of each WorkflowGen Windows Service running.

    Docker Compose example

    This is the same example as in the section. It has one WorkflowGen container that runs every service (web applications and Windows Services).

    Helm example

    This example is different from the example. This Helm release is not scalable in the cluster. It has a pod that runs all of the WorkflowGen services (web applications and Windows services) and another pod for the database. You can use the steps in the example to generate the requested values. Don't forget to get the external IP address of the load balancer once it's created.

    Multiple web application instances, single Windows Services instance

    Since there can be only one instance of each WorkflowGen Windows Service running at a time, this architecture lets you run multiple replicas of the web applications in order to scale WorkflowGen to meet your traffic and processing needs without having more instances of the Windows Services.

    You'll need to set the WFGEN_START_SERVICE environment variable to web_apps for the web applications' containers, and to win_services for the single container to run all of the Windows Services without web applications. This architecture is good for scaling the web portals to the traffic and processing needs, without too much pressure on the Windows Services.

    Docker Compose example

    Helm example

    This is the same example as in the section. The Windows Services containers will always be in the same pod when you use the WorkflowGen Helm chart. You can use the steps in the example to generate the requested values. Don't forget to get the external IP address of the load balancer once it's created.

    Multiple web application instances, dedicated Windows services containers

    This recommended architecture is the most scalable. It has multiple containers for the web applications that can be scaled for increased traffic or processing needs, and has dedicated containers for each Windows Service: one for the directory synchronization service and one for the engine service. Therefore, you would set the WFGEN_START_SERVICE environment variable to web_apps for the web applications' containers, to dir_sync for the directory synchronization service container, and to engine for the engine service container. This architecture is good for high availability and high performance scenarios.

    Docker Compose example

    Helm example

    This is the same example as in the section. The Windows services containers will always be in the same pod when you use the WorkflowGen Helm chart. You can use the steps in the example to generate the requested values. Don't forget to get the external IP address of the load balancer once it's created.

    SQL Server Hosting Options
    File Management
    Getting Started
    Getting Started
    Getting Started
    Getting Started
    Getting Started
    Getting Started
    Getting Started
    Single container architecture
    Multiple web application instances, single Windows services instance
    Multiple web application instances, dedicated Windows services containers

    Configuration

    Overview

    This section explains how to completely configure a WorkflowGen container, including the web.config file, iisnode configuration for Node.js applications, database connection strings, etc. Everything is configurable via an environment variable except the license file, which is configured via a volume.

    WorkflowGen environment variables

    WorkflowGen's image provides a number of specific environment variables that makes specific configurations possible. The following table provides descriptions of each of them:

    Format-based environment variables

    WorkflowGen's image also exposes various environment variables based on a specific format in order to configure more generic elements.

    web.config

    In WorkflowGen, the web.config file is the main point of configuration. Since a container is by definition ephemeral, any changes made in the Configuration Panel would not persist between container restarts.

    In order to set configuration properties in the web.config file, you need to use a specific format for an environment variable that will contain the value of the property you want to set; this format is WFGEN_APP_SETTING_<name>.

    For example, if you want to set the ApplicationUrl property in the web.config to https://mycorporation.com/wfgen, you would set the WFGEN_APP_SETTING_ApplicationUrl=https://mycorporation.com/wfgen environment variable in the container.

    📌 Example with the run command

    For a list of web.config parameters and their descriptions and possible values, see the appendix in the .

    iisnode configuration for Node.js applications

    You can also set specific iisnode properties for each Node.js application. To do this, you need to set an environment variable with the following format: WFGEN_IISNODE_<node name>_<property name>.

    • Replace <node name> with the name of the Node.js application (AUTH, HOOKS, GRAPHQL, or SCIM).

    • Replace <property name> with the name of the property you want to set for the <iisnode/> XML node in the specific Node.js application's web.config

    For example, if you want to set the iisnode loggingEnabled property in the Auth application to true, you would set the environment variable WFGEN_IISNODE_AUTH_loggingEnabled=true.

    📌 Example with the run command

    Special iisnode options for Node.js applications

    There are some special options that you can enable for each Node.js application by setting an environment variable that has the following template: WFGEN_ENABLE_IISNODE_OPTION_<node app name>. Then, you replace <node app name> with the name of the Node.js application (AUTH for example) and the value must be one of the following:

    Database configuration

    Main connection string

    The main connection string can be configured via the WFGEN_DATABASE_CONNECTION_STRING environment variable. You can put any string in this variable and its value will be put in WorkflowGen's web.config file at the MainDbSource connection string.

    Here's how to specify the connection string with the run command:

    Read-only connection string

    If you have a read-only replica, you can configure it in the container as well. You can specify it with the WFGEN_DATABASE_READONLY_CONNECTION_STRING environment variable. It will be added to WorkflowGen's web.config file as a new entry in the connection strings with the name ReadOnlyDbSource.

    Here's how to specify the read-only connection string with the run command:

    Custom connection strings

    You can also configure more connections to custom data sources if you need to. They can be configured using a specific environment variable format: WFGEN_CUSTOM_CONNECTION_STRING_<name>=<connection_string>.

    For example, if you want a data source named MyDataSource with the connection string value of MyConnectionString in the WorkflowGen web.config, you would specify the following environment variable: WFGEN_CUSTOM_CONNECTION_STRING_MyDataSource=MyConnectionString.

    📌 Example with the run command

    Secrets

    When using an orchestrator such as Kubernetes, you'll probably want to secure secrets using their built-in secret management tools. Follow the specific guide for your orchestrator to know how to create a secret.

    For Kubernetes, see .

    It's recommended to inject secrets into WorkflowGen containers as files because they won't be exposed as environment variables and they'll be removed from the container when it's stopped or removed.

    Secrets management is only possible using an orchestrator.

    In order to get the secret value in the file, you need to suffix any environment variable you want to get the value of this way with _FILE and set its value to the path of the file containing the secret. The container will then get the value in the file at the specified path and set the environment variable without the suffix with that value.

    For example, let's say you want to set the license serial number in the web.config to WFG-SOME-LICENSE-KEY using the environment variable WFGEN_APP_SETTING_ApplicationSerialNumber, but you want to use a secret for the value. All you have to do is suffix the environment variable name with _FILE so it becomes WFGEN_APP_SETTING_ApplicationSerialNumber_FILE. Then, set the value of this variable to the path of the file containing the serial number.

    📌 Example with Docker Swarm orchestrator

    For Kubernetes, you would create a ConfigMap that complements your secret like this:

    Then, you would map the ConfigMap as environment variables and mount the secret as a volume like this:

    Configuring the authentication mode

    For all authentication modes, you need to set WFGEN_APP_SETTING_ApplicationUrl and WFGEN_APP_SETTING_ApplicationSerialNumber in order to avoid unwanted behaviors.

    Application authentication

    In order to let WorkflowGen handle authentication and the storage of user passwords, you don't need to configure anything special in the container. Keep in mind that the default username for the WorkflowGen administrative account is wfgen_admin.

    Windows and Basic authentication

    In order to make Windows or Basic authentication modes work, your host needs to be in an Active Directory forest. Creating a user account on the host for Basic authentication won't work, because the IIS web server inside the container will try to find a user account registered inside the container instead of the host. For this reason, you need Active Directory.

    To configure your Docker host to work with Active Directory to authenticate users, follow the (gMSA) guide from Microsoft in its Windows Containers documentation.

    Kubernetes supports gMSAs for Windows pods and containers as of version 1.18. See the Kubernetes article for details on how to configure it. Keep in mind that not all cloud providers supports gMSAs with Kubernetes. For example, Azure Kubernetes Service doesn't support this feature.

    You can't use Basic authentication with Kubernetes.

    Azure v1 and Microsoft Identity Platform

    For these providers, there is no special configuration to do other than setting the WFGEN_AUTH_MODE variable. For configuration instructions, see the guide.

    Active Directory Federation Services (AD FS), Auth0, and Okta

    For these providers, there is no special configuration to do other than setting the WFGEN_AUTH_MODE variable. For configuration instructions, see the .

    Configuring your license

    In order to configure your license, you need to set a specific environment variable with your license and copy your license file into a volume exposed to the WorkflowGen container. To do this, you first need to create a license volume or have your license at a specific path.

    Create a volume

    This will create a volume at a specific path on your file system (typically C:\ProgramData\Docker\volumes\licenses\_data) managed by Docker. You can get the path to the volume by executing the following command:

    Then, you need to copy your license file to this location:

    Now, you can run the WorkflowGen container like so:

    Use a specific path

    Here, you'll provide a path that you control as a volume to the container. You only need to pass the path when you run WorkflowGen:

    Bringing the WorkflowGen website offline

    You can bring the web applications inside WorkflowGen's container offline by executing a script embedded in the image. This is useful to ensure that the site is still available when you want to perform maintenance tasks on its data without anything new being written. With pure containers, you can execute the following command:

    With Kubernetes, you can use kubectl:

    You must do this for each WorkflowGen container that is running. The recommended approach is to scale down the number of containers to one and execute the set-state.ps1 script once.

    If you browse to your WorkflowGen website, you'll see the default offline web page. You can customize this web page by adding your own HTML file at the path <wfgen appdata>\Templates\server\offline.htm. If this file is present, it will be taken instead of the default one. If you have a volume for WorkflowGen's data, you can execute the following script:

    You can bring the site back online by executing the following command:

    Using an orchestrator

    Kubernetes

    Kubernetes also has a built-in object called ConfigMap to manage pod configuration. See the Kubernetes article for more information and instructions on how to use it. You should use this object to configure environment variables for WorkflowGen.

    You can also manage sensitive information by protecting it further in the orchestrator in a secure area. See the Kubernetes article for more information and instructions on how to use it. You should use this object to protect sensitive information such as the WorkflowGen license key, usernames, passwords, cryptographic keys, API keys, etc.

    Using your own configuration files

    In order to use your own configuration files, you should build your own WorkflowGen image using the WorkflowGen onbuild image variant. See the page in the WorkflowGen Image section for more information.

    Using an external configuration manager

    Some popular configuration managers support Docker containers out-of-the-box. Here are a few links to their specific documentation to get you started:

    Chef

    Ansible

    Puppet

    Cluster Management Tools

    Overview

    This section presents some tools that you can use to administer a cluster of containers.

    Kubernetes Dashboard

    version: '3.7'
    services:
      workflowgen:
        image: advantys/workflowgen:7.18.3-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        ports:
          - '8080:80'
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      database:
        image: advantys/workflowgen-sql:7.18.3-express-win-ltsc2019
        env_file:
          - '.\database.env'
        volumes:
          - 'sqldata:C:\wfgen\sql'
    
    volumes:
      wfgdata:
      licenses:
        external: true
      sqldata:
      
    scalable: false
    
    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
    
    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
    
    version: '3.7'
    services:
      workflowgen-web-apps:
        image: advantys/workflowgen:7.18.3-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        environment:
          WFGEN_START_SERVICE: web_apps
        ports:
          - '8080:80'
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      workflowgen-win-services:
        image: advantys/workflowgen:7.18.3-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        environment:
          WFGEN_START_SERVICE: win_services
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      database:
        image: advantys/workflowgen-sql:7.18.3-express-win-ltsc2019
        env_file:
          - '.\database.env'
        volumes:
          - 'sqldata:C:\wfgen\sql'
    
    volumes:
      appdata:
      licenses:
        external: true
      sqldata:
      
    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
    
    version: '3.7'
    services:
      workflowgen-web-apps:
        image: advantys/workflowgen:7.18.3-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        environment:
          WFGEN_START_SERVICE: web_apps
        ports:
          - '8080:80'
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      workflowgen-dir-sync-service:
        image: advantys/workflowgen:7.18.3-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        environment:
          WFGEN_START_SERVICE: dir_sync
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      workflowgen-engine-service:
        image: advantys/workflowgen:7.18.3-win-ltsc2019
        restart: always
        env_file:
          - '.\workflowgen.env'
        environment:
          WFGEN_START_SERVICE: engine
        volumes:
          - 'wfgdata:C:\wfgen\data'
          - 'licenses:C:\wfgen\licenses:RO'
        depends_on:
          - database
      database:
        image: advantys/workflowgen-sql:7.18.3-express-win-ltsc2019
        env_file:
          - '.\database.env'
        volumes:
          - 'sqldata:C:\wfgen\sql'
    
    volumes:
      wfgdata:
      licenses:
        external: true
      sqldata:
    
    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
    
    Kubernetes comes installed with its own management portal called the Dashboard. See the Web UI (Dashboard) Kubernetes article for more information.

    See the Access the Kubernetes web dashboard in Azure Kubernetes Service (AKS) Microsoft article for instructions on how to connect to it in Azure Kubernetes Service.

    VMware Octant

    Octant is an open source software from VMware to visualize Kubernetes clusters. You can also edit some YAML definitions and forward ports directly to your machine.

    File name (including extension) of the license needed in the C:\licenses volume

    If none is specified, the first file found is taken.

    WFGEN_START_SERVICE

    Indicates what the container should run

    You can either run the WorkflowGen web application or Windows Services, or both. In a cluster, you'd probably want to have multiple containers in web app mode and only one container in Windows Services mode. You can also divide more by running multiple containers in web app mode, one container in engine mode, and one container in directory sync mode.

    Possible values:

    • all (default)

    WFGEN_MACHINE_KEY_VALIDATION_KEY

    Represents the validationKey property of the machineKey element in the web.config file

    By default, IIS generates one when it isn't there. It's recommended to use this environment variable to share the machine key between instances of this container (e.g. in a web farm). See the and Microsoft articles for more details.

    WFGEN_MACHINE_KEY_DECRYPTION_KEY

    Represents the decryptionKey property of the machineKey element in the web.config file

    By default, IIS generates one when it isn't there. It's recommended to use this environment variable to share the machine key between instances of this container (e.g. in a web farm). See the and Microsoft articles for more details.

    WFGEN_MACHINE_KEY_VALIDATION_ALG

    Represents the validation property of the machineKey element in the web.config file

    The algorithm name used to generate the validation key. Default: HMACSHA256

    WFGEN_MACHINE_KEY_DECRYPTION_ALG

    Represents the decryption property of the machineKey element in the web.config file

    The algorithm name used to generate the decryption key. Default: AES

    WFGEN_DEPENDENCY_CHECK_INTERVAL

    Time between dependency check retries in milliseconds

    Default: 1000 (1 second)

    WFGEN_DEPENDENCY_CHECK_RETRIES

    Number of retries to attempt for each dependency check

    Default: 10

    WFGEN_DEPENDENCY_CHECK_ENABLED

    Indicates whether or not the dependency check should be done

    Possible values: Y (default), N

    WFGEN_GRAPHQL_CORS_ENABLED

    Enables CORS headers for the GraphQL API

    Possible values: Y (default), N

    WFGEN_GRAPHQL_CORS_ALLOWED_ORIGINS

    Comma-separated list of origins from which CORS will allow requests

    Default: *

    file.

    Variable

    Description & values

    WFGEN_ADMIN_USERNAME

    The username for the WorkflowGen administrator account

    Changing this value is useful when you are configuring this image with an OpenID provider. You can set it to a username that exists on the provider that you have access to. Then, when you browse to WorkflowGen, you can authenticate with it and it will log you in as an administrator.

    For example, if you have a username on your provider named [email protected], then you can set this environment variable to this username and authenticate with it in the container to have administrative access to WorkflowGen. ✏️ Note: If you change this, make sure to update the database as well.

    Possible values: wfgen_admin (default)

    WFGEN_DATABASE_CONNECTION_STRING

    Required variable

    The connection string of the main database source

    This environment variable must be present, or else the container will throw an error and exit.

    WFGEN_DATABASE_READONLY_ CONNECTION_STRING

    The connection string of the read-only database source for a database setup with replicas

    WFGEN_AUTH_MODE

    This variable indicates which authentication method to be used by WorkflowGen

    Possible values:

    • adfs

    • application (default)

    • auth0

    • azure-v1

    • basic

    • ms-identity-v2

    • okta

    • windows

    WFGEN_GEN_APP_SYM_ENCRYPT_KEY

    Indicates whether or not the ApplicationSecurityPasswordSymmetricEncryptionKey should be generated if no value is provided

    If Y, the ApplicationSecurityPasswordSymmetricEncryptionKey is regenerated when the container restarts. It is not compatible for usage in production because the secrets will be encrypted with different keys. Therefore, use Y only for developing or testing a single container scenario.

    Possible values: Y (default), N

    Value name

    Description

    exposelogs

    Exposes the logs of the application through http. They will then be available at https://example.com/wfgen/auth/iisnode if the chosen Node.js application is AUTH.

    ✏️ Note: This option is for debugging purposes only. It is not recommended to use it in production.

    Web and Application Configuration Parameters
    WorkflowGen Technical Guide
    https://kubernetes.io/docs/concepts/configuration/secret/
    Group Managed Service Account
    Configure GMSA for Windows Pods and containers
    WorkflowGen for Azure
    WorkflowGen Technical Guide
    Configure a Pod to Use a ConfigMap
    Secrets
    Custom Image
    Docker Cookbook
    Chef and Kubernetes
    Ansible – Getting started with Docker
    k8s – Manage Kubernetes (K8s) objects
    How to run Puppet in Docker
    How to Install and Configure Kubernetes with the Puppet Kubernetes Module

    WFGEN_LICENSE_FILE_NAME

    docker container run `
        # ...
        --env 'WFGEN_APP_SETTING_ApplicationUrl=https://mycorporation.com/wfgen' `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    docker container run `
        # ...
        --env WFGEN_IISNODE_AUTH_loggingEnabled=true `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    docker container run `
        # ...
        --env WFGEN_DATABASE_CONNECTION_STRING=SomeConnectionString `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    docker container run `
        # ...
        --env WFGEN_DATABASE_CONNECTION_STRING=SomeConnectionString `
        --env WFGEN_DATABASE_READONLY_CONNECTION_STRING=SomeReadOnlyConnectionString `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    docker container run `
        # ...
        --env WFGEN_DATABASE_CONNECTION_STRING=SomeConnectionString `
        --env WFGEN_DATABASE_READONLY_CONNECTION_STRING=SomeReadOnlyConnectionString `
        --env WFGEN_CUSTOM_CONNECTION_STRING_MyDataSource=MyConnectionString `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    # Create the secret for the license serial number
    "WFG-SOME-LICENSE-KEY" | docker secret create ApplicationSerialNumber -
    
    # Create the container service in Docker Swarm
    docker service create `
        # ...
        --env WFGEN_APP_SETTING_ApplicationSerialNumber_FILE=C:\ProgramData\Docker\secrets\ApplicationSerialNumber `
        --secret ApplicationSerialNumber `
        # ...
        advantys/workflowgen:7.18.3-win-ltsc2019
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: wfgen-config
    data:
      WFGEN_APP_SETTING_ApplicationSerialNumber_FILE: C:\secrets\ApplicationSerialNumber
    ---
    apiVersion: v1
    kind: Secret
    type: Opaque
    metadata:
      name: wfgen-secret
    data:
      # "V0ZHLVNPTUUtTElDRU5TRS1LRVkK" is the base64-encoded value of "WFG-SOME-LICENSE-KEY"
      ApplicationSerialNumber: 'V0ZHLVNPTUUtTElDRU5TRS1LRVkK'
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wfgen
    spec:
      selector:
        matchLabels:
          # ...
      template:
        metadata:
          labels:
            # ...
        spec:
          containers:
            - name: wfgen
              image: advantys/workflowgen:7.18.3-win-ltsc2019
              # ...
              envFrom: # ConfigMap as environment variables
                - configMapRef:
                    name: wfgen-config
              env:
                - name: WFGEN_START_SERVICE
                  value: webapps
              # ...
              volumeMounts:
                # ...
                - mountPath: C:\secrets # Mount Secret as a volume
                  readOnly: true
                  name: secrets
          volumes:
            # ...
            - name: secrets # Mount Secret as a volume
                secret:
                  secretName: wfgen-sec
    docker volume create licenses
    docker volume inspect -f "{{.Mountpoint}}" licenses
    Copy-Item C:\Path\To\WorkflowGen.lic $(docker volume inspect -f "{{.Mountpoint}}" licenses)
    docker container run `
        # ...
        --env WFGEN_APP_SETTING_ApplicationSerialNumber=YOUR-WFG-LIC-NUM `
        --mount "type=volume,src=licenses,dst=C:\wfgen\licenses,readonly" `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    docker container run `
        # ...
        --env WFGEN_APP_SETTING_ApplicationSerialNumber=YOUR-WFG-LIC-NUM `
        --mount "type=bind,src=C:\Path\To\Your\Licenses,dst=C:\wfgen\licenses,readonly" `
        # ...
        advantys/workflowgen:7.16.0-win-ltsc2019
    docker container exec -i wfgen powershell C:\set-state.ps1 Offline
    kubectl exec -i wfgen-pod -- powershell C:\set-state.ps1 Offline
    $offlinePath = ".\offline.htm"
    $serverTemplatePath = [io.path]::Combine(
        $(docker volume inspect --format "{{ .Mountpoint }}" wfgdata),
        "appdata" , "Template", "server"
    )
    
    if (-not (Test-Path $serverTemplatePath)) {
        New-Item $serverTemplatePath -ItemType Directory -Force
    }
    
    Copy-Item $offlinePath $serverTemplatePath
    
    docker container exec -i wfgen powershell C:\set-state.ps1 Online
    kubectl exec -i wfgen-pod -- powershell C:\set-state.ps1 Online

    dir_sync

  • engine

  • web_apps

  • win_services

  • Resolving view state message authentication code (MAC) errors
    MachineKeySection Class
    Resolving view state message authentication code (MAC) errors
    MachineKeySection Class

    Custom Image

    Overview

    This page explains how to create a custom image of the WorkflowGen database in order to add custom code or SQL scripts to execute. Keep in mind that this guide provides simple examples, so you're not limited to what is shown here. The examples will use the Linux version of the image. All code examples are in PowerShell.

    Prerequisites

    • A Linux machine with Docker installed. See the specific instructions for your distribution to install and configure the Docker engine. See for installation instructions. It might not have all the supported distributions.

    • A Mac with installed.

    • A Windows 10 Pro machine with installed and the Linux containers enabled. It is recommended to use the WSL 2 (Windows Subsystem for Linux) backend if available. Otherwise, use the default.

    Simple example

    Creating your own WorkflowGen image is as simple as creating a Dockerfile file. Create a context directory and add an empty file called Dockerfile to it:

    File tree:

    You'll then open the Dockerfile and add some code to it:

    This instruction says that you want to base your image on the WorkflowGen database image. From here, you can add other instructions to add some files or scripts to execute and perform the custom initialization that you want. For example, you could add a custom SQL script and execute it:

    File tree:

    Dockerfile:

    As you can see, PowerShell is available in the Linux container so that scripting can be done easily between Windows and Linux. If you prefer Bash scripting, you can use it just as easily by replacing the .ps1 script by your own .sh script.

    customcode.ps1:

    This script looks like a lot but is in fact simple. It begins by importing the SqlServer, Utils, and Crypto libraries, then gets some information from the environment and initializes variables based on that. Afterward, it checks if the database has already been created by checking for the existence of an .mdf file before hashing and salting a custom secret, creating a custom database and executing a script with a prepared variable. If there are no arguments passed to the script, it restarts the SQL Server process so that its logs are written to the standard output. If there are some arguments, it executes what is passed.

    The condition to check if the database is already created is there because the script will be executed after each container restart and run. Therefore, the state files including the .mdf and .ldf files of all the databases inside SQL Server will already be there. There will be no need to re-create the database.

    The last part is a general good practice in a Docker container. For example, if you're debugging the container and only want to prompt a PowerShell command line after the start sequence, you would pass powershell as an argument to the run command like so:

    The powershell argument will be executed by the Invoke-Expression command and a new PowerShell command prompt will be displayed.

    Now, all you have to do is build the container:

    Scripts available in the image

    Advantys has developed some PowerShell scripts and modules to take care of some functionalities. Here's a list of those scripts with their descriptions:

    • docker-entrypoint.ps1: This is the main script that gets executed when you run a container. It handles the parsing of environment variables, initialization of the WorkflowGen database, etc.

      • Windows path: C:\docker-entrypoint.ps1

      • Linux path: /usr/local/bin/docker-entrypoint.ps1

    Getting Started

    Overview

    This section presents how to quickly run the WorkflowGen container with a minimal architecture on Kubernetes.

    There are known limitations when using Hyper-V isolation with the WorkflowGen container in WorkflowGen versions 7.19.x and earlier. It's recommended to use

  • C:\monitor-database.ps1 (Windows version only): This script handles the monitoring of the database process, as well as gathering the container logs and redirecting them to the standard output. The Linux version doesn't need this script because the SQL Server process runs in the foreground and writes its logs in the standard output.

  • /usr/local/bin/healthcheck.ps1 (Linux version only): This script handles the periodic check that indicates if the database is working properly or not. This is defined in the Dockerfile and is handled by the Docker engine. The Windows version also has a healthcheck defined. It's a simple command that doesn't need its own script. In Kubernetes, it's ignored, so you must provide a liveness probe. See the Configure Liveness, Readiness and Startup Probes Kubernetes article for more information.

  • *.psm1: Various developed PowerShell modules available in the image.

    • Windows path: C:\

    • Linux path: /usr/local/lib/

  • /usr/local/bin/set-state.ps1 (Linux version only): Sets the state of the container, such as bringing the WorkflowGen database offline or online.

    • Windows path: C:\

    • Linux path: /usr/local/bin/

  • Install Docker Engine
    Docker Desktop for Mac
    Docker Desktop for Windows
    context-dir/
        Dockerfile
    FROM advantys/workflowgen-sql:7.18.3-ubuntu-18.04
    context-dir/
        Dockerfile
        myscript.sql
        customcode.ps1
    FROM advantys/workflowgen-sql:7.18.3-ubuntu-18.04
    
    COPY ./myscript.sql /usr/local/mycorporation/scripts/
    COPY ./customcode.ps1 /usr/local/bin/
    CMD /usr/local/bin/customcode.ps1
    <#
    .SYNOPSIS
        Custom script that creates a new database if not exists and executes
        a custom SQL script with a prepared variable.
    .NOTES
        File name: customcode.ps1
    #>
    #requires -Version 7.0
    
    Import-Module SqlServer
    Import-Module /usr/local/lib/Utils.psm1 -Function "Get-EnvVar"
    Import-Module /usr/local/lib/Crypto.psm1
    
    $saPassword = Get-EnvVar "SA_PASSWORD"
    $aSecret = Get-EnvVar "MYCORPORATION_SECRET"
    
    $myCustomDatabaseName = "MYDB"
    $myDatabasePath = Join-Path "/" "var" "opt" "mssql" "data" "$myCustomDatabaseName.mdf"
    $myScriptPath = Join-Path "/" "usr" "local" "mycorporation" "scripts" "myscript.sql"
    $commonArgs = @{
        ServerInstance = "localhost"
        Username = "sa"
        Password = $saPassword
    }
    
    # MYDB not created
    if (-not (Test-Path $myDatabasePath)) {
        $secretSalt = Get-Salt # from Crypto.psm1
        $secretPassHash = Get-PasswordHash ($salt + $aSecret)
    
        Invoke-Sqlcmd "CREATE DATABASE [`$(DATABASE_NAME)] CONTAINMENT = PARTIAL" `
            -Variable ,"DATABASE_NAME=$myCustomDatabaseName" `
            @commonArgs
        Invoke-Sqlcmd -InputFile $myScriptPath `
            -Variable ,"A_SECRET=$secretPassHash" `
            @commonArgs
    }
    
    if ($args.Count -gt 0 {
        Invoke-Expression $args
    } else {
        # Restart the SQL Server process so that the logs
        # are written in the standard output file
        Stop-Process -Name sqlservr -Force
        Start-Process -FilePath /opt/mssql/bin/sqlservr -Wait
    }
     docker container run -it `
         # ...
         mycorporation/workflowgen-sql:7.18.3-ubuntu-18.04 /usr/local/bin/customcode.ps1 pwsh
     docker container run -it \
         # ...
         mycorporation/workflowgen-sql:7.18.3-ubuntu-18.04 /usr/local/bin/customcode.ps1 pwsh
    Set-Location path/to/context-dir
    docker container build `
        -t mycorporation/workflowgen-sql:7.18.3-ubuntu-18.04 `
        .
    cd path/to/context-dir
    docker container build \
        -t mycorporation/workflowgen-sql:7.18.3-ubuntu-18.04 \
        .
    process isolation
    exclusively. This limitation no longer applies as of WorkflowGen version 7.20.0.

    Kubernetes with AKS

    This example is designed for Azure Kubernetes Service (AKS). To get started with AKS, see the Create a Windows Server container on an Azure Kubernetes Service (AKS) cluster using the Azure CLI Microsoft article.

    Architecture overview

    At the end of this section, you'll have this cluster configuration:

    Azure resources view
    Kubernetes objects view

    Every container in the cluster will have access to the configuration and secrets inside their namespaces. Several Azure services will be deployed by Azure Kubernetes Service. This doesn't require any manual steps other than interacting with Kubernetes itself. The load balancer that the service will create will dispatch the requests between the WorkflowGen server replicas.

    Prerequisites

    • You must have a working Kubernetes cluster with Windows Server 2019 nodes. See the Azure resources view above for a basic AKS setup. See Deploy a Windows Server container on an Azure Kubernetes Service (AKS) cluster using Azure CLI to get started with creating an AKS cluster with Windows nodes support.

    • You must have installed the kubectl command line tool and it must be connected to the cluster. See the Connect to the cluster section in the Deploy a Windows Server container on an Azure Kubernetes Service (AKS) cluster using Azure CLI Microsoft article for instructions on how to connect kubectl with AKS.

    As well, note that you should not create any other resources in Azure besides the cluster and its nodes. All required resources for the containers will be created by Kubernetes automatically. AKS is a fully-managed platform.

    Add a PersistentVolumeClaim for shared storage

    Now, you need to add a claim that represent the WorkflowGen data volume that will be used by your deployment. To do this, apply the following YAML to your cluster:

    Then, apply it to the cluster using the following command:

    Add your WorkflowGen license file to the cluster

    Kubernetes enables you to manage secrets and configurations as files inside the cluster and inject them into pods. In this case, you'll add your license file as a secret and later inject it to the WorkflowGen pod. To add your license to the cluster, execute the following command:

    Add ConfigMaps for the services

    As mentioned earlier, there is a mechanism in Kubernetes that allows you to manage your containers' configurations. Here, you'll create one for WorkflowGen and another for the database:

    The WFGEN_APP_SETTING_ApplicationUrl value will be changed to the load balancer's IP address after creating the WorkflowGen services. Therefore, it doesn't matter for now what is put in there because it will be changed later in this example.

    Don't forget to apply this configuration:

    Add secrets for the services

    Kubernetes also manages secrets for you. They are securely stored and only given to the containers as files.

    You need an encryption key to put as a secret:

    Before creating the secrets, you must encode them in base64:

    Replace <YOUR_WFG_LIC_KEY> with your WorkflowGen license key, and replace <YOUR_NEW_GUID> with the GUID that you generated.

    Those encoded values will go into the secrets declaration. To create the required secrets for the services, apply the following YAML:

    Replace <YOUR_WFG_LIC_KEY_BASE64> with the value generated in the previous step for the WorkflowGen license key, and replace <YOUR_NEW_GUID_BASE64> with the value generated in the previous step for the new GUID.

    Don't forget to apply this:

    Deploy the containers

    You're now ready to deploy the services. You'll create two Deployment objects and one ReplicaSet object. The deployment will create ReplicaSets for all the services with different configurations. Those deployments can later be configured to automatically scale with the pods' usage. The ReplicaSet will provide the necessary services to the database container in order to run properly and avoid data losses. Don't forget that there should only be one instance of each WorkflowGen Windows Service running at all time. This container pattern is called a Singleton.

    Database

    This configuration will deploy the StatefulSet database along with a headless service. This object will also create a persistent volume claim based on the template provided in the declaration.

    Apply the database first:

    WorkflowGen web applications

    Apply this replication controller:

    Windows Services deployment

    Apply the Windows Services:

    Add a load balancer

    Now, you need to add a public-facing load balancer in order to dispatch requests to your pods. To do this, execute the following command:

    You now need to wait for the IP to be provisioned. Execute the following command periodically until you get the load balancer's public IP:

    Once the value of EXTERNAL-IP is provisioned, copy it and modify the WorkflowGen configuration to change the WFGEN_APP_SETTING_ApplicationUrl value:

    Replace <EXTERNAL_IP> with the value of EXTERNAL-IP that you have.

    Apply it:

    Then, restart all of the pods in the WorkflowGen deployment to apply the changes to them. You have to do this for the Windows services as well. To do this, execute the following commands:

    You should now have a working WorkflowGen with a load balancer and a database.

    Kubernetes with AKS using Helm

    Helm is a package manager–like tool for Kubernetes. It manages the sharing, deployment, updates and rollbacks of software developed for Kubernetes. Based on values provided, Helm generates definition files for the cluster with the template engine from the Go programming language. For each release, WorkflowGen now produces a chart that you can use with your cluster. To have the latest bug fixes and features from the chart, make sure to always pick the chart released with the latest update of WorkflowGen.

    Architecture overview

    At the end of this section, you'll have this cluster configuration:

    Azure resources view
    Kubernetes objects view

    Every container in the cluster will have access to the configuration and secrets inside their namespaces. Several Azure services will be deployed by Azure Kubernetes Service. This doesn't require any manual steps other than interacting with Kubernetes itself. The load balancer that the service will create will dispatch the requests between the WorkflowGen server replicas.

    Prerequisites

    • You must have a working Kubernetes cluster with Windows Server 2019 nodes. See the Azure resources view above for a basic AKS setup. See Deploy a Windows Server container on an Azure Kubernetes Service (AKS) cluster using Azure CLI to get started with creating an AKS cluster with Windows node support.

    • You must have installed the kubectl command line tool and it must be connected to the cluster. See the Connect to the cluster section in the Deploy a Windows Server container on an Azure Kubernetes Service (AKS) cluster using Azure CLI Microsoft article for instructions on how to connect kubectl with AKS.

    • 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 Helm versions 3.0 and later are supported.

    As well, note that you should not create any other resources in Azure besides the cluster and its nodes. All required resources for the containers will be created by Kubernetes automatically. AKS is a fully-managed platform.

    Create the symmetric encryption key

    This value should be generated by you. A simple GUID will suffice since it has sufficient entropy not to be guessed:

    Add your WorkflowGen license file to the cluster

    Kubernetes enables you to manage secrets and configurations as files inside the cluster and inject them into pods. In this case, you'll add your license file as a secret and later inject it to the WorkflowGen pod. To add your license to the cluster, execute the following command:

    Create a file with your values for the chart

    In order to generate the templates tailored to your configuration expectations, you have to provide some values to the helm command when you install or update a release. You can specify those values using the command line interface or with a file. In the case of a new installation, it will be easier with a file. Here are the values that you will need:

    Replace <YOUR_WFG_LIC_KEY> with your WorkflowGen license key, and replace <YOUR_NEW_GUID> with the GUID that you generated.

    You can save this file as values.yaml. The name is not important.

    Install the WorkflowGen chart

    You now need to install the chart with those values. To do this, execute the following command:

    Helm will generate Kubernetes deployment files for you and install them on the cluster.

    Update the application URL

    This configuration will create a load balancer in front of the WorkflowGen containers. You will need to wait for it to get a public IP address. Execute the following command periodically until you get the load balancer's public IP:

    Once the value of EXTERNAL-IP is provisioned, copy it and modify the WorkflowGen configuration to change the WFGEN_APP_SETTING_ApplicationUrl value. To do this, you first need to get the name of the ConfigMap associated with the WorkflowGen deployment. The following command will give you all the ConfigMap objects in the default namespace:

    Copy the WorkflowGen ConfigMap name and replace <WFG_CONFIG_MAP> with the value in the following command:

    This will bring up an editor so you can replace the WFGEN_APP_SETTING_ApplicationUrl value with the correct IP address from the load balancer service. Save the file and exit the editor. To apply the changes made to the ConfigMap object, restart all of the pods in the WorkflowGen deployment. You have to do this for the Windows services as well. Get the name of the deployments with the following command:

    Replace <WEB_APPS_DEPLOYMENT_NAME> and <WIN_SERVICES_DEPLOYMENT_NAME> in the following script with the correct deployment names to restart all containers:

    You should now have a working WorkflowGen with a load balancer and a database.

    Configuration

    Overview

    This section explains how to completely configure a WorkflowGen upgrade container. Some options are configured as environment variables and others are passed directly to the entry point script. It is available as Linux and Windows images.

    This image is not designed to be taken as a base image.

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: wfgdata-pvc
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: azurefile
      resources:
        requests:
          storage: 50Gi
    kubectl apply -c .\wfgdata-pvc.yml
    kubectl create secret generic wfgen-license-secret --from-file C:\Path\To\WorkflowGen.lic
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: wfgen-config
    data:
      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
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: database-config
    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
    kubectl apply -f .\config.yml
    [guid]::NewGuid().ToString('N')
    # fda7a6a81db2428b8885bd1210522755
    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))
        }
    }
    
    # Database containers
    "strong(!)Pass" | ConvertTo-Base64String # c3Ryb25nKCEpUGFzcw==
    "WFGEN_USER" | ConvertTo-Base64String # V0ZHRU5fVVNFUg==
    
    # WorkflowGen containers
    "<YOUR_WFG_LIC_KEY>" | ConvertTo-Base64String # PFlPVVJfV0ZHX0xJQ19LRVk+
    "<YOU_NEW_GUID>" | ConvertTo-Base64String # PFlPVV9ORVdfR1VJRD4=
    "Server=database-0.database.default.svc.cluster.local,1433;Database=WFGEN;User ID=WFGEN_USER;Password=strong(!)Pass;" `
        | ConvertTo-Base64String # V0ZHRU5fREFUQUJBU0VfQ09OTkVDVElPTl9TVFJJTkc9RGF0YSBTb3VyY2U9ZGF0YWJhc2UsMTQzMztOZXR3b3JrIExpYnJhcnk9REJNU1NPQ047SW5pdGlhbCBDYXRhbG9nPVdGR0VOO1VzZXIgSUQ9V0ZHRU5fVVNFUjtQYXNzd29yZD1zdHJvbmcoISlQYXNzOw==
    "39B3AE9CCCF94AA47D795EC84F7CCB7928F5D59BE2EB2BBA4FE2AC0B3C8D0C85" | ConvertTo-Base64String # MzlCM0FFOUNDQ0Y5NEFBNDdENzk1RUM4NEY3Q0NCNzkyOEY1RDU5QkUyRUIyQkJBNEZFMkFDMEIzQzhEMEM4NQ==
    "82F6247A5DBF8666FB60B8EFE6483360436F0EC426CC0351A9569C607B46C1FAD6497406DD8B0B519DD83CAA6764904C89999D742638ECE756E7C0B8799B45E9" `
        | ConvertTo-Base64String # ODJGNjI0N0E1REJGODY2NkZCNjBCOEVGRTY0ODMzNjA0MzZGMEVDNDI2Q0MwMzUxQTk1NjlDNjA3QjQ2QzFGQUQ2NDk3NDA2REQ4QjBCNTE5REQ4M0NBQTY3NjQ5MDRDODk5OTlENzQyNjM4RUNFNzU2RTdDMEI4Nzk5QjQ1RTk=
    apiVersion: v1
    kind: Secret
    metadata:
      name: database-sec
    type: Opaque
    data:
      SA_PASSWORD: c3Ryb25nKCEpUGFzcw==
      WFGEN_DATABASE_USER_PASSWORD: c3Ryb25nKCEpUGFzcw==
      WFGEN_ADMIN_PASSWORD: c3Ryb25nKCEpUGFzcw==
      WFGEN_DATABASE_USER_USERNAME: V0ZHRU5fVVNFUg==
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: wfgen-sec
    type: Opaque
    data:
      ApplicationSerialNumber: <YOUR_WFG_LIC_KEY_BASE64>
      ApplicationSecurityPasswordSymmetricEncryptionKey: <YOUR_NEW_GUID_BASE64>
      WFGEN_DATABASE_CONNECTION_STRING: V0ZHRU5fREFUQUJBU0VfQ09OTkVDVElPTl9TVFJJTkc9RGF0YSBTb3VyY2U9ZGF0YWJhc2UsMTQzMztOZXR3b3JrIExpYnJhcnk9REJNU1NPQ047SW5pdGlhbCBDYXRhbG9nPVdGR0VOO1VzZXIgSUQ9V0ZHRU5fVVNFUjtQYXNzd29yZD1zdHJvbmcoISlQYXNzOw==
      WFGEN_MACHINE_KEY_DECRYPTION_KEY: MzlCM0FFOUNDQ0Y5NEFBNDdENzk1RUM4NEY3Q0NCNzkyOEY1RDU5QkUyRUIyQkJBNEZFMkFDMEIzQzhEMEM4NQ==
      WFGEN_MACHINE_KEY_VALIDATION_KEY: ODJGNjI0N0E1REJGODY2NkZCNjBCOEVGRTY0ODMzNjA0MzZGMEVDNDI2Q0MwMzUxQTk1NjlDNjA3QjQ2QzFGQUQ2NDk3NDA2REQ4QjBCNTE5REQ4M0NBQTY3NjQ5MDRDODk5OTlENzQyNjM4RUNFNzU2RTdDMEI4Nzk5QjQ1RTk=
    kubectl apply -f secrets.yml
    apiVersion: v1
    kind: Service
    metadata:
      name: database
    spec:
      type: ClusterIP
      clusterIP: None
      ports:
        - port: 1433
          targetPort: mssql
          protocol: TCP
          name: mssql
      selector:
        app.kubernetes.io/name: workflowgen
        app.kubernetes.io/component: database
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: database
    spec:
      replicas: 1
      serviceName: database
      selector:
        matchLabels:
          app.kubernetes.io/name: workflowgen
          app.kubernetes.io/component: database
      template:
        metadata:
          labels:
            app.kubernetes.io/name: workflowgen
            app.kubernetes.io/component: database
        spec:
          terminationGracePeriodSeconds: 10
          nodeSelector:
            kubernetes.io/os: linux
          containers:
            - name: database
              image: advantys/workflowgen-sql:7.18.3-ubuntu-18.04
              imagePullPolicy: Always
              securityContext:
                runAsUser: 0
                runAsGroup: 0
              resources:
                requests:
                  memory: "1Gi"
                  cpu: "500m"
                limits:
                  memory: "2Gi"
                  cpu: "1"
              envFrom:
                - configMapRef:
                    name: database-config
              ports:
                - name: mssql
                  containerPort: 1433
              livenessProbe:
                initialDelaySeconds: 30
                timeoutSeconds: 5
                exec:
                  command:
                    - pwsh
                    - -NoLogo
                    - -NoProfiles
                    - /usr/local/bin/healthcheck.ps1
              readinessProbe:
                initialDelaySeconds: 20
                timeoutSeconds: 5
                exec:
                  command:
                    - pwsh
                    - -NoLogo
                    - -NoProfiles
                    - /usr/local/bin/healthcheck.ps1
              volumeMounts:
                - mountPath: /var/opt/mssql
                  name: sqldata
                - mountPath: /mnt/secrets
                  readOnly: true
                  name: secrets
          volumes:
            - name: secrets
                secret:
                  secretName: database-sec
      volumeClaimTemplates:
        - metadata:
            name: sqldata
          spec:
            accessModes:
              - ReadWriteOnce
            storageClassName: default
            resources:
              requests:
                storage: 100Gi
    kubectl apply -f database.yml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wfgen-webapps
    spec:
      replicas: 3
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app.kubernetes.io/name: workflowgen
          app.kubernetes.io/component: webapps
      template:
        metadata:
          labels:
            app.kubernetes.io/name: workflowgen
            app.kubernetes.io/component: webapps
        spec:
          nodeSelector:
            kubernetes.io/os: windows
          containers:
            - name: wfgen
              image: advantys/workflowgen:7.18.3-win-ltsc2019
              imagePullPolicy: Always
              resources:
                requests:
                  memory: "2Gi"
                  cpu: "1"
                limits:
                  memory: "2Gi"
                  cpu: "1"
              ports:
                - name: http
                  containerPort: 80
                  protocol: TCP
              envFrom:
                - configMapRef:
                    name: wfgen-config
              env:
                - name: WFGEN_START_SERVICE
                  value: webapps
              livenessProbe:
                periodSeconds: 30
                timeoutSeconds: 5
                initialDelaySeconds: 60
                exec:
                  command:
                    - powershell
                    - C:\healthcheck.ps1
              livenessProbe:
                timeoutSeconds: 5
                initialDelaySeconds: 60
                exec:
                  command:
                    - powershell
                    - -Command
                    - if (Test-Path "C:\iislog\W3SVC\*log") { return 0 } else { return 1 }
              volumeMounts:
                - mountPath: C:\wfgen\data
                  name: wfgdata
                - mountPath: C:\wfgen\licenses
                  readOnly: true
                  name: licenses
                - mountPath: C:\secrets
                  readOnly: true
                  name: secrets
          volumes:
            - name: wfgdata
              persistentVolumeClaim:
                claimName: wfgdata-pvc
            - name: licenses
              secret:
                secretName: wfgen-license-secret
                items:
                  # The following must match the name of the license item in 
                  # the license secret, e.g. the name of the license file
                  - key: WorkflowGen.lic
                    path: WorkflowGen.lic
            - name: secrets
                secret:
                  secretName: wfgen-sec
    kubectl apply -f wfgen-webapps.yml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wfgen-winservices
    spec:
      replicas: 1 # Singleton pattern
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app.kubernetes.io/name: workflowgen
          app.kubernetes.io/component: winservices
      template:
        metadata:
          labels:
            app.kubernetes.io/name: workflowgen
            app.kubernetes.io/component: winservices
        spec:
          nodeSelector:
            kubernetes.io/os: windows
          containers:
            - name: wfgen-dir-sync
              image: advantys/workflowgen:7.18.3-win-ltsc2019
              resources:
                requests:
                  memory: "1Gi"
                  cpu: "500m"
                limits:
                  memory: "1Gi"
                  cpu: "750m"
              envFrom:
                - configMapRef:
                    name: wfgen-config
              env:
                - name: WFGEN_START_SERVICE
                  value: dir_sync
              livenessProbe:
                periodSeconds: 30
                timeoutSeconds: 5
                initialDelaySeconds: 60
                exec:
                  command:
                    - powershell
                    - C:\healthcheck.ps1
              volumeMounts:
                - mountPath: C:\wfgen\data
                  name: wfgdata
                - mountPath: C:\wfgen\licenses
                  readOnly: true
                  name: licenses
                - mountPath: C:\secrets
                  readOnly: true
                  name: secrets
            - name: wfgen-engine
              image: advantys/workflowgen:7.18.3-win-ltsc2019
              resources:
                requests:
                  memory: "1Gi"
                  cpu: "500m"
                limits:
                  memory: "1Gi"
                  cpu: "750m"
              envFrom:
                - configMapRef:
                    name: wfgen-config
              env:
                - name: WFGEN_START_SERVICE
                  value: engine
              livenessProbe:
                periodSeconds: 30
                timeoutSeconds: 5
                initialDelaySeconds: 60
                exec:
                  command:
                    - powershell
                    - C:\healthcheck.ps1
              volumeMounts:
                - mountPath: C:\wfgen\data
                  name: wfgdata
                - mountPath: C:\wfgen\licenses
                  readOnly: true
                  name: licenses
                - mountPath: C:\secrets
                  readOnly: true
                  name: secrets
          volumes:
            - name: wfgdata
              persistentVolumeClaim:
                claimName: wfgdata-pvc
            - name: licenses
              secret:
                secretName: fgen-license-secret
                items:
                  # The following must match the name of the license item in 
                  # the license secret, e.g. the name of the license file
                  - key: WorkflowGen.lic
                    path: WorkflowGen.lic
            - name: secrets
                secret:
                  secretName: wfgen-sec
    kubectl apply -f wfgen-win-services.yml
    kubectl expose deployment wfgen-webapps --type=LoadBalancer --name=wfgen-service
    kubectl get services wfgen-service
    # wfgen-config.yml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: wfgen-config
    data:
      WFGEN_APP_SETTING_ApplicationUrl: 'http://<EXTERNAL_IP>/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
    kubectl apply -f wfgen-config.yml
    kubctl scale deployment wfgen-webapps --replicas 0 -n wfgen-service
    kubctl scale deployment wfgen-winservices --replicas 0 -n wfgen-service
    
    # Wait until the scaling is done and then scale up
    kubctl scale deployment wfgen-webapps --replicas 3 -n wfgen-service
    kubctl scale deployment wfgen-winservices --replicas 1 -n wfgen-service
    [guid]::NewGuid().ToString('N')
    # fda7a6a81db2428b8885bd1210522755
    kubectl create secret generic wfgen-license-secret --from-file C:\Path\To\WorkflowGen.lic
    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
    
    helm install -f .\values.yaml wfg https://github.com/advantys/workflowgen-releases/releases/download/7.18.3/workflowgen-0.0.3.tgz
    kubectl get services wfgen-service
    kubectl get configmap
    kubectl edit configmap "<WFGEN_CONFIG_MAP>"
    kubectl get deployment
    kubctl scale deployment "<WEB_APPS_DEPLOYMENT_NAME>" --replicas 0 -n wfgen-service
    kubctl scale deployment "<WIN_SERVICES_DEPLOYMENT NAME>" --replicas 0 -n wfgen-service
    
    # Wait until the scaling is done and then scale up
    kubctl scale deployment "<WEB_APPS_DEPLOYMENT_NAME>" --replicas 3 -n wfgen-service
    kubctl scale deployment "<WIN_SERVICES_DEPLOYMENT NAME>" --replicas 1 -n wfgen-service
    Environment variables

    In the case of the upgrade image, the environment variables are arguments that you should not have to change often when upgrading WorkflowGen. That way, you can easily pass a file that defines those variables and reuse it between runs. Here's the list of available environment variables with their descriptions:

    Variables

    Description & values

    WFGEN_UPGRADE_UPDATE_PACKAGES_PATH

    A path local to the container where the update packages are located. See the page of this section for more information and examples.

    Default value:

    • Windows: C:\wfgen\updatepackages

    • Linux: /mnt/updatepackages

    WFGEN_UPGRADE_UPDATE_PACKAGE_FILE_NAME

    The name of the update package archive to pick in the update packages path for this upgrade. If no value is provided, <ToVersion>/update.zip will be picked where <ToVersion> is passed as an argument to the container.

    WFGEN_DATABASE_CONNECTION_STRING

    Required variable

    The connection string to the WorkflowGen database. The user passed must have the rights to modify the schema of the database.

    WFGEN_UPGRADE_EXCLUDE_FILES

    Globally excluded files when copying App_Data files from the update package to your App_Data volume, and when copying wfapps files from the update package to your wfapps volume. The elements in this list must be comma-separated (e.g.myfile.txt,myfile2.txt).

    ✏️ Notes:

    • There is no distinction between files and folders in the Linux version.

    WFGEN_UPGRADE_EXCLUDE_FOLDERS

    Globally excluded folders when copying App_Data files from the update package to your App_Data volume, and when copying wfapps files from the update package to your wfapps volume. The elements in this list must be comma-separated (e.g.myfolder,myfolder).

    ✏️ Notes:

    • There is no distinction between files and folders in the Linux version.

    Script parameters

    Script parameters define options to pass as arguments directly to the upgrade container. These arguments are more likely to be defined each time you run the container, which is why they are not in environment variables. Here's the help file of the entrypoint script. It describes all of the parameters and their groupings, and provides a few examples:

    Using an external configuration manager

    Some popular configuration managers support Docker containers out-of-the-box. You would use an external configuration manager only for environment variables definition. Here are a few links to their specific documentation to get you started:

    Chef

    • Docker Cookbook - Chef Supermarket

    • Chef and Kubernetes

    Ansible

    • Ansible and Docker

    • k8s – Manage Kubernetes (K8s) objects

    Puppet

    • Puppet in Docker: running Puppet on container-centric infrastructure

    • Installing Kubernetes with the (certified!) Puppet Kubernetes module

    NAME
        /usr/local/bin/docker-entrypoint.ps1
        
    SYNOPSIS
        Entrypoint script for the upgrade container.
        
        
    SYNTAX
        /usr/local/bin/docker-entrypoint.ps1 -FromVersion <String> -ToVersion <String> [-RemainingArgs <Object>] [-Offline] [<CommonParameters>]
        
        /usr/local/bin/docker-entrypoint.ps1 -Command -RemainingArgs <Object> [<CommonParameters>]
        
        /usr/local/bin/docker-entrypoint.ps1 -Help [<CommonParameters>]
        
        
    DESCRIPTION
        This script will merge files for the App_Data and wfapps directory between
        the upgrade package of the destination version and the current installation
        ones (passed as volumes).
        
        It will also launch the required SQL migration scripts in order from lowest
        to highest version. Make sure to use a SQL account that has the proper 
        rights to modify the database tables.
        
        The "Files", "LogFiles" and "Ws" subfolders in App_Data are always ignored.
        You don't have to specify them in the exclusion environment variables.
        
    
    PARAMETERS
        -FromVersion <String>
            The current version of WorkflowGen. The starting version of the 
            migration.
            
            Required?                    true
            Position?                    named
            Default value                
            Accept pipeline input?       false
            Accept wildcard characters?  false
            
        -ToVersion <String>
            The version to which you want to migrate the current one.
            
            Required?                    true
            Position?                    named
            Default value                
            Accept pipeline input?       false
            Accept wildcard characters?  false
            
        -Command [<SwitchParameter>]
            Indicates to execute a command inside the container. This is used in 
            conjunction with RemainingArgs
            
            Required?                    true
            Position?                    named
            Default value                False
            Accept pipeline input?       false
            Accept wildcard characters?  false
            
        -RemainingArgs <Object>
            Commands to execute inside the container. If versions are not passed, it is
            executed at the beginning and then it exits after the execution. If 
            versions are passed, it is executed at the end of the script.
            
            Required?                    false
            Position?                    named
            Default value                
            Accept pipeline input?       false
            Accept wildcard characters?  false
            
        -Help [<SwitchParameter>]
            Get full help for this script.
            
            Required?                    true
            Position?                    named
            Default value                False
            Accept pipeline input?       false
            Accept wildcard characters?  false
            
        -Offline [<SwitchParameter>]
            If provided, the script will not try to download the update package. 
            This means that you have to provide the update package from a volume.
            
            Required?                    false
            Position?                    named
            Default value                False
            Accept pipeline input?       false
            Accept wildcard characters?  false
            
        <CommonParameters>
            This cmdlet supports the common parameters: Verbose, Debug,
            ErrorAction, ErrorVariable, WarningAction, WarningVariable,
            OutBuffer, PipelineVariable, and OutVariable. 
            For more information, see about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 
        
    NOTES
        
        
        File name: docker-entrypoint.ps1
            
        requires -Version 7.0
        
        -------------------------- EXAMPLE 1 --------------------------
        
        PS > docker container run -i "..." advantys/workflowgen-upgrade:latest-ubuntu-18.04 -Help
        
        Displays the full help for the container.
        
        
        
        
        -------------------------- EXAMPLE 2 --------------------------
        
        PS > docker container run -i "..." advantys/workflowgen-upgrade:latest-ubuntu-18.04 -Command dir /mnt/appdata
        
        This executes an arbitrary command inside the container. It can be useful 
        for debugging network issues or other problems prior to the migration.
        
        
        
        
        -------------------------- EXAMPLE 3 --------------------------
        
        PS > docker container run -i "..." advantys/workflowgen-upgrade:latest-ubuntu-18.04 -FromVersion 7.14.10 -ToVersion 7.18.2
        
        This will launch the migration process to upgrade WorkflowGen from version 
        7.14.10 to the 7.18.2 version.
        
        
        
        
        -------------------------- EXAMPLE 4 --------------------------
        
        PS > docker container run -i "..." advantys/workflowgen-upgrade:latest-ubuntu-18.04 -FromVersion 7.14.10 -ToVersion 7.18.2 dir /mnt/appdata
        
        This will launch the migration process to upgrade WorkflowGen from version 
        7.14.10 to the 7.18.2 version. In addition, it will execute an arbitrary command 
        at the end of the migration process.
    
    

    Excluded files in Windows version are recursive.

  • You can't use sub-paths in the Windows version.

  • Excluded folders in the Windows version are recursive.

  • You can't use sub-paths in the Windows version.

  • WFGEN_UPGRADE_APPDATA_EXCLUDE_FILES

    Globally excluded files when copying App_Data files from the update package to your App_Data volume. The elements in this list must be comma-separated (e.g.myfile.txt,myfile2.txt).

    ✏️ Notes:

    • There is no distinction between files and folders in the Linux version.

    • Excluded files in the Windows version are recursive.

    • You can't use sub-paths in the Windows version.

    WFGEN_UPGRADE_WFAPPS_EXCLUDE_FILES

    Globally excluded files when copying wfapps files from the update package to your wfapps volume. The elements in this list must be comma-separated (e.g.myfile.txt,myfile2.txt).

    ✏️ Notes:

    • There is no distinction between files and folders in the Linux version.

    • Excluded files in the Windows version are recursive.

    • You can't use sub-paths in the Windows version.

    WFGEN_UPGRADE_APPDATA_EXCLUDE_FOLDERS

    Globally excluded folders when copying App_Data files from the update package to your App_Data volume. The elements in this list must be comma-separated (e.g. myfolder,myfolder).

    ✏️ Notes:

    • There is no distinction between files and folders in the Linux version.

    • Excluded folders in the Windows version are recursive.

    • You can't use sub-paths in the Windows version.

    WFGEN_UPGRADE_WFAPPS_EXCLUDE_FOLDERS

    Globally excluded folders when copying wfapps files from the update package to your wfapps volume. The elements in this list must be comma-separated (e.g. myfolder,myfolder).

    ✏️ Notes:

    • There is no distinction between files and folders in the Linux version.

    • Excluded folders in the Windows version are recursive.

    • You can't use sub-paths in the Windows version.

    Usage
    k8s – Manage Kubernetes (K8s) objects
    How to Install and Configure Kubernetes with the Puppet Kubernetes Module

    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 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 :

    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:

    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 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:

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

    WorkflowGen values

    The following are all of the value names supported by the WorkflowGen chart and their default values, accompanied by brief descriptions.

    The chart is divided in groups of configuration:

    • Global

    • WorkflowGen

    • WorkflowGen Windows services

    • Database

    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.

    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:

    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

    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.

    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:

    The content of the object is exactly the . 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.

    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.

    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

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

    Custom image reference

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

    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 in the Kubernetes documentation.

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

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

    Security

    There are many security features that aren't yet supported, or don't work in Windows but do work in Linux. It's important to plan the security of the deployments. To find out more about unsupported security features on Windows containers in Kubernetes, see the section in the 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. To get the mount options for Azure Files, see the section in the Microsoft documentation.

    Infrastructure-related recommendations

    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:

    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:

    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.

    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:

    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

    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:

    The content of the template is exactly the . 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 the Microsoft documentation.

    Custom image reference

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

    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 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:

    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 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.

    For more information about Docker security features, see in the Docker documentation. To find out how to configure these security features in Kubernetes, see in the Kubernetes documentation.

    Infrastructure-related recommendations

    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:

    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 . It is optional to generate the Ingress rule object. To disable it, you can add the following values:

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

    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 or . 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 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:

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

    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 for more information about configuring the WorkflowGen upgrade container.

    Common scenarios

    Deploying a simple WorkflowGen pod

    Overview

    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-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).

    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:

    With that done, you can now install the release:

    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

    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-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).

    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:

    With this done, you can now install the release:

    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

    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

    • 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).

    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:

    With this done, you can now install the release:

    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.

    Ingress

  • Hooks

  • 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
    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.

    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

    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

    Bash

    Step 2: Create the objects from the files

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

    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:

    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

    Step 2: Deploy the definition into the cluster

    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:

    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
    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.

    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

    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

    Bash

    Step 2: Create the objects from the files

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

    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:

    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 the Create and use a volume with Azure Files in Azure Kubernetes Service (AKS) Microsoft article for more information.

  • 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 the Create and use a volume with Azure Files in Azure Kubernetes Service (AKS) Microsoft article for more information.

  • 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 the Create and use a volume with Azure Files in Azure Kubernetes Service (AKS) Microsoft article for more information.

  • Installing Helm
    Helm website
    Helm Install
    Kubernetes PersistentVolumeClaim specification
    Secrets
    Ingress Controllers
    Security
    Windows in Kubernetes
    Mount options
    Create and use a volume with Azure Files in Azure Kubernetes Service (AKS)
    Kubernetes PersistentVolumeClaim spec
    Create and use a volume with Azure Disks in Azure Kubernetes Service (AKS)
    Service
    Configure SQL Server container images on Docker
    Docker security
    Configure a Security Context for a Pod or Container
    Ingress object specification
    open source community project page
    the commercial page
    TLS/SSL
    Configuration
    Simple WorkflowGen pod deployment
    Scalable WorkflowGen pod deployment
    Scalable architecture with a database container
    Configuration
    Configuration
    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
    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
    echo 'Server=some.sql.server.com,1433;...' | base64 # U2VydmVyPXNvbWUuc3FsLnNlcnZlci5jb20sMTQzMzsuLi4K
    echo 'MY-WFG-LIC-NUMBER' | base64 # TVktV0ZHLUxJQy1OVU1CRVIK
    echo '1f73c842692f436b92411641c46fb338' | base64 # MWY3M2M4NDI2OTJmNDM2YjkyNDExNjQxYzQ2ZmIzMzgK
    my-wfg-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-wfg-pvc
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: azurefile
      resources:
        requests:
          storage: 50Gi
    kubectl apply -f ./my-wfg-pvc.yaml
    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=
    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=
    echo 'strong(!)Pass' | base64 # c3Ryb25nKCEpUGFzcwo=
    echo 'WFGEN_USER' | base64 # V0ZHRU5fVVNFUgo=
    helm install --set image.tag=7.15.5-win-ltsc2019 release-name ./chart-path
    image:
      tag: 7.15.5-win-ltsc2019
    {
        "image": {
            "tag": "7.15.5-win-ltsc2019"
        }
    }
    # YAML
    helm install --set-file ./my-values.yaml release-name ./chart-path
    
    # JSON
    helm install --set-file ./my-values.json release-name ./chart-path
    # 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: []
    
    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
    workflowgen:
      dataPvcSpec:
        accessModes:
          - ReadWriteMany
        storageClassName: azurefile
        resources:
          requests:
            storage: 50Gi
    kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic
    workflowgen:
      license:
        secretName: wfgen-license-secret
        items:
          - key: WFG.lic
            path: WFG.lic
    workflowgen:
      image:
        reference: mycorporation/workflowgen
        tag: 7.18.3-win-ltsc2019
    workflowgen:
      service:
        kind: LoadBalancer
    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
    database:
      create: false
    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
    database:
      volumeClaimTemplateSpec:
        accessModes:
          - ReadWriteOnce
        storageClassName: default
        resources:
          requests:
            storage: 100Gi
    database:
      image:
        reference: mycorporation/workflowgen-sql
        tag: 7.18.3-ubuntu-18.04
    database:
      fullnameOverride: my-database
    database:
      resources:
        limits:
          cpu: '2'
          memory: 4Gi
        requests:
          cpu: '1'
          memory: 2Gi
    ingress:
      enabled: false
    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
    hooks:
      preupgrade:
        enabled: false
    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"
    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
    
    kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic
    helm install -f ./my-values.yaml wfgen https://github.com/advantys/workflowgen-releases/releases/download/7.18.2/workflowgen-0.0.3.tgz
    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
    kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic
    helm install -f ./my-values.yaml wfgen https://github.com/advantys/workflowgen-releases/releases/download/7.18.2/workflowgen-0.0.3.tgz
    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
    
    kubectl create secret generic wfgen-license-secret --from-file ./WFG.lic
    helm install -f ./my-values.yaml wfgen https://github.com/advantys/workflowgen-releases/releases/download/7.18.2/workflowgen-0.0.3.tgz
    kubectl apply -f ./my-configmap.yaml
    kubectl apply -f ./my-secret.yaml
    my-values.yaml
    workflowgen:
      createConfigMap: false
      configMapNameOverride: my-configmap
      createSecret: false
      secretNameOverride: my-secret
    workflowgen:
      createDataPvc: false
      dataPvcNameOverride: my-wfg-pvc
    kubectl apply -f ./my-db-configmap.yaml
    kubectl apply -f ./my-db-secret.yaml
    my-values.yaml
    database:
      createConfigMap: false
      configMapNameOverride: my-db-configmap
      createSecret: false
      secretNameOverride: my-db-secret