How to deploy Workato OPA as a microservice on Kubernetes

Table of Contents

In this article, you will learn how to build the Workato On-prem Agent (OPA) into a Docker container and deploy it as a microservice into a Kubernetes cluster.

We’ll cover steps for Amazon EKS and Microsoft AKS, but most are applicable to deploying to any Kubernetes environment including Google Cloud GKE or IBM OpenShift.

This article assumes you already have both a working Kubernetes cluster or Docker image registry available and you can successfully push and deploy a hello world app to/from your registry to your Kubernetes cluster.

Process of deploying Workato OPA as a microservice on Kubernetes

The overall process includes three major steps:

  1. Build the Docker image
  2. Push the Docker image to a registry
  3. Deploy the Docker image from the registry to Kubernetes

We will use a payroll management system, as an example, that lacks suitable APIs and is running behind a firewall without access to the Internet. We will deploy OPA to access this app’s database directly. The same approach could be used to inject Workato into a protected microservices architecture that doesn’t expose its services to the Internet.

It is a good idea to test our OPA Docker image and the recipes that use it in a sandbox before deploying them to a production environment. For example, your cluster may have two namespaces: staging and prod. The commands used to deploy your image to these namespaces will be similar. However, to keep this article more concise, we will only deploy to one namespace.

Consider fault tolerance when deploying microservice based Workato OPA on Kubernetes

It’s also a good idea to consider fault tolerance when deploying OPA. Fault tolerance can be accomplished in different ways.

Workato fault tolerance

The traditional Workato approach to fault tolerance is to use an On-prem Group with two or more agents. Workato will load balance between available agents in the group, so if one becomes unavailable then load will be balanced to the others.

Kubernetes fault tolerance

However, Kubernetes has its own approach to fault tolerance. Kubernetes can monitor pod health, and can restart pods if necessary.

In some cases, Kubernetes fault tolerance may be enough, and this article will demonstrate deploying a single agent to a Kubernetes cluster (though we will show an on-prem group with multiple agents to demonstrate migrating an agent from a virtual server to a Kubernetes cluster).

There may be other reasons for deploying multiple agents to an on-prem group, multiple agents to a Kubernetes cluster, across clusters or across other environments, but this article won’t consider those.

When deploying multiple agents, keep in mind that every agent instance should have a unique key pair to identify itself when connecting to Workato. When two OPA agents use the same key pair, only one will be able to connect at a time.

Before we start

To follow along while reading this article, you will need to get access to Amazon EKS or Microsoft AKS cluster; or you can try using a different Kubernetes distribution like Google GKE, IBM OpenShift or even Docker Kubernetes running on your laptop. 

As mentioned above, this article does not cover setting up a working Kubernetes cluster or Docker image registry. It assumes you already have both available and you can successfully push and deploy a hello world app to/from your registry to your Kubernetes cluster.

At the end, we will use this Employees sample MySQL database to test our agents. It contains information about departments, employees and their salaries.

Before starting, you will need to install: 

  • awscli(if using AWS EKS), 
  • az (if using Azure AKS) 
  • docker and kubectl tools 

You’ll also need to be able to login to AWS, Azure and Docker from the command line.

Step-by-step: How to deploy Workato OPA as a microservice on Kubernetes

Step 1. Build the Docker image

Our docker image should contain at least three major components: 

  • the OPA agent
  • its configuration file 
  • its key pair — this is used by Workato to identify a particular agent instance through a secure mutual TLS websocket connection.

In addition to these mandatory components the docker image may contain some additional artifacts. If you are using connectors which depend on 3rd party libraries, you will have to include those libraries into the image too.

OPA agent configuration file

The most important part of the agent is its config file. For testing our agents we will use the following config.yml:

employees_db:
    adapter: mysql
    host: ${MYSQL_HOST}
    port: ${MYSQL_PORT}
    database: ${MYSQL_DATABASE}
    username: ${MYSQL_USER}
    password: ${MYSQL_PASSWORD}

You may notice that this file contains references to environment variables MYSQL_* which will be defined below. The contents of an OPA config file depends on the applications or services you are going to connect to via that agent.

A group of OPA agents deployed for fault tolerance should have identical config files to ensure correct behavior when Workato traffic is load balanced across the group. For the full list of supported connections visit Workato On-Prem Agent Connection Profiles Documentation.

Creating an OPA group and an OPA agent

Next, we will get the archived OPA binaries. We’ll do this by creating an OPA group and an OPA agent. Be sure to select Linux OS when adding the agent.

You will have to accept an End User License Agreement every time you add a new agent. This is one reason why Workato does not currently distribute OPA as a prepackaged Docker image.

Unique OPA agent key pair

When done, you should have:

  • a unique key pair per agent (cert.zip)
  • a distributable package (workato-agent-linux-x64-X.Y.Z.tar.gz). 

Copy the config.yml file from earlier and the distributable package to a working directory to create the Dockerfile.

Your working directory contains the following files (the key pair in the cert.zip file will be added as kubernetes secrets in step 3):

  • config.yml — configuration file
  • workato-agent-linux-x64-2.9.10.tar.gz — distributable package

And your on-prem group should look similar to this (though without the Amazon EC2 agent):

On-prem group

On-prem group

In the screenshot above, we have two agents:

Amazon EC2 agent

The Amazon EC2 agent is an older agent which is running in a virtual machine. In your case, this should not show in your on-prem group.

Kubernetes agent

We’re going to replace the Amazon EC2 agent with a new more modern one running in a Kubernetes cluster. When the new agent has been deployed, we can remove the old agent. The same procedure may be used to migrate from one public cloud to another.

Create your Dockerfile

Now create a new file called Dockerfile in the working directory, and add these contents:

In our case, we do not need any 3rd party libraries, but if you do, you will need to uncomment and modify the appropriate lines in this file.

You may notice that this Dockerfile points to certificate and private key files that are not copied from the working directory by the Dockerfile. Again, we will introduce them as Kubernetes secrets in step 3.

For now, it’s enough to know that the config.yml expects certain environment variables and the Dockerfile points to a specific key pair identifying our OPA agent in the On-prem Group. Let’s build the image!

Building the docker image

% docker image build -t workato-agent:2.10-r1

This command should be run inside your working directory. Don’t forget the dot at the end which references the current directory. Also, the fully qualified name of the image will differ based on the name of your registry that may already exist or that you might create below.

If the image builds successfully, you should see it in the list of available images:

% docker images
REPOSITORY                TAG      IMAGE ID      CREATED         SIZE     
workato-agent             2.10-r1  3f845d078cd8  13 minutes ago  524MB

Congratulations! Now you have an OPA Docker image

Step 2. Push the Docker image to a registry

The tools and commands we will use to push our image to a registry and deploy it to Kubernetes may be different for different cloud providers. In the following sections, we show the appropriate tools and commands for AWS ECR/EKS and Azure ACR/AKS.

Pushing to Amazon Elastic Container Registry (ECR)

Workato OPA as microservice with amazon Kubernetes

First, make sure you have installed the AWS CLI and have logged into your account from the command line. For example:

% aws ecr get-login-password --region us-west-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-west-1.amazonaws.com

Next, we can create the registry for our agent (in case you have not done so yet). For example:

% aws ecr create-repository --repository-name workato-agent --image-scanning-configuration scanOnPush=true
REPOSITORY 1644982532.0 MUTABLE 123456789012 arn:aws:ecr:us-west-1:123456789012:repository/workato-agent workato-agent 123456789012.dkr.ecr.us-west-1.amazonaws.com/workato-agent
ENCRYPTIONCONFIGURATION AES256
IMAGESCANNINGCONFIGURATION True 

You can refer to the detailed instructions provided in the AWS Console for how to push an image to your ECR registry (available under the “View push command” button in the list of repositories in ECR). For example, we will push our image to the ECR registry:

% docker tag workato-agent:2.10-r1 123456789012.dkr.ecr.us-west-1.amazonaws.com/workato-agent:2.10-r1
% docker push 123456789012.dkr.ecr.us-west-1.amazonaws.com/workato-agent:2.10-r1

Every time Kubernetes starts a Workato OPA container instance, it will pull this image from the registry and run it in the cluster.

Pushing to Azure Container Registry

In order to push anything to Microsoft Azure cloud we need to get Azure CLI and login:

% az login
% az acr login --name myregistry
% docker login myregistry.azurecr.io

In Microsoft Azure, the repository can be created automatically upon deployment:

% docker tag workato-agent:2.10-r1 workato.azurecr.io/workato-agent:2.10-r1
% docker push myregistry.azurecr.io/workato-agent:2.9.10-r1

Step 3. Deploy the Docker image from the registry to Kubernetes

Now our OPA Docker image is ready to be pulled from the registry and deployed to our Kubernetes cluster.

Deploy docker image to Amazon EKS

First, let’s just check that we are connected to the right cluster:

% aws eks update-kubeconfig --region us-west-1 --name north-california     
Added new context arn:aws:eks:us-west-1:123456789012:cluster/north-california to ~/.kube/config
% kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.100.0.1           443/TCP   3h43m
% kubectl config current-context
arn:aws:eks:us-west-1:123456789012:cluster/north-california

Next, we recommend creating a separate namespace to keep production and staging namespaces isolated:

% kubectl create namespace prod
namespace/prod created

Earlier in this article we downloaded key pair and now it’s time to put it in place by creating a Kubernetes secret  like this:

% kubectl create secret tls workato-agent-keypair --cert=north-california/cert.pem --key=north-california/cert.key --namespace=prod
secret/workato-agent-keypair created

You may remember that our config.yml referenced environment variables for connection properties. We should pass these now into our OPA container using a ConfigMap in Kubernetes. Create a file `mysql-prod.env` like this:

MYSQL_HOST=mysql-98ccbdf8-zztwh
MYSQL_PORT=3306
MYSQL_DATABASE=employees

Then import that data into Kubernetes:

% kubectl create configmap employee-db --from-env-file mysql-prod.env --namespace=prod
configmap/employee-db created

The access credentials for the database should be saved in a different way to prevent exposure in the Kubernetes environment:

% kubectl create secret generic employee-db \
  --from-literal=MYSQL_USER=admin \
  --from-literal=MYSQL_PASSWORD='S!B\*d$zDsb=' \
  --namespace=prod
secret/employee-db created

That’s it. Our cluster now has a prod namespace ready to run Workato on-prem agent image. To make it happen we just need to tell Kubernetes that this image will use the secrets and ConfigMap we’ve just created.

For this purpose, the cluster expects us to provide a deployment descriptor. You can download it here:

This descriptor does not contain exact information about any particular database, so we can use the same descriptor to run the Docker image in any namespace. However, you will have to update the descriptor with the fully qualified name of the image in your registry:

    spec:
      containers:
      - name: workato-agent
        image: <fully qualified name of your image in your registry>
        volumeMounts:

And we need is to specify the namespace in the command line:

% kubectl apply -f workato-agent.yaml --namespace=prod
deployment.apps/workato-agent created

Now you can verify that Kubernetes pod was started:

% kubectl get pods --namespace=prod
NAME                             READY   STATUS    RESTARTS   AGE
workato-agent-7c6dfcf89b-5ll7c   1/1     Running   0          113m

Here you can see that the Kubernetes pod is running one of one containers (or replicas). That’s because the deployment descriptor specifies one replica. However, that can be overridden manually, or otherwise, to scale the number of running containers in Kubernetes. That should be avoided, because scaling the containers will lead to duplicate key conflicts between OPA agents.

You can look at the OPA agents log in Kubernetes like so:

% kubectl logs workato-agent-7c6dfcf89b-5ll7c
2022-02-17 03:06:30.070Z [main] INFO     com.workato.agent.Config - [JRE] Oracle Corporation version 11.0.12
2022-02-17 03:06:30.074Z [main] INFO     com.workato.agent.Config - [OS] Linux amd64 5.4.176-91.338.amzn2.x86_64
2022-02-17 03:06:31.562Z [main] INFO     c.w.agent.Application - Agent version: 2.10 CN: 3ab29a47f0d287a9ef6f90b703dbf4c1:12055
2022-02-17 03:06:32.317Z [main] INFO     c.w.a.sap.WebhookNotifier - HTTP nofification connectTimeout=10000, connectionRequestTimeout=10000, socketTimeout=10000
2022-02-17 03:06:32.721Z [main] INFO     o.h.v.i.util.Version - HV000001: Hibernate Validator 6.0.7.Final
2022-02-17 03:06:32.987Z [main] INFO     c.w.agent.http.SapService - Service starting...
2022-02-17 03:06:33.531Z [main] INFO     o.a.c.h.Http11Nio2Protocol - Initializing ProtocolHandler ["https-jsse-nio2-127.0.0.1-3000"]
2022-02-17 03:06:33.820Z [main] INFO     o.a.c.h.Http11Nio2Protocol - Starting ProtocolHandler ["https-jsse-nio2-127.0.0.1-3000"]
2022-02-17 03:06:33.822Z [main] INFO     c.w.agent.http.Server - Connector started on /127.0.0.1:3000
2022-02-17 03:06:34.807Z [main] INFO     c.workato.agent.net.Agent - Gateway ping successful: sg1.workato.com:443 version dev
2022-02-17 03:06:35.435Z [main] INFO     c.workato.agent.net.Agent - Gateway ping successful: sg2.workato.com:443 version dev
2022-02-17 03:06:35.753Z [agent-control-thread] INFO     c.workato.agent.net.Agent - Connected to gateway sg1.workato.com.
2022-02-17 03:06:35.838Z [agent-control-thread] INFO     c.workato.agent.net.Agent - Connected to gateway sg2.workato.com.

OPA outputs its logs to stdout and stderr as recommended by the Twelve-Factor App manifesto which provides the gold standard for architecting modern applications.

This also makes it easy to ship the OPA container logs  to a centralized log aggregation system that is automatically monitored. Amazon CloudWatch or Azure Monitor can help with this, and other vendors have similar tools.

Deploy docker image to Azure Kubernetes Services

Deploying to Azure AKS is similar. However, initializing kubectl is different. You can find particular instructions for your cluster at:

Azure Portal > Kubernetes services<your cluster> > Overview > Connect

They should look like that:

% az account set --subscription 00000000-0000-0000-0000-000000000000
% az aks get-credentials --resource-group PROD --name virginia

After command line tools are initialized, we can switch between clusters

% kubectl config use-context virginia

And after that, the procedure is completely similar to what we did above at AWS.

Step 4: End-to-end testing

Now, when setup is done, let’s test if it works. It’s likely that you completed adding your agents without testing them earlier in this document. You will have to step through the setup up wizard again by clicking the “setup now” link for the agent in its OPA group in Workato.

You should be able to click the Next button on until you are on the last step of the wizard, Step 7 Test, where you will click the Test agent button.

Testing the OPA agent

Testing the OPA agent

If the OPA log that we looked at above says the agent connected to the gateway, your test results should look like this:

Testing OPA agent successful

Testing OPA agent — successful

And the list of OPAs in on-prem group should look something like this:

Verify that the OPA agent has access to the data in your Kubernetes cluster

OK, but does it have access to the Employees sample MySQL database in the cluster? We need to create a recipe to verify that.

The recipe is super-simple and contains a timer trigger and MySQL / Select rows action.

When configuring the MySQL connection in the recipe, you’ll want to select the name of your on-prem group in the “Is this app in a private network?” connection property. This tells that connection to connect through OPA agents in the group.

Select name of on-prem group

Select name of on-prem group in the “Is this app in a private network?” connection property.

While editing the MySQL action, the connector should be able to populate the list of database tables for you. This already tells you that the connector was able to successfully connect to your database through OPA to discover those tables. In case anything goes wrong,  you should check agent’s log as it is described above for additional information about errors.

Populated database

Populated database

Was this post useful?

Get the best of Workato straight to your inbox.

Table of Contents
array(5) { [0]=> object(WP_Term)#3026 (11) { ["term_id"]=> int(80) ["name"]=> string(3) "opa" ["slug"]=> string(3) "opa" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(80) ["taxonomy"]=> string(8) "post_tag" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(3) ["filter"]=> string(3) "raw" ["term_order"]=> string(1) "0" } [1]=> object(WP_Term)#3025 (11) { ["term_id"]=> int(284) ["name"]=> string(13) "on-prem agent" ["slug"]=> string(13) "on-prem-agent" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(284) ["taxonomy"]=> string(8) "post_tag" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(3) ["filter"]=> string(3) "raw" ["term_order"]=> string(1) "0" } [2]=> object(WP_Term)#3024 (11) { ["term_id"]=> int(394) ["name"]=> string(13) "Microservices" ["slug"]=> string(13) "microservices" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(394) ["taxonomy"]=> string(8) "post_tag" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(2) ["filter"]=> string(3) "raw" ["term_order"]=> string(1) "0" } [3]=> object(WP_Term)#2950 (11) { ["term_id"]=> int(432) ["name"]=> string(10) "Kubernetes" ["slug"]=> string(10) "kubernetes" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(432) ["taxonomy"]=> string(8) "post_tag" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(1) ["filter"]=> string(3) "raw" ["term_order"]=> string(1) "0" } [4]=> object(WP_Term)#3028 (11) { ["term_id"]=> int(433) ["name"]=> string(16) "Docker container" ["slug"]=> string(16) "docker-container" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(433) ["taxonomy"]=> string(8) "post_tag" ["description"]=> string(0) "" ["parent"]=> int(0) ["count"]=> int(1) ["filter"]=> string(3) "raw" ["term_order"]=> string(1) "0" } }