Giter VIP home page Giter VIP logo

service-mesh-use-cases's Introduction

Use Cases for Service Mesh

The goal of these use cases is to test and compare different service mesh implementations.

Prerequisites

To run the different demos, you need to have a running Kubernetes cluster with an access to it via the kubectl CLI, as well as Open Service Mesh running (OSM) on top of it. You can follow these two documents to get a proper environment:

UC-02 | Routing of an API endpoint request to the right service

UC-02.01 | Initial situation

Let's have Alpha API an API with two API endpoints:

  • get /path-01
  • get /path-02

Let's have client-x a service calling these two API endpoints.

Let's have service-a a service implementing the two API endpoints of Alpha API. More precisely, let's have the version 1.0.0 of service-a implementing these two API endpoints.

alt text

WARNING. The client-x MUST NOT know the implementation details of the Alhpa API, and that includes the service which implements it. So, we could add an additional network name like aplha-api that would represent the API. However, as the API endpoints such as get /path-01 and get /path-02 are distinct, we can have only one unique network name such as acme-api. If, and only if, we would have a collision about two or more different API endpoints having the same name, then, and only then, we can still use a different network name such as <differentiator>.acme-api.

alt text

Demo Configuration

The Kubernetes manifests of the above situation can be written as follow:

# uc-02.01.yaml
---
# Deploy 'demo' Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: demo
---
# Deploy 'service-a' Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: service-a
  namespace: demo
---
# Deploy 'service-a-version-1-0-0-deployment' Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-a-version-1-0-0-deployment
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: service-a
      version: 1.0.0
      api: acme-api
  template:
    metadata:
      labels:
        app: service-a
        version: 1.0.0
        api: acme-api
    spec:
      serviceAccountName: service-a
      containers:
      - name: service-a
        image: patrice1972/service-a:1.0.0
        ports:
        - name: service-a-port
          protocol: TCP
          containerPort: 3000
---
# Deploy 'service-a-version-1-0-0' Service
apiVersion: v1
kind: Service
metadata:
  name: service-a-version-1-0-0
  namespace: demo
spec:
  selector:
    app: service-a
    version: 1.0.0
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000
---
# Deploy 'acme-api' Service
apiVersion: v1
kind: Service
metadata:
  name: acme-api
  namespace: demo
spec:
  selector:
    api: acme-api
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000
---
# Deploy 'client-x' Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: client-x
  namespace: demo
---
# Deploy 'client-x-version-1-0-1-deployment' Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-x-version-1-0-1-deployment
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: client-x
      version: 1.0.1
  template:
    metadata:
      labels:
        app: client-x
        version: 1.0.1
    spec:
      serviceAccountName: client-x
      containers:
      - name: client-x
        image: patrice1972/client-x:1.0.1
        env:
        - name: API_HOST
          value: "acme-api.demo"
---
# Deploy 'client-x-version-1-0-1' (dummy) Service [Required by OSM]
apiVersion: v1
kind: Service
metadata:
  name: client-x-version-1-0-1
  namespace: demo
spec:
  selector:
    app: client-x
    version: 1.0.1
  ports:
  - protocol: TCP
    port: 9999
    name: dummy-unused-port

You can deploy them using the following command:

$ kubectl apply -f https://raw.githubusercontent.com/patricekrakow/service-mesh-use-cases/master/uc-02.01.yaml

or

$ kubectl apply -f uc-02.01.yaml
Output of the command
namespace/demo created
serviceaccount/service-a created
deployment.apps/service-a-version-1-0-0-deployment created
service/service-a-version-1-0-0 created
service/acme-api created
serviceaccount/client-x created
deployment.apps/client-x-version-1-0-1-deployment created
service/client-x-version-1-0-1 created

Then, you can verify that the installation of the demo using the following command:

$ kubectl get pods -n demo
Output of the command
NAME                                                  READY   STATUS    RESTARTS   AGE
client-x-version-1-0-1-deployment-7db9cf495b-5cmc6    1/1     Running   0          49s
service-a-version-1-0-0-deployment-5d4fbcc598-22pj6   1/1     Running   0          49s

Finally, you can verify that the demo is working properly using the following command:

$ kubectl logs client-x-version-1-0-1-deployment-7db9cf495b-5cmc6 -n demo | tail
Output of the command
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-22pj6

You can see that the client-x while addressing the network name acme-api is getting replies from the version 1.0.0. of the service-a.

Let's now add the service mesh.

