OTEL Tracing demo with ADOT, AWS X-Ray and Grafana

Shakir - Apr 26 - - Dev Community

Introduction

Hello 👋, In this post we'll see about sending traces from a demo app to AWS X-Ray via the ADOT(AWS Distro for OpenTelemetry) collector. We would then visualize this on Grafana. Note that we'd deploy the workloads on a kubernetes cluster.

Here is a picture of what we are trying to accomplish:
Block diagram for the lab

Alright, let's get started!!!

Namespace

We shall deploy the workloads on a separate namespace. Let's create one.



kubectl create ns adot-traces-demo


Enter fullscreen mode Exit fullscreen mode

Credentials

Store the AWS credentials as a kubernetes secret.



kubectl create secret generic aws-credentials \
    --from-literal=AWS_ACCESS_KEY_ID=<access-key-id> \
    --from-literal=AWS_SECRET_ACCESS_KEY=<aws-secret-access-key> \
    -n adot-traces-demo


Enter fullscreen mode Exit fullscreen mode

ADOT Config

Set the ADOT config in a file.



$ cat adot-config.yaml
exporters:
  awsxray:
    region: ap-south-2
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
service:
  pipelines:
    traces:
      exporters:
        - awsxray
      receivers:
        - otlp


Enter fullscreen mode Exit fullscreen mode

And create a config map with this file.



kubectl create configmap adot-config --from-file=adot-config.yaml -n adot-traces-demo 


Enter fullscreen mode Exit fullscreen mode

ADOT Deployment

Setup deployment spec in a file, that injects the secret we created earlier as environment variables and the configmap as a volume.



$ cat adot-deploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: adot-collector
  name: adot-collector
spec:
  replicas: 1
  selector:
    matchLabels:
      app: adot-collector
  template:
    metadata:
      labels:
        app: adot-collector
    spec:
      containers:
        - args:
            - '--config=/etc/adot-config.yaml'
          envFrom:
            - secretRef:
                name: aws-credentials
          image: public.ecr.aws/aws-observability/aws-otel-collector:latest
          name: adot-collector
          volumeMounts:
            - mountPath: /etc/adot-config.yaml
              name: config-volume
              subPath: adot-config.yaml
      volumes:
        - configMap:
            name: adot-config
          name: config-volume


Enter fullscreen mode Exit fullscreen mode

Create the deployment.



kubectl create -f adot-deploy.yaml -n adot-traces-demo


Enter fullscreen mode Exit fullscreen mode

The pod in the deployment should be running.



$ kubectl get po -n adot-traces-demo
NAME                              READY   STATUS    RESTARTS   AGE
adot-collector-7cbf849b89-b4bkl   1/1     Running   0          3m26s


Enter fullscreen mode Exit fullscreen mode

ADOT Service

We can expose the ADOT deployment with a service spec that exposes the grpc port 4317 as follows.



$ cat adot-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: adot-collector-service
spec:
  selector:
    app: adot-collector
  ports:
    - protocol: TCP
      port: 4317
      targetPort: 4317


Enter fullscreen mode Exit fullscreen mode

We can now create the service.



kubectl create -f adot-svc.yaml -n adot-traces-demo


Enter fullscreen mode Exit fullscreen mode

The endpoint IP should match with the pod IP.



$ kubectl get ep -n adot-traces-demo
NAME                     ENDPOINTS         AGE
adot-collector-service   10.1.3.187:4317   22s

$ kubectl get po -n adot-traces-demo -o wide
NAME                              READY   STATUS    RESTARTS   AGE     IP           NODE             NOMINATED NODE   READINESS GATES
adot-collector-7cbf849b89-b4bkl   1/1     Running   0          7m11s   10.1.3.187   docker-desktop   <none>           <none>


Enter fullscreen mode Exit fullscreen mode

Demo app

We can now deploy the sample demo app which can send traces to ADOT collector, with the following manifest.



$ cat k6-tracing-deploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: xk6-tracing
spec:
  replicas: 1
  selector:
    matchLabels:
      app: xk6-tracing
  template:
    metadata:
      labels:
        app: xk6-tracing
    spec:
      containers:
        - env:
            - name: ENDPOINT
              value: adot-collector-service:4317
          image: ghcr.io/grafana/xk6-client-tracing:v0.0.2
          name: xk6-tracing


Enter fullscreen mode Exit fullscreen mode

Let's create the deployment.



kubectl create -f k6-tracing-deploy.yaml -n adot-traces-demo


Enter fullscreen mode Exit fullscreen mode

Both the ADOT collector and k6-tracing pods should now be running.



$ kubectl get po -n adot-traces-demo

NAME READY STATUS RESTARTS AGE
adot-collector-7cbf849b89-b4bkl 1/1 Running 0 14m
xk6-tracing-69b48fcfd9-bjzbd 1/1 Running 0 24s

Enter fullscreen mode Exit fullscreen mode




X-Ray

We can now headover to AWS X-Ray, in ap-south-2 region that we mentioned in the adot-config.
Traces in AWS X-Ray

The nodes(services) shown in the screenshot belong to our demo application. We could filter for traces that passes through a particular service name for ex. article service, like below.
Traces

If we click on a single trace we should be able to see a complete service map for that trace, that shows all the services that trace traverses.
Service map for a trace

If we go a further down on this we should be able to see the details for segments/spans with in this trace.
Spans in trace

Grafana

So we far we were able to see the traces in AWS X-Ray, we can do a similar exercise on Grafana. I am using a Grafana Cloud Free subscription for this lab.

Go to Connections, Add a new connection and search for X-Ray and install it.
Install X-Ray

You can then go to datasources, add a new X-Ray datasource with the access key id, secret access key, and default region(I have chosen ap-south-2 which matches with adot config).

Add X-Ray datasource

All good, we can try adding a new panel, go to dashboards > new dashboard and a new visualization with table as panel type and a sample query for ex. service(id(name: "article-service" ))
Traces in tabular format

We can click on one of the traces we should take us to the explore view where we can see the node graph(service map)
Node graph for trace in grafana

We should also see the trace explorer that shows the individual spans.
Trace explorer in Grafana

Okay so we reached this far, that was some fun exploring traces on AWS and Grafana with Open Telemetry. Thank you for reading !!!

CleanUp

Just delete the namespace with kubectl delete ns adot-traces-demo and it should remove the workloads we deployed from kubernetes and stop sending any new data to the cloud.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .