StackSaga in Kubernetes

Overview

If your system is deployed in Kubernetes, the following changes should be made to the adaptation.

Orchestrator Service Changes

Based on the running environment, it can be chosen one of environment support dependencies. Due to we are now in eureka environment, the stacksaga-connect-k8s-support dependency should be added to the pom.xml of the orchestrator service.

<dependency>
    <groupId>org.stacksaga</groupId>
    <artifactId>stacksaga-connect-k8s-support</artifactId>
    <version>${stacksaga-version}</version>
</dependency>

After adding the dependency, you have to provide a service account with roles to access the kubernetes API. because stacksaga-connect-k8s-support dependency access the kubernetes endpoint internally to get some meta-data like the service name, pod ID, etc.

ServiceAccount Manifest

Create the service account for the orchestrator service.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: demo-order-service-service-account #the name of the service account.
  namespace: default #the namespace the application is deployed.

Role Manifest

Create a role for granting access to the pods and nodes.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: demo-order-service-role
  namespace: default
rules:
  - apiGroups: [ "" ]
    resources: [ "pods","nodes" ]
    verbs: [ "get" ]

RoleBinding Manifest

Bind the role with the service account.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: demo-order-service-service-account-role
  namespace: default
subjects:
  - kind: ServiceAccount
    name: demo-order-service-service-account
    namespace: default
roleRef:
  kind: RoleBinding
  name: demo-order-service-role
  apiGroup: rbac.authorization.k8s.io

Deployment Manifest

After binding the role with the service-account, configure the service-account with the deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-application
spec:
  selector:
    matchLabels:
      app: sample-application
  template:
    metadata:
      labels:
        app: sample-application
    spec:
      serviceAccountName: demo-order-service-service-account #mention the service account name here
      automountServiceAccountToken: true
      containers:
        - name: order-service
          image: mafeidev/sample-service:1.0.0
      #.... rest of properties

See the application configuration properties regarding the stacksaga-connect-k8s-support here.

SagaInstanceInfo feature with the help of kubernetes API

After adding stack-saga-k8s-discovery you can use it to access the pod metadata and as well as the node metadata that kubernetes provides.
import io.kubernetes.client.openapi.models.V1Node;
import io.kubernetes.client.openapi.models.V1Pod;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.stacksaga.common.communication.SagaInstanceInfo;
import org.stacksaga.common.communication.ServiceInstanceInfo;
import org.stacksaga.kubernetes.KubernetesSagaInstanceInfo;

@Component
@RequiredArgsConstructor
public class InstanceDetailService {

    private final ServiceInstanceInfo serviceInstanceInfo; (1)

    public void showInstanceInfo() {
        final SagaInstanceInfo sagaInstanceInfo = serviceInstanceInfo.getSagaInstanceInfo();
        if (sagaInstanceInfo instanceof KubernetesSagaInstanceInfo) { (2)
            final KubernetesSagaInstanceInfo kubernetesSagaInstanceInfo = (KubernetesSagaInstanceInfo) sagaInstanceInfo; (3)
            V1Pod v1Pod = kubernetesSagaInstanceInfo.getV1Pod(); (4)
            System.out.println("v1Pod = " + v1Pod);
            V1Node v1Node = kubernetesSagaInstanceInfo.getV1Node(); (5)
            System.out.println("v1Node = " + v1Node);
        }
    }
}
1 Autowire the ServiceInstanceInfo bean.
2 Call the getSagaInstanceInfo() method to get the assistance details and check that object is an instance of KubernetesSagaInstanceInfo. due to the adding the stack-saga-k8s-discovery dependency you will have a KubernetesSagaInstanceInfo.
3 cast the object in to KubernetesSagaInstanceInfo object.
4 Access the V1Pod object.
5 Access the V1Node object.

Agent service

If you have already created the agent-service with eureka profile, just change the profile to k8s in the application.yml file and remove other configuration properties related to eureka. see the changes here

If you are creating the agent-service from the beginning, first, create the agent-service with one of the stacksaga-agent implementations and then chose the profile as k8s.

After that, grant accessing the API for the agent application with a service account and the role.

If you prefer to configure the same service-account with the role, you can use the same service-account that has been created for the orchestrator service. Or otherwise, you can create a separate one with the same access control.

After binding the role with the service-account, configure the service-account with the deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-order-service-agent
spec:
  selector:
    matchLabels:
      app: demo-order-service-agent
  template:
    metadata:
      labels:
        app: demo-order-service-agent
    spec:
      serviceAccountName: demo-order-service-service-account #mention the service account name here
      automountServiceAccountToken: true
      containers:
        - name: order-service
          image: mafeidev/sample-service:1.0.0
      #.... rest of properties

Migration from Eureka profile to Kubernetes profile

server:
  port: 5566
spring:
  profiles:
    active: k8s (1)
  application:
    name: order-service-agent-eureka
  datasource:
    username: root
    password: mafei
    url: jdbc:mysql://mysql_host:3306/order-service-db
    driver-class-name: com.mysql.cj.jdbc.Driver
stacksaga:
  agent:
    retry-batch-size: 10000
    target-service: order-service
    target-service-host: order-service
    act-master-as-slave: true
    retry-pool:
      pool-size: 10
(2)

#    eureka:
#      instance-type: master
#      token-range-update-delay: 10000
#      token-range-update-initial-delay: 10000
#      token-range-valid-duration: 150000
#eureka:
#  client:
#    service-url:
#      defaultZone: http://localhost:8077/eureka/
#  instance:
#    metadata-map:
#      stacksagaRegion: myRegion
#      stacksagaZone: myZone

1 Changed the profile to k8s.
2 Removed all the eureka related properties.