This page installs the NRDOT Collector using Helm, configures it to scrape Linkerd proxy and control plane metrics, and verifies that data is flowing to New Relic. Expect this to take about 15 minutes.
Compatibility and requirements
Supported
- Kubernetes cluster (EKS, GKE, AKS, or self-managed) with
kubectlconfigured against it - Linkerd installed and healthy (
linkerd checkpasses) - Helm-managed cluster configuration
You need
A New Relic ingest license key
The base Kubernetes OpenTelemetry Helm installation completed
Network connectivity to New Relic OTLP endpoints
Injection enabled on the namespaces you want to observe. If it isn't, annotate and restart them:
bash$kubectl annotate namespace <YOUR_NAMESPACE> linkerd.io/inject=enabled$kubectl rollout restart deployment -n <YOUR_NAMESPACE>
ヒント
The NRDOT Helm chart bundles kube-state-metrics and enables it by default, so your Kubernetes workload entities are already correlated with Linkerd metrics. No extra setup needed.
Install
Set your cluster name in your
values.yaml.deployment:envs:- name: OTEL_RESOURCE_ATTRIBUTESvalue: "k8s.cluster.name=<YOUR_CLUSTER_NAME>"Add the Linkerd scrape config and processors to
deployment.configMap.extraConfigin yourvalues.yaml.receivers:prometheus:config:scrape_configs:- job_name: 'linkerd-controller'kubernetes_sd_configs:- role: podnamespaces: { names: ['linkerd', 'linkerd-viz'] }relabel_configs:- { source_labels: [__meta_kubernetes_pod_container_port_name], action: keep, regex: admin-http }- { source_labels: [__meta_kubernetes_pod_container_name], target_label: component }- { source_labels: [__meta_kubernetes_namespace], target_label: namespace }- { source_labels: [__meta_kubernetes_pod_name], target_label: pod }- job_name: 'linkerd-proxy'kubernetes_sd_configs: [{ role: pod }]relabel_configs:- { source_labels: [__meta_kubernetes_pod_container_name, __meta_kubernetes_pod_container_port_name, __meta_kubernetes_pod_label_linkerd_io_control_plane_ns], action: keep, regex: ^linkerd-proxy;linkerd-admin;linkerd$$ }- { source_labels: [__meta_kubernetes_namespace], target_label: namespace }- { source_labels: [__meta_kubernetes_pod_name], target_label: pod }- { source_labels: [__meta_kubernetes_pod_label_linkerd_io_control_plane_ns], target_label: linkerd_control_plane_ns }- { source_labels: [__meta_kubernetes_pod_label_linkerd_io_control_plane_component], target_label: linkerd_control_plane_component }processors:resource/strip_service:attributes:- { key: service.name, action: delete }- { key: service.instance.id, action: delete }transform/k8s:metric_statements:- context: datapointstatements:- set(attributes["k8s.namespace.name"], attributes["namespace"]) where attributes["namespace"] != nil- set(attributes["k8s.pod.name"], attributes["pod"]) where attributes["pod"] != nil- delete_key(attributes, "instance")transform/deployment:metric_statements:- context: datapointstatements:- set(attributes["k8s.deployment.name"], attributes["k8s.pod.name"]) where attributes["k8s.deployment.name"] == nil and attributes["k8s.pod.name"] != nil- replace_pattern(attributes["k8s.deployment.name"], "-[a-z0-9]+-[a-z0-9]+$", "") where attributes["k8s.deployment.name"] == attributes["k8s.pod.name"]transform/metadata_nullify:metric_statements:- context: metricstatements:- set(description, "")- set(unit, "")filter/drop_unused:error_mode: ignoremetrics:metric:- 'name == "rustls_info" or name == "proxy_build_info"'- 'name == "scrape_series_added"'- 'IsMatch(name, "stack_(poll|create|drop)_total") or name == "stack_poll_total_ms"'- 'IsMatch(name, "tokio_rt_.*")'- 'IsMatch(name, "(inbound|outbound)_http_.*_frame_size_bytes")'- 'IsMatch(name, "(inbound|outbound)_tcp_detect_http_duration_seconds")'- 'IsMatch(name, "outbound_tcp_balancer_queue_.*")'- 'name == "scrape_duration_seconds" or name == "scrape_samples_scraped" or name == "scrape_samples_post_metric_relabeling"'pipelines:metrics/linkerd:receivers: [prometheus]processors: [memory_limiter, resource/strip_service, transform/k8s, transform/deployment, transform/metadata_nullify, filter/drop_unused, resource/newrelic, batch]exporters: [otlp_http/newrelic]pipelines:must be defined at the root ofextraConfig, not nested underservice:. The Helm chart template mapsextraConfig.pipelinesintoservice.pipelines.
Configure
Update the
values.yamlfile as per the following table:Parameter Description OTEL_RESOURCE_ATTRIBUTESSet k8s.cluster.nameto your Kubernetes cluster name for identification in New Relicfilter/drop_unusedDrops low-value Linkerd proxy metrics by default. Remove entries from this list to re-enable them Apply the updated values to your running Helm release.
bash$helm upgrade nr-k8s-otel-collector newrelic/nr-k8s-otel-collector \>--namespace newrelic --reuse-values -f values.yaml
Find your data
- Go to one.newrelic.com > All capabilities > All entities.
- Search for your cluster name.
- Select your Linkerd entity to open the built-in dashboard.
The built-in dashboard covers request rate, latency p50/p95/p99, success rate, TCP connections, mTLS certificate status, control plane health, and meshed pod inventory. For detailed information, refer to Find Linkerd data documentation.
Related articles
Linkerd distributed tracing with OpenTelemetry
Enable proxy trace export and instrument your application pods to correlate mesh spans with APM traces.
Collect Linkerd proxy logs
Optionally collect linkerd-proxy sidecar container logs.
Metrics reference
Full list of Linkerd metrics and resource attributes collected by the OTel Collector.