Overview

OpenShift Service Mesh (OSSM) is the Red Hat version of the opensource Istio project, which provides seamless networking capabilities like dynamic endpoint routing, security, and health monitoring.

I’ve also been told that OSSM is actually based on Maistra, rather than directly on Istio, and some of the setup steps are definitely maistra.io annotations.

Also, the Kiali tool provides visualization of this networking configuration.

Implementation

Service Mesh Operator

The Red Hat OpenShift Service Mesh Operator seems to be based on earlier versions of Maistra and Istio. That is, this official Operator seems to not stay on the leading edge of those upstream projects. Of particular note, I think it’s still using the 1.x Maistra project, not the newer 2.x.

Note this Operator also requires installation of the following Operators:

  • ElasticSearch
  • Jaeger
  • Kiali

The Operator is globally installed in the OCP cluster. A “Control Plane” instance is then created, say in the istio-system Project. Then, a “Member Roll” is created, where Projects that want to participate in the Service Mesh must be manually added.

Note that once a Project is added to the mesh (via the Member Roll), at least all external network routing (Route objects) to applications within that Project will cease to work until appropriate Istio objects are created for them.

Documentation seems to suggest a simple label that will expose even non-managed applications, but I never got this to work.

Application Enablement

To enable an Application to be managed by Istio/Service Mesh, the following steps are required:

  1. Create a normal k8s Service object
  2. Add an annotation for Istio Envoy sidecar injection to the application Pod template (e.g. in a Deployment)
  3. Create an Istio VirtualService object to route to the above Service
  4. Create an Istio “ingress” Gateway object to route to the above VirtualService

Deployment example

kind: Deployment
apiVersion: apps/v1
metadata:
  name: my-app1

spec:
  selector:
    matchLabels:
      app: my-app1

  template:
    metadata:
      labels:
        app: my-app1
      annotations:
        # for Service Mesh/Istio Envoy injection
        sidecar.istio.io/inject: 'true'
  ...

OpenLiberty Operator example

apiVersion: openliberty.io/v1beta1
kind: OpenLibertyApplication
metadata:
  name: my-api
  labels:
    app: my-api
  annotations:
    # for Service Mesh/Istio injection
    sidecar.istio.io/inject: 'true'
...
spec:
  ...
  expose: false   # will have istio expose instead
  ...

VirtualService and Gateway example

The following can be split into separate files, but as you seem to always need both, I’m not sure what value that would provide.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-api-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - my-api.apps.ocp1.myocp.com
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: my-api
spec:
  hosts:
  - my-api.apps.ocp1.myocp.com
  gateways:
  - my-api-gateway
  http:
  - route:
    - destination:
        host: my-api # reference to the Service
        port:
          number: 9080

I also really, really wish you didn’t have to specify the full cluster host name in here. Most examples use "*" instead, but this won’t work when you have more than one application from the Project participating. And the short name doesn’t work either. (About which I’ve seen at least a couple of Issues raised somewhere.)

Routes

Note that the Gateway creation, I think specifically with spec.selector.istio=ingressgateway, actually causes a Route to be created over in the istio-system Project. This is why no Route in the application Project is needed/used.

$ oc get routes -n istio-system
NAME                                                HOST/PORT                                                     PATH   SERVICES               PORT    TERMINATION          WILDCARD
my-project-my-api-gateway-3552b80c74b8b4d5          my-api.apps.ocp1.myocp.com
               istio-ingressgateway   http2                        None
my-project-my-app1-gateway-b9422a85a9e29f30         my-app1.apps.ocp1.myocp.com
               istio-ingressgateway   http2                        None
...

I believe this is due to what Maistra calls IOR, which does seem to be enabled by the OSSM Control Plane, by default.

        istio-ingressgateway:
          autoscaleEnabled: false
          enabled: true
          gatewayType: ingress
          ior_enabled: true
          name: istio-ingressgateway
          resources:
            requests:
              cpu: 10m
              memory: 128Mi
          type: ClusterIP

I believe there are other approaches here that require more manual configuration, but I haven’t understood those yet.

External services

Istio can manage and visualize connections to external services as well, if those are wrapped in a ServiceEntry object.

For example, to a remote JDBC endpoint:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: db2jdbc-svc-entry
spec:
  hosts:
  - db2server.mydomain.com
  ports:
  - number: 60000
    name: tcp
    protocol: tcp
  location: MESH_EXTERNAL
  resolution: DNS

Troubleshooting

Istio GitHub Troubleshooting article

The istioctl command-line tool can provide some insight into the current Istio configuration. It’s apparently not supported by Red Hat, but it did work for me against our cluster. See Debugging Envoy and Istiod.

Also, the Kiali tool does some configuration analysis and flags errors or warnings in the Istio configuration. Some of the things it warns about appear to be “best practice” items for Kiali itself, that don’t break Istio functionality. But others are genuine mistakes in the configuration.

References