Kubesense

.NET on a Linux VM

Zero-code instrumentation for .NET applications running on Linux virtual machines.

This guide instruments a .NET application (.NET 6 or later) on a Linux VM with OpenTelemetry .NET automatic instrumentation. You don't change application code.

Prerequisites

  • A Linux VM with the .NET runtime installed
  • curl and unzip
  • The GitHub CLI (gh), signed in. The installer uses it to verify the downloaded release (see Step 1)
  • Network access from the VM to the KubeSense trace endpoint on port 33443. See Instrumentation.

Step 1: Install the automatic instrumentation

Install it into a shared directory, so the application's service user can read it.

The installer verifies the downloaded release with the GitHub CLI, which must be signed in. Sign in once with gh auth login, or provide a GitHub token in the GH_TOKEN environment variable:

curl -sSfL -o otel-dotnet-auto-install.sh \
  https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/latest/download/otel-dotnet-auto-install.sh

sudo GH_TOKEN="$GH_TOKEN" OTEL_DOTNET_AUTO_HOME=/opt/otel-dotnet-auto sh ./otel-dotnet-auto-install.sh
sudo chmod +x /opt/otel-dotnet-auto/instrument.sh

Installing without verification: If you can't install or sign in to the GitHub CLI on the VM, add SKIP_RELEASE_VERIFICATION=true to the install command. The installer then prints a warning and installs the release without verifying it:sudo SKIP_RELEASE_VERIFICATION=true OTEL_DOTNET_AUTO_HOME=/opt/otel-dotnet-auto sh ./otel-dotnet-auto-install.sh

The script detects the CPU architecture and C library (glibc or musl) and downloads the matching build. Check which profiler folder was installed:

ls /opt/otel-dotnet-auto
# linux-x64 (glibc, x86_64), linux-arm64, linux-musl-x64 or linux-musl-arm64

Step 2: Configure and start the application

Option A: from a shell

instrument.sh sets all the profiler variables (CORECLR_*, DOTNET_*) for the current shell:

export OTEL_DOTNET_AUTO_HOME=/opt/otel-dotnet-auto
export OTEL_SERVICE_NAME=orders-api
export OTEL_EXPORTER_OTLP_ENDPOINT=http://<KUBESENSE_INGEST_HOST>:33443
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_RESOURCE_ATTRIBUTES=kubesense.cluster=<CLUSTER_NAME>,kubesense.env_type=legacy
export OTEL_METRICS_EXPORTER=none
export OTEL_LOGS_EXPORTER=none

. /opt/otel-dotnet-auto/instrument.sh
dotnet /srv/orders-api/OrdersApi.dll

Add the variables to the service unit, for example /etc/systemd/system/orders-api.service. Use the profiler folder you saw in Step 1. The example below is for linux-x64:

[Service]
ExecStart=/usr/bin/dotnet /srv/orders-api/OrdersApi.dll

# OpenTelemetry .NET automatic instrumentation
Environment=OTEL_DOTNET_AUTO_HOME=/opt/otel-dotnet-auto
Environment=CORECLR_ENABLE_PROFILING=1
Environment=CORECLR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318}
Environment=CORECLR_PROFILER_PATH=/opt/otel-dotnet-auto/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so
Environment=DOTNET_STARTUP_HOOKS=/opt/otel-dotnet-auto/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll

# Exporter settings
Environment=OTEL_SERVICE_NAME=orders-api
Environment=OTEL_EXPORTER_OTLP_ENDPOINT=http://<KUBESENSE_INGEST_HOST>:33443
Environment=OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
Environment=OTEL_RESOURCE_ATTRIBUTES=kubesense.cluster=<CLUSTER_NAME>,kubesense.env_type=legacy
Environment=OTEL_METRICS_EXPORTER=none
Environment=OTEL_LOGS_EXPORTER=none

Reload and restart the service:

sudo systemctl daemon-reload
sudo systemctl restart orders-api

warning: Set the profiler variables only on the services you want to instrument, never globally (for example in /etc/environment). Global settings instrument every .NET process on the VM.

Step 3: Verify

Generate some traffic, then open APM → Traces in KubeSense and filter by your service name. Instrumentation logs are written to /var/log/opentelemetry/dotnet. Set OTEL_LOG_LEVEL=debug temporarily for more detail.

Troubleshooting

SymptomCheck
No traces and no instrumentation logsCORECLR_PROFILER_PATH points to a file that doesn't exist. Use the folder installed in Step 1
Export errors in the instrumentation logsCheck that the VM can reach <KUBESENSE_INGEST_HOST>:33443, and that trace ingestion is enabled on KubeSense
Permission errors on startThe service user can't read /opt/otel-dotnet-auto. Check its permissions
Traces appear under the wrong clusterCheck kubesense.cluster and kubesense.env_type in OTEL_RESOURCE_ATTRIBUTES