Add the OSM CLI to your path using the following command:

$ export PATH="$HOME/environment/go/src/github.com/openservicemesh/osm/bin:$PATH"
$ osm version
Output of the command
Version: dev; Commit: 930991cbc4a211c43c15195a7a4c7d2c867ddf05; Date: 2020-08-25-09:22

Install the service mesh using the following command:

$ osm install --osm-image-tag 930991cbc4a211c43c15195a7a4c7d2c867ddf05
Output of the command
OSM installed successfully in namespace [osm-system] with mesh name [osm]

We can then check the installation of OSM using the following command:

$ kubectl get pods --namespace osm-system
Output of the command
NAME                              READY   STATUS    RESTARTS   AGE
jaeger-6864b858c5-mwc24           1/1     Running   0          116s
osm-controller-8554b44bd4-lvvpp   1/1     Running   0          116s
osm-grafana-fdc677699-r8j2x       1/1     Running   0          116s
osm-prometheus-6cdf59c56f-5s5gg   1/1     Running   0          116s

Let's onboard the services of our demo to the service mesh via the Kubernetes namespace using the following command:

$ osm namespace add demo
Output of the command
Namespace [demo] successfully added to mesh [osm]

We also need to delete the pods so they get re-created them with the sidecar proxy injected:

$ kubectl delete pods --all -n demo
Output of the command
pod "client-x-version-1-0-1-deployment-7db9cf495b-5cmc6" deleted
pod "service-a-version-1-0-0-deployment-5d4fbcc598-22pj6" deleted

Looking back at the pods using the following command:

$ kubectl get pods -n demo
Output of the command
NAME                                                  READY   STATUS    RESTARTS   AGE
client-x-version-1-0-1-deployment-7db9cf495b-8t7xs    2/2     Running   0          92s
service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv   2/2     Running   0          92s

We can now see that there are two containers per pod, because of the injection of the sidecar proxies.

And, the demo, as expected, does not work anymore:

$ kubectl logs client-x-version-1-0-1-deployment-7db9cf495b-8t7xs client-x -n demo | tail
Output of the command
[INFO] get /path-02 | 404
[INFO] get /path-01 | 404
[INFO] get /path-02 | 404
[INFO] get /path-01 | 404
[INFO] get /path-02 | 404
[INFO] get /path-01 | 404
[INFO] get /path-02 | 404
[INFO] get /path-01 | 404
[INFO] get /path-02 | 404
[INFO] get /path-01 | 404

We need to explicitly allow the traffic from client-x to service-a using TrafficTarget SMI configuration:

# uc-02.01.smi.yaml
---
apiVersion: specs.smi-spec.io/v1alpha3
kind: HTTPRouteGroup
metadata:
  name: alpha-api-routes
  namespace: demo
spec:
  matches:
  - name: get-path-01
    pathRegex: /path-01
    methods:
    - GET
  - name: get-path-02
    pathRegex: /path-02
    methods:
    - GET
---
# Deploy the 'allow-client-x-to-service-a-through-alpha-api-routes' TrafficTarget
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha2
metadata:
  name: allow-client-x-to-service-a-through-alpha-api-routes
  namespace: demo
spec:
  destination:
    kind: ServiceAccount
    name: service-a
    namespace: demo
    port: 3000
  rules:
  - kind: HTTPRouteGroup
    name: alpha-api-routes
    matches:
    - get-path-01
    - get-path-02
  sources:
  - kind: ServiceAccount
    name: client-x
    namespace: demo
$ kubectl apply -f uc-02.01.smi.yaml
Output of the command
httproutegroup.specs.smi-spec.io/alpha-api-routes created
traffictarget.access.smi-spec.io/allow-client-x-to-service-a-through-alpha-api-routes created

Let's have a look back at the log of client-x:

$ kubectl logs client-x-version-1-0-1-deployment-7db9cf495b-8t7xs client-x -n demo | tail
Output of the command
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv

We can see that client-x can reach back service-a.

UC-02.02 | Let's split the implementation of two API endpoints which belong to the same API

Let's have the version 1.0.0 of service-b implementing the second API endpoint โ€“ get /path-02.

alt text

Demo Configuration

The Kubernetes manifests of the above situation can be written as follow:

# uc-02.02.yaml
---
# Deploy 'service-b' Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: service-b
  namespace: demo
---
# Deploy 'service-b-version-1-0-0-deployment' Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-b-version-1-0-0-deployment
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: service-b
      version: 1.0.0
      api: acme-api
  template:
    metadata:
      labels:
        app: service-b
        version: 1.0.0
        api: acme-api
    spec:
      serviceAccountName: service-b
      containers:
      - name: service-b
        image: patrice1972/service-b:1.0.0
        ports:
        - name: service-b-port
          protocol: TCP
          containerPort: 3000
---
# Deploy 'service-b-version-1-0-0' Service
apiVersion: v1
kind: Service
metadata:
  name: service-b-version-1-0-0
  namespace: demo
spec:
  selector:
    app: service-b
    version: 1.0.0
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000

You can deploy them using the following command:

$ kubectl apply -f https://raw.githubusercontent.com/patricekrakow/service-mesh-use-cases/master/uc-02.02.yaml

or

$ kubectl apply -f uc-02.02.yaml
Output of the command
serviceaccount/service-b created
deployment.apps/service-b-version-1-0-0-deployment created
service/service-b-version-1-0-0 created

Then, you can verify that the installation of the demo using the following command:

$ kubectl get pods -n demo
Output of the command
NAME                                                  READY   STATUS    RESTARTS   AGE
client-x-version-1-0-1-deployment-7db9cf495b-8t7xs    2/2     Running   0          17m
service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv   2/2     Running   0          17m
service-b-version-1-0-0-deployment-5b44559c86-nrmgw   2/2     Running   0          38s

Now, if you look at how the demo is working using the following command:

kubectl logs client-x-version-1-0-1-deployment-7db9cf495b-8t7xs client-x -n demo | tail
Output of the command
[INFO] get /path-01 | 404
[INFO] get /path-02 | Hello from get /path-02 | service-b (1.0.0) | service-b-version-1-0-0-deployment-5b44559c86-nrmgw
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | 404
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | 404
[INFO] get /path-02 | Hello from get /path-02 | service-b (1.0.0) | service-b-version-1-0-0-deployment-5b44559c86-nrmgw
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv

I cannot know if the 404 is coming from service-b or from the sidecar proxies. However it's weird to get response from service-b since we don't have any TrafficTarget configuration for service-b.

You will see that the client-x does not always get a reply when calling get /path-01 which corresponds to the situation when it get directed to service-b.

We need to configure the mesh to make sure that the route to get /path-01 only goes to service-a while the route to get /path-02 can go to both service-a and service-b.

# uc-02.02.smi.yaml
---
apiVersion: specs.smi-spec.io/v1alpha3
kind: HTTPRouteGroup
metadata:
  name: alpha-api-routes
  namespace: demo
spec:
  matches:
  - name: get-path-01
    pathRegex: /path-01
    methods:
    - GET
  - name: get-path-02
    pathRegex: /path-02
    methods:
    - GET
---
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
  name: get-path-01-traffic
  namespace: demo
spec:
  service: acme-api
  matches:
  - kind: HTTPRouteGroup
    name: get-path-01
  backends:
  - service: service-a-version-1-0-0
    weight: 100
  - service: service-b-version-1-0-0
    weight: 0
---
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
  name: get-path-02-traffic
  namespace: demo
spec:
  service: acme-api
  matches:
  - kind: HTTPRouteGroup
    name: get-path-02
  backends:
  - service: service-a-version-1-0-0
    weight: 90
  - service: service-b-version-1-0-0
    weight: 10

You can deploy them using the following command:

$ kubectl apply -f https://raw.githubusercontent.com/patricekrakow/service-mesh-use-cases/master/uc-02.02.smi.yaml

or

$ kubectl apply -f uc-02.02.smi.yaml
Output of the command
httproutegroup.specs.smi-spec.io/alpha-api-routes unchanged
trafficsplit.split.smi-spec.io/get-path-01-traffic created
trafficsplit.split.smi-spec.io/get-path-02-traffic created

Now, you can verify that the demo is working properly using the following command:

$ kubectl logs client-x-version-1-0-1-deployment-7db9cf495b-8t7xs client-x -n demo | tail
Output of the command

It does NOT always work... yet :-(

[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | 503
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | Hello from get /path-01 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv
[INFO] get /path-01 | 503
[INFO] get /path-02 | 503
[INFO] get /path-01 | 503
[INFO] get /path-02 | Hello from get /path-02 | service-a (1.0.0) | service-a-version-1-0-0-deployment-5d4fbcc598-j6jzv

service-mesh-use-cases's People

Contributors

patricekrakow avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.