Elven Observability: Operator Collector (Automatic Instrumentation)

In order to use auto-instrumentation, we need to install the collector operator.

Dependencies:
cert-manager

Install the operator

				
					kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
				
			
  • If you are going to instrument Golang applications:
				
					kubectl -n opentelemetry-operator-system patch deployment opentelemetry-operator-controller-manager \
--type=json \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--enable-go-instrumentation=true"}]'
				
			

Install the collector

It is a recommended practice to send telemetry from containers to an OpenTelemetry Collector rather than directly to a backend. The Collector helps simplify secrets management, decouples data export issues (such as the need for retries) from your applications, and allows you to add additional data to your telemetry, such as with the k8sattributesprocessor component. If you choose not to use a Collector, you can skip to the next section.

https://opentelemetry.io/docs/kubernetes/operator/automatic/

Configuration example

				
					apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: otel
spec:
  config: 
    receivers:
      otlp:
        protocols:
          grpc:
          http:
    processors:
      memory_limiter:
        check_interval: 1s
        limit_percentage: 75
        spike_limit_percentage: 15
      batch:
        send_batch_size: 10000
        timeout: 10s
    exporters:
      otlp:
        endpoint: "tempo-distributor.domain.io:443"
        tls:
          insecure: false
          insecure_skip_verify: true
      prometheusremotewrite:
        endpoint: https://mimir-distributor.domain.io/api/v1/push
        headers:
          X-Scope-OrgID: <TENANT>          
    service:
      pipelines:
        metrics:
          receivers: [otlp] 
          processors: [batch]
          exporters: [prometheusremotewrite]
        traces:
          receivers: [otlp]
          processors: []
          exporters: [otlp]
				
			
  • Apply the collector
				
					kubectl apply -k otel-collector-operator/
				
			

OpenTelemetry Instrumentation

To manage auto-instrumentation, the Operator needs to be configured to know which pods to instrument and which auto-instrumentation to use for those pods. This is done through the Instrumentation CRD.

Ex. Java

				
					apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: instrumentation-sample
spec:
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1"
  env:
    - name: OTEL_EXPORTER_OTLP_ENDPOINT
      value: otel-collector.monitoring:4318
  java:    
    env:
      - name: OTEL_EXPORTER_OTLP_ENDPOINT
        value: http://otel-collector.monitoring:4317 
				
			

Ex. DOTNET

				
					apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: instrumentation-sample
spec:
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1"
  env:
    - name: OTEL_EXPORTER_OTLP_ENDPOINT
      value: otel-collector.default:4318   
  dotnet:
    env:
      - name: OTEL_DOTNET_AUTO_METRICS_CONSOLE_EXPORTER_ENABLED
        value: "false"
      - name: OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED
        value: "false"
      - name: OTEL_DOTNET_AUTO_LOGS_CONSOLE_EXPORTER_ENABLED
        value: "false"  
      - name: OTEL_EXPORTER_OTLP_ENDPOINT
        value: http://otel-collector.monitoring:4318
      - name: OTEL_TRACES_EXPORTER
        value: "true"
      - name: OTEL_METRICS_EXPORTER
        value: "true"
				
			

Add annotations to existing deployments

The final step is to opt-in your services for auto-instrumentation. This is done by updating your services spec.template.metadata.annotations to include a language-specific annotation:

  • .NET: instrumentation.opentelemetry.io/inject-dotnet: “true”
  • Go: instrumentation.opentelemetry.io/inject-go: “true”
  • Java: instrumentation.opentelemetry.io/inject-java: “true”
  • Node.js: instrumentation.opentelemetry.io/inject-nodejs: “true”
  • Python: instrumentation.opentelemetry.io/inject-python: “true”

Test application using auto-instrumentation for JAVA
https://opentelemetry.io/docs/kubernetes/operator/automatic/

				
					kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: java-sample
  template:
    metadata:
      labels:
        app: java-sample
      annotations:
        instrumentation.opentelemetry.io/inject-java: "true"
    spec:
      containers:
      - name: java-sample
        image: emr001/java-app
        ports:
        - containerPort: 8080
        env:
          - name: OTEL_SERVICE_NAME
            value: "java-demo"
---
apiVersion: v1
kind: Service
metadata:
  name: java-app
spec:
  selector:
    app: java-sample
  ports:
    - port: 8080
      protocol: TCP
      targetPort: 8080
---
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: instrumentation-sample
spec:
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1"
  env:
    - name: OTEL_EXPORTER_OTLP_ENDPOINT
      value: otel-collector.monitoring:4318
  java:    
    env:
      - name: OTEL_EXPORTER_OTLP_ENDPOINT
        value: http://otel-collector.monitoring:4317
  dotnet:
    env:
      - name: OTEL_DOTNET_AUTO_METRICS_CONSOLE_EXPORTER_ENABLED
        value: "false"
      - name: OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED
        value: "false"
      - name: OTEL_DOTNET_AUTO_LOGS_CONSOLE_EXPORTER_ENABLED
        value: "false"  
      - name: OTEL_EXPORTER_OTLP_ENDPOINT
        value: http://otel-collector.monitoring:4318
      - name: OTEL_TRACES_EXPORTER
        value: "true"
      - name: OTEL_METRICS_EXPORTER
        value: "true"              
EOF 
				
			

Restart the deployment for the operator to inject the agent via an init-container

				
					kubectl rollout restart deployment java-sample 
				
			

Perform a port-forward on port 8080 and use the loop below to send traces, metrics, and logs.

				
					kubectl port-forward svc/java-app 8080:8080
				
			

We will create a loop to send several requests.

				
					while true; do curl http://localhost:8080/api/hello && echo "" && sleep 1; done
				
			

Tracing Grafana

  • Test application using auto-instrumentation for .NET

				
					kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dotnet-sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dotnet-sample
  template:
    metadata:
      labels:
        app: dotnet-sample
      annotations:
        instrumentation.opentelemetry.io/inject-dotnet: "true"
    spec:
      containers:
      - name: dotnet-sample
        image: emr001/dotnet8-app:v1
        ports:
        - containerPort: 8080
        env:
          - name: OTEL_SERVICE_NAME
            value: "dotnet-demo"
---
apiVersion: v1
kind: Service
metadata:
  name: dotnet-app
spec:
  selector:
    app: dotnet-sample
  ports:
    - port: 80
      protocol: TCP
      targetPort: 8080
EOF
				
			

Restart the deployment for the operator to inject the agent via an init-container

				
					kubectl rollout restart deployment dotnet-sample 
				
			

Restart the deployment for the operator to inject the agent via an init-container

				
					kubectl port-forward svc/dotnet-app 80:80
				
			

We will create a loop to send several requests.

				
					while true; do curl http://localhost/weatherforecast && echo "" && sleep 1; done
				
			
				
					while true; do curl http://localhost/error && echo "" && sleep 1; done
				
			

Dashboard Grafana

Scroll to Top