---
# System prepended metadata

title: Set up OpenShift Service Mesh 2.6 + Distributed Tracing (Tempo)

---

# Set up OpenShift Service Mesh + Distributed Tracing (Tempo)

## ！！！此文件目的為驗證服務架構，非生產環境安裝指引！！！

## The whole picture of OSSM + Tempo

![image](https://hackmd.io/_uploads/ryYrDPBsR.png)

## Environment and important pre-set

- Resource Hub OCP 4.16 cluster

- minio is installed in ns/minio
- Minio Access Key : `tempo`
- Minio Secret Key : `supersecret`
- Minio's svc is named `minio` 
- TempoStack is installed in ns/tracing-system
- TempoStack is named `sample`
- A OpenTelemetryCollector named `otel` is installed in ns/otel-collector
- otel collector's svc is named `otel-collector`

## Install NFS Provisioner Operator (You can use other Storage class)

### Install Operator
```bash=
# Create a new namespace
oc new-project nfsprovisioner-operator

# Deploy NFS Provisioner operator in the terminal (You can also use OpenShift Console
cat << EOF | oc apply -f -  
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: nfs-provisioner-operator
  namespace: openshift-operators
spec:
  channel: alpha
  installPlanApproval: Automatic
  name: nfs-provisioner-operator
  source: community-operators
  sourceNamespace: openshift-marketplace
EOF
```

### Create NFS server mount path on a worker node
```bash=
# Check nodes
oc get nodes
NAME                                      STATUS   ROLES                  AGE   VERSION
master-0.smtest.lab.psi.pnq2.redhat.com   Ready    control-plane,master   44m   v1.29.6+aba1e8d
master-1.smtest.lab.psi.pnq2.redhat.com   Ready    control-plane,master   44m   v1.29.6+aba1e8d
master-2.smtest.lab.psi.pnq2.redhat.com   Ready    control-plane,master   44m   v1.29.6+aba1e8d
worker-0.smtest.lab.psi.pnq2.redhat.com   Ready    worker                 22m   v1.29.6+aba1e8d
worker-1.smtest.lab.psi.pnq2.redhat.com   Ready    worker                 22m   v1.29.6+aba1e8d

# Set Env variable for the target node name
export target_node=worker-0.smtest.lab.psi.pnq2.redhat.com
oc label node/${target_node} app=nfs-provisioner

# ssh to the node
oc debug node/${target_node}

# Create a directory and set up the Selinux label.
chroot /host
mkdir -p /home/core/nfs
chcon -Rvt svirt_sandbox_file_t /home/core/nfs
exit 
exit
```

### Create NFS Provisioner CRD
```bash=
# Create NFSProvisioner Custom Resource
cat << EOF | oc apply -f -  
apiVersion: cache.jhouse.com/v1alpha1
kind: NFSProvisioner
metadata:
  name: nfsprovisioner-sample
  namespace: nfsprovisioner-operator
spec:
  hostPathDir: /home/core/nfs
  nodeSelector:
    app: nfs-provisioner
EOF

# Check if NFS Server is running
oc get pod
NAME                               READY   STATUS    RESTARTS   AGE
nfs-provisioner-77bc99bd9c-57jf2   1/1     Running   0          2m32s
```

oc adm policy add-scc-to-user hostmount-anyuid -z nfs-provisioner -n nfsprovisioner-operator

```bash=
# Update annotation of the NFS StorageClass
oc patch storageclass nfs -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

# Check the default next to nfs StorageClass
oc get sc
NAME            PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs (default)   example.com/nfs   Delete          Immediate           false                  4m29s
```


## Install Minio to provide Object storage

```bash=
# Create NS for minio
oc new-project minio

# Create SS for minio

cat << EOF | oc apply -f -
kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: minio
  namespace: minio
  labels:
    app: minio
spec:
  serviceName: minio
  revisionHistoryLimit: 10
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain
    whenScaled: Retain
  volumeClaimTemplates:
    - kind: PersistentVolumeClaim
      apiVersion: v1
      metadata:
        name: data
        creationTimestamp: null
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
        storageClassName: nfs # << Should fit your default SC
        volumeMode: Filesystem
      status:
        phase: Pending
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: minio
    spec:
      containers:
        - resources: {}
          terminationMessagePath: /dev/termination-log
          name: minio
          env:
            - name: MINIO_ACCESS_KEY
              value: tempo
            - name: MINIO_SECRET_KEY
              value: supersecret
            - name: MINIO_KMS_SECRET_KEY
              value: 'my-minio-key:oyArl7zlPECEduNbB1KXgdzDn2Bdpvvw0l8VO51HQnY='
          ports:
            - containerPort: 9000
              protocol: TCP
          imagePullPolicy: Always
          volumeMounts:
            - name: data
              mountPath: /data
          terminationMessagePolicy: File
          image: 'quay.io/rhn_support_jaliang/minio/minio:RELEASE.2023-05-27T05-56-19Z'
          args:
            - server
            - /data
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirst
      securityContext: {}
      schedulerName: default-scheduler
  podManagementPolicy: OrderedReady
  replicas: 1
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0
  selector:
    matchLabels:
      app: minio
EOF
```

Create Service for Minio
```bash=
cat << EOF | oc apply -f -
apiVersion: v1
kind: Service
metadata:
  name: minio
  labels:
    app: minio
spec:
  type: NodePort
  ports:
    - port: 9000
      name: minio
      nodePort: 30080
  selector:
    app: minio
EOF
```

Create route for minio client
```bash=
oc expose svc/minio -n minio
```

Using minio client to create bucket for Tempo on Bastion

```bash=

curl https://dl.min.io/client/mc/release/linux-amd64/mc \
  --create-dirs \
  -o $HOME/minio-binaries/mc

chmod +x $HOME/minio-binaries/mc
export PATH=$PATH:$HOME/minio-binaries/


[quickcluster@upi-0 ~]$ oc get route
NAME    HOST/PORT                                         PATH   SERVICES   PORT    TERMINATION   WILDCARD
minio   minio-minio.apps.smtest.lab.psi.pnq2.redhat.com          minio      minio                 None
[quickcluster@upi-0 ~]$
[quickcluster@upi-0 ~]$ mc alias set myminio http://minio-minio.apps.smtest.lab.psi.pnq2.redhat.com --insecure
mc: Configuration written to `/home/quickcluster/.mc/config.json`. Please update your access credentials.
mc: Successfully created `/home/quickcluster/.mc/share`.
mc: Initialized share uploads `/home/quickcluster/.mc/share/uploads.json` file.
mc: Initialized share downloads `/home/quickcluster/.mc/share/downloads.json` file.
Enter Access Key: tempo
Enter Secret Key:
Added `myminio` successfully.


[quickcluster@upi-0 ~]$ mc ready play
The cluster is ready

[quickcluster@upi-0 ~]$ mc mb myminio/tempo
Bucket created successfully `myminio/tempo`.

```

## Install Tempo Operator and Create TempoStack

### Install Tempo Operator with default setting
https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html/distributed_tracing/distributed-tracing-platform-tempo#dist-tracing-tempo-installing
![image](https://hackmd.io/_uploads/ByiZBjroC.png)

### Create TempoStack 

```bash=
oc new-project tracing-system
```

Check minio's svc under ns/minio
```bash=
[quickcluster@upi-0 ~]$ oc get svc -n minio
NAME    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
minio   NodePort   172.30.63.66   <none>        9000:30080/TCP   8m9s
```

>> minio.minio.svc:9000

Create Secret with S3 endpoint info for Tempo
```bash=
cat << EOF | oc apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: minio
  namespace: tracing-system
stringData:
  endpoint: http://minio.minio.svc:9000
  bucket: tempo
  access_key_id: tempo
  access_key_secret: supersecret
type: Opaque
EOF
```

Create a TempoStack named `sample` under ns/tracing-system
```bash=
cat << EOF | oc apply -f -
apiVersion: tempo.grafana.com/v1alpha1
kind: TempoStack
metadata:
  name: sample
  namespace: tracing-system
spec:
  storageSize: 1Gi
  storage: 
    secret:
      name: minio
      type: s3
  resources:
    total:
      limits:
        memory: 2Gi
        cpu: 2000m
  template:
    queryFrontend:
      jaegerQuery: 
        enabled: true
        ingress:
          route:
            termination: edge
          type: route
EOF
```

Once TempoStack is ready, You will be able to access Jaeger console in ns/tracing-system.
```bash=
[quickcluster@upi-0 ~]$ oc get route
NAME                          HOST/PORT                                                                        PATH   SERVICES                      PORT        TERMINATION   WILDCARD
tempo-sample-query-frontend   tempo-sample-query-frontend-tracing-system.apps.smtest.lab.psi.pnq2.redhat.com          tempo-sample-query-frontend   jaeger-ui   edge          None
```


## Install Red Hat build of OpenTelemetry Operator

Install RH build of OpenTelemetry Operator with default setting.
https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html/red_hat_build_of_opentelemetry/install-otel

![image](https://hackmd.io/_uploads/ryNjusHiC.png)

### Create NS for otel-collector and create a OpenTelemetryCollector in this NS
```bash=
oc new-project otel-collector

cat << EOF | oc apply -f -
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: otel
  namespace: otel-collector  
  annotations:
    sidecar.istio.io/inject: 'true' 
spec:
  mode: deployment
  config: |
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
    exporters:
      otlp:
        endpoint: "tempo-sample-distributor.tracing-system.svc.cluster.local:4317" 
        tls:
          insecure: true
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: []
          exporters: [otlp]
EOF
```

Check otel-collector pod and svc
```bash=
[quickcluster@upi-0 ~]$ oc get po,svc -n otel-collector
NAME                                  READY   STATUS    RESTARTS   AGE
pod/otel-collector-7659b9d696-ktsgk   2/2     Running   0          112s

NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/otel-collector              ClusterIP   172.30.215.76   <none>        4317/TCP   112s
service/otel-collector-headless     ClusterIP   None            <none>        4317/TCP   112s
service/otel-collector-monitoring   ClusterIP   172.30.185.70   <none>        8888/TCP   112s
```

## Install ServiceMesh Operator 2.6


### Install required Operators
https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html/service_mesh/service-mesh-2-x#installing-ossm

https://docs.redhat.com/en/documentation/openshift_container_platform/4.16/html/service_mesh/service-mesh-2-x#ossm-viewing-metrics_observability

Install Servcie Mesh Operator 2.6 with default setting.
![image](https://hackmd.io/_uploads/Hk4LKoBoR.png)

Install Kiali Operator with default setting.
![image](https://hackmd.io/_uploads/B1eGA6srs0.png)

### Configure SMCP
```bash=
# Create NS for SM control Plane
oc new-project istio-system

# Create SMCP in ns/istio-system

cat << EOF | oc apply -f -
kind: ServiceMeshControlPlane
apiVersion: maistra.io/v2
metadata:
  name: basic
  namespace: istio-system
spec:
  addons:
    grafana:
      enabled: true
    kiali:
      enabled: true
    prometheus:
      enabled: true
  meshConfig:
    extensionProviders:
      - name: otel
        opentelemetry:
          port: 4317
          service: otel-collector.otel-collector.svc.cluster.local
  policy:
    type: Istiod
  telemetry:
    type: Istiod
  version: v2.6
EOF

# Create a Telemetry resource in istio-system
cat << EOF | oc apply -f -
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system
spec:
  tracing:
  - providers:
    - name: otel
    randomSamplingPercentage: 100
EOF
```

### Configure the Kiali resource specification to enable a Kiali workload traces dashboard. You can use the dashboard to view tracing query results.

```bash=

oc edit kiali kiali -n istio-system

apiVersion: kiali.io/v1alpha1
kind: Kiali
# ...
spec:
  external_services:
    tracing:
      query_timeout: 30
      enabled: true
      in_cluster_url: 'http://tempo-sample-query-frontend.tracing-system.svc.cluster.local:16685'
      url: 'http://tempo-sample-query-frontend-tracing-system.apps.smtest.lab.psi.pnq2.redhat.com'
      use_grpc: true
```


### Create SMMR for bookinfo and otel-collector NS
```bash=
cat << EOF | oc apply -f -
kind: ServiceMeshMemberRoll
apiVersion: maistra.io/v1
metadata:
  name: default
  namespace: istio-system
spec:
  members:
    - bookinfo
    - otel-collector
EOF
```

### Install bookinfo example in ns/bookinfo

```bash=
oc new-project bookinfo

oc apply -n bookinfo -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.6/samples/bookinfo/platform/kube/bookinfo.yaml


oc apply -n bookinfo -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.6/samples/bookinfo/networking/bookinfo-gateway.yaml

oc apply -n bookinfo -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.6/samples/bookinfo/networking/destination-rule-all.yaml


export GATEWAY_URL=$(oc -n istio-system get route istio-ingressgateway -o jsonpath='{.spec.host}')

echo "http://$GATEWAY_URL/productpage"

curl -k -I "http://$GATEWAY_URL/productpage"
HTTP/1.1 200 OK
server: istio-envoy
date: Fri, 23 Aug 2024 06:46:13 GMT
content-type: text/html; charset=utf-8
content-length: 5290
vary: Cookie
x-envoy-upstream-service-time: 37
set-cookie: cd10b69e39387eb7ec9ac241201ab1ab=479a0937580de7ceadd29a6d0ad0e86b; path=/; HttpOnly

```


## You can now access Jaeger in tracing-system NS and see bookinfo's tracing data

```bash=
[quickcluster@upi-0 ~]$ oc get route -n tracing-system
NAME                          HOST/PORT                                                                        PATH   SERVICES                      PORT        TERMINATION   WILDCARD
tempo-sample-query-frontend   tempo-sample-query-frontend-tracing-system.apps.smtest.lab.psi.pnq2.redhat.com          tempo-sample-query-frontend   jaeger-ui   edge          None
```

![image](https://hackmd.io/_uploads/B1-Hu2SoR.png)





# References

Install NFS Operator - https://developers.redhat.com/articles/2022/04/20/create-and-manage-local-persistent-volumes-codeready-containers

Install Minio in OCP CRC - https://blog.min.io/develop-on-openshift-with-minio/



