Skip to content

Commit a786b35

Browse files
authored
Add sdk-only support for opentelemetry-autoinstrumentation (#965)
# Description [CX-44042](https://coralogix.atlassian.net/browse/CX-44042) [CX-44042]: https://coralogix.atlassian.net/browse/CX-44042?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ Signed-off-by: Israel Blancas <iblancasa@gmail.com>
1 parent b574f11 commit a786b35

12 files changed

Lines changed: 214 additions & 62 deletions

File tree

.github/workflows/otel-integration-e2e-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
run: |
5959
cd ./otel-integration/k8s-helm/e2e-test/
6060
go clean -testcache
61-
go test -v -run='^TestE2E.*' -skip='^(TestE2E_TargetAllocator_ServiceMonitorMetrics|TestE2E_InstrumentationWebhookNoCRDs)$' $(go list ./... | rg -v '/supervisor$')
61+
go test -v -run='^TestE2E.*' -skip='^(TestE2E_TargetAllocator_ServiceMonitorMetrics|TestE2E_InstrumentationWebhookNoCRDs|TestE2E_SDKInjection)$' $(go list ./... | rg -v '/supervisor$')
6262
- name: Pods logs
6363
if: failure()
6464
run: |

otel-integration/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## OpenTelemetry-Integration
44

5+
### v0.0.327 / 2026-07-13
6+
7+
- [Chore] Bump OpenTelemetry Operator chart dependency to 0.119.0
8+
- [Feat] Add SDK-only injection support for applications with manual instrumentation
9+
510
### v0.0.326 / 2026-07-08
611

712
- [Chore] Bump chart dependency to opentelemetry-collector 0.135.0

otel-integration/k8s-helm/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: v2
22
name: otel-integration
33
description: OpenTelemetry Integration
4-
version: 0.0.326
4+
version: 0.0.327
55
keywords:
66
- OpenTelemetry Collector
77
- OpenTelemetry Agent
@@ -16,7 +16,7 @@ dependencies:
1616
condition: opentelemetry-agent.enabled
1717
- name: opentelemetry-operator
1818
alias: opentelemetry-autoinstrumentation
19-
version: "0.115.1"
19+
version: "0.119.0"
2020
repository: https://open-telemetry.github.io/opentelemetry-helm-charts
2121
condition: opentelemetry-autoinstrumentation.enabled
2222
- name: opentelemetry-collector

otel-integration/k8s-helm/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,34 @@ Supported annotations:
205205
instrumentation.opentelemetry.io/inject-java: "true"
206206
instrumentation.opentelemetry.io/inject-python: "true"
207207
instrumentation.opentelemetry.io/inject-dotnet: "true"
208+
instrumentation.opentelemetry.io/inject-sdk: "true"
208209
```
209210
210211
Java and .NET use OTLP/gRPC to `http://$(OTEL_NODE_IP):4317`. Python uses OTLP HTTP/protobuf to `http://$(OTEL_NODE_IP):4318`.
211212

213+
#### SDK-only Injection
214+
215+
The `inject-sdk` annotation enables SDK-only injection mode for applications that are already manually instrumented or cannot be auto-instrumented with language-specific agents. This mode injects only OpenTelemetry SDK environment variables without adding init containers or modifying the application binary.
216+
217+
SDK-only injection uses the common environment variables configured in `opentelemetry-autoinstrumentation.manager.config.instrumentations.spec.env` along with the exporter and sampler configuration from `spec.exporter` and `spec.sampler` in the Helm values.
218+
219+
Use this mode when:
220+
- Your application is already instrumented with OpenTelemetry SDK
221+
- You want centralized configuration of SDK behavior via Kubernetes annotations
222+
- Language-specific auto-instrumentation is not available or compatible
223+
224+
Example pod annotation:
225+
226+
```yaml
227+
metadata:
228+
annotations:
229+
instrumentation.opentelemetry.io/inject-sdk: "true"
230+
```
231+
232+
The injected environment variables will configure the SDK to send telemetry to the `opentelemetry-agent` DaemonSet on the same node using the endpoint from `spec.exporter.endpoint` (default: `http://$(OTEL_NODE_IP):4317`).
233+
234+
For more details, see the [OpenTelemetry Operator SDK-only documentation](https://github.com/open-telemetry/opentelemetry-operator/blob/main/docs/auto-instrumentation/languages/sdk-only.md).
235+
212236
> [!IMPORTANT]
213237
>
214238
> Do not enable `opentelemetry-autoinstrumentation` in a cluster that already has another OpenTelemetry Operator webhook installed, unless the webhook names and selectors are configured to avoid collisions.

otel-integration/k8s-helm/e2e-test/instrumentation_webhook_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,3 +494,110 @@ func eventually(timeout, interval time.Duration, check func() (bool, error)) err
494494
}
495495
return fmt.Errorf("condition not met within %s", timeout)
496496
}
497+
498+
func TestE2E_SDKInjection(t *testing.T) {
499+
kubeconfigPath := testKubeConfig
500+
if kubeConfigFromEnv := os.Getenv(kubeConfigEnvVar); kubeConfigFromEnv != "" {
501+
kubeconfigPath = kubeConfigFromEnv
502+
}
503+
504+
k8sClient, err := xk8stest.NewK8sClient(kubeconfigPath)
505+
require.NoError(t, err)
506+
507+
require.NoError(t, waitForInstrumentationWebhookManager(k8sClient))
508+
509+
ns := fmt.Sprintf("sdk-injection-e2e-%s", uuid.NewString()[:8])
510+
nsObj := &unstructured.Unstructured{Object: map[string]any{
511+
"apiVersion": "v1",
512+
"kind": "Namespace",
513+
"metadata": map[string]any{
514+
"name": ns,
515+
},
516+
}}
517+
_, err = k8sClient.DynamicClient.Resource(corev1.SchemeGroupVersion.WithResource("namespaces")).Create(context.Background(), nsObj, metav1.CreateOptions{})
518+
require.NoError(t, err)
519+
t.Cleanup(func() {
520+
_ = xk8stest.DeleteObject(k8sClient, nsObj)
521+
})
522+
523+
tracesConsumer := new(consumertest.TracesSink)
524+
shutdownSink := StartUpSinks(t, ReceiverSinks{
525+
Traces: &TraceSinkConfig{
526+
Consumer: tracesConsumer,
527+
Ports: &ReceiverPorts{
528+
Grpc: 4321,
529+
},
530+
},
531+
})
532+
defer shutdownSink()
533+
534+
tests := []struct {
535+
name string
536+
image string
537+
port int
538+
path string
539+
command []string
540+
expectedEnvs []string
541+
noExpectedInit bool
542+
}{
543+
{
544+
name: "sdk-only-python",
545+
image: "ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-python:main",
546+
port: 8080,
547+
path: "/",
548+
expectedEnvs: []string{
549+
"OTEL_EXPORTER_OTLP_ENDPOINT",
550+
"OTEL_NODE_IP",
551+
"OTEL_TRACES_SAMPLER",
552+
"OTEL_LOGS_EXPORTER",
553+
},
554+
noExpectedInit: true,
555+
},
556+
{
557+
name: "sdk-only-java",
558+
image: "ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-java:main",
559+
port: 8080,
560+
path: "/",
561+
expectedEnvs: []string{
562+
"OTEL_EXPORTER_OTLP_ENDPOINT",
563+
"OTEL_NODE_IP",
564+
"OTEL_TRACES_SAMPLER",
565+
"OTEL_LOGS_EXPORTER",
566+
},
567+
noExpectedInit: true,
568+
},
569+
}
570+
571+
for _, tc := range tests {
572+
t.Run(tc.name, func(t *testing.T) {
573+
deployment := instrumentationWebhookDeployment(tc.name, ns, "", tc.image, tc.port, tc.path, tc.command, nil, "")
574+
created, err := k8sClient.DynamicClient.Resource(appsV1Deployments()).Namespace(ns).Create(context.Background(), deployment, metav1.CreateOptions{})
575+
require.NoError(t, err)
576+
t.Cleanup(func() {
577+
_ = xk8stest.DeleteObject(k8sClient, created)
578+
})
579+
580+
baselinePod := waitForDeploymentReadyPod(t, k8sClient, ns, created.GetName(), "")
581+
curlPod(t, k8sClient, ns, baselinePod.GetName(), tc.port, tc.path)
582+
requireNoTraceForPod(t, tracesConsumer, baselinePod.GetName(), 15*time.Second)
583+
584+
err = injectDeploymentInstrumentation(k8sClient, ns, created.GetName(), "instrumentation.opentelemetry.io/inject-sdk")
585+
require.NoError(t, err)
586+
587+
instrumentedPod := waitForDeploymentReadyPod(t, k8sClient, ns, created.GetName(), baselinePod.GetName())
588+
589+
if tc.noExpectedInit {
590+
initContainers, found, _ := unstructured.NestedSlice(instrumentedPod.Object, "spec", "initContainers")
591+
if found && len(initContainers) > 0 {
592+
t.Errorf("SDK-only injection should not add init containers, but found %d init containers", len(initContainers))
593+
}
594+
}
595+
596+
for _, envName := range tc.expectedEnvs {
597+
require.Truef(t, containerHasEnv(instrumentedPod, "app", envName), "expected env %q on container 'app' in pod %s", envName, tc.name)
598+
}
599+
600+
t.Logf("SDK-only injection verified for %s - environment variables injected without init containers", tc.name)
601+
})
602+
}
603+
}

otel-integration/k8s-helm/e2e-test/run-all.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ TestE2E_DeltaToCumulativePreset|linux|component=agent-collector||./values.yaml .
9191
TestE2E_SpanMetricsConnector|linux|component=agent-collector||./values.yaml ./e2e-test/testdata/values-e2e-span-metrics.yaml
9292
TestE2E_SpanSanitization|linux|component=agent-collector||./values.yaml ./e2e-test/testdata/values-e2e-test.yaml
9393
TestE2E_InstrumentationWebhookNoCRDs|linux|component=agent-collector||./values.yaml ./e2e-test/testdata/values-e2e-test.yaml ./e2e-test/testdata/values-e2e-instrumentation-webhook.yaml
94+
TestE2E_SDKInjection|linux|component=agent-collector||./values.yaml ./e2e-test/testdata/values-e2e-test.yaml ./e2e-test/testdata/values-e2e-sdk-injection.yaml
9495
EOF
9596
}
9697

@@ -763,7 +764,7 @@ run_workflow_mode() {
763764

764765
log_test "========================================"
765766
# Base package only; supervisor tests require different chart values and run below.
766-
log_test "Workflow Mode (Base): go test -v -run='^TestE2E.*' -skip='^(TestE2E_TargetAllocator_ServiceMonitorMetrics|TestE2E_InstrumentationWebhookNoCRDs)$' ."
767+
log_test "Workflow Mode (Base): go test -v -run='^TestE2E.*' -skip='^(TestE2E_TargetAllocator_ServiceMonitorMetrics|TestE2E_InstrumentationWebhookNoCRDs|TestE2E_SDKInjection)$' ."
767768
log_test "========================================"
768769

769770
export KUBECONFIG="${KUBECONFIG_PATH}"
@@ -776,7 +777,7 @@ run_workflow_mode() {
776777
(
777778
cd "${E2E_TEST_DIR}" || exit 1
778779
go clean -testcache
779-
go test -v -run='^TestE2E.*' -skip='^(TestE2E_TargetAllocator_ServiceMonitorMetrics|TestE2E_InstrumentationWebhookNoCRDs)$' $(go list ./... | rg -v '/supervisor$')
780+
go test -v -run='^TestE2E.*' -skip='^(TestE2E_TargetAllocator_ServiceMonitorMetrics|TestE2E_InstrumentationWebhookNoCRDs|TestE2E_SDKInjection)$' $(go list ./... | rg -v '/supervisor$')
780781
)
781782
local exit_code=$?
782783
local workflow_end_time
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
opentelemetry-autoinstrumentation:
2+
enabled: true
3+
4+
opentelemetry-agent:
5+
config:
6+
service:
7+
pipelines:
8+
traces:
9+
exporters:
10+
- otlp/traces
11+
- debug

otel-integration/k8s-helm/tests/golden/ebpf-profiler.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,14 @@ data:
184184
timeout: 10s
185185
logs:
186186
headers:
187-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
187+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
188188
metrics:
189189
headers:
190-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
190+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
191191
private_key: ${env:CORALOGIX_PRIVATE_KEY}
192192
profiles:
193193
headers:
194-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
194+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
195195
x-coralogix-ingress: otlp/v1.10.0
196196
sending_queue:
197197
batch:
@@ -213,13 +213,13 @@ data:
213213
timeout: 30s
214214
traces:
215215
headers:
216-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
216+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
217217
coralogix/resource_catalog:
218218
application_name: resource
219219
domain: eu2.coralogix.com
220220
logs:
221221
headers:
222-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
222+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
223223
x-coralogix-ingress: metadata-as-otlp-logs/v1
224224
private_key: ${CORALOGIX_PRIVATE_KEY}
225225
sending_queue:
@@ -1052,14 +1052,14 @@ data:
10521052
timeout: 10s
10531053
logs:
10541054
headers:
1055-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
1055+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
10561056
metrics:
10571057
headers:
1058-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
1058+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
10591059
private_key: ${env:CORALOGIX_PRIVATE_KEY}
10601060
profiles:
10611061
headers:
1062-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
1062+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
10631063
x-coralogix-ingress: otlp/v1.10.0
10641064
sending_queue:
10651065
batch:
@@ -1081,13 +1081,13 @@ data:
10811081
timeout: 30s
10821082
traces:
10831083
headers:
1084-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
1084+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
10851085
coralogix/resource_catalog:
10861086
application_name: resource
10871087
domain: eu2.coralogix.com
10881088
logs:
10891089
headers:
1090-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
1090+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
10911091
x-coralogix-ingress: metadata-as-otlp-logs/v1
10921092
private_key: ${CORALOGIX_PRIVATE_KEY}
10931093
sending_queue:
@@ -2047,7 +2047,7 @@ spec:
20472047
template:
20482048
metadata:
20492049
annotations:
2050-
checksum/config: 3f8ed465f594b374cdbfe68a6a326e4c4bd8aea38b64e7afeea27df960035045
2050+
checksum/config: 65c7e661bf3813231ce7f4c02bedbb566baa6747ae38ee5956b6b1ddfa84d823
20512051

20522052
labels:
20532053
app.kubernetes.io/name: opentelemetry-agent
@@ -2234,7 +2234,7 @@ spec:
22342234
template:
22352235
metadata:
22362236
annotations:
2237-
checksum/config: f86e349cad25d9f05ed32dd5be6b649d1a51bfc2179f4665a6dfbaef2ab07cac
2237+
checksum/config: e9f5093348aca9a0b280227c5fe99b3d2e460aab617748e6bc4b248aef5e53f7
22382238

22392239
labels:
22402240
app.kubernetes.io/name: opentelemetry-cluster-collector

otel-integration/k8s-helm/tests/golden/eks-fargate.yaml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ data:
5555
timeout: 10s
5656
logs:
5757
headers:
58-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
58+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
5959
metrics:
6060
headers:
61-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
61+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
6262
private_key: ${env:CORALOGIX_PRIVATE_KEY}
6363
profiles:
6464
headers:
65-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
65+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
6666
x-coralogix-ingress: otlp/v1.10.0
6767
sending_queue:
6868
batch:
@@ -87,7 +87,7 @@ data:
8787
timeout: 30s
8888
traces:
8989
headers:
90-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
90+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
9191
debug: {}
9292
extensions:
9393
health_check:
@@ -350,14 +350,14 @@ data:
350350
timeout: 10s
351351
logs:
352352
headers:
353-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
353+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
354354
metrics:
355355
headers:
356-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
356+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
357357
private_key: ${env:CORALOGIX_PRIVATE_KEY}
358358
profiles:
359359
headers:
360-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
360+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
361361
x-coralogix-ingress: otlp/v1.10.0
362362
sending_queue:
363363
batch:
@@ -382,7 +382,7 @@ data:
382382
timeout: 30s
383383
traces:
384384
headers:
385-
X-Coralogix-Distribution: helm-otel-integration/0.0.326
385+
X-Coralogix-Distribution: helm-otel-integration/0.0.327
386386
debug: {}
387387
extensions:
388388
health_check:
@@ -845,7 +845,7 @@ spec:
845845
template:
846846
metadata:
847847
annotations:
848-
checksum/config: b4938f2651addfd373b3d2df3b4f7c1ca0946414be8bb10ca1620b86077ac65b
848+
checksum/config: 51c0c23316f8f6b22e5a9c92cecdcdd7178e82199d8a48e2bcdcf53956501496
849849

850850
labels:
851851
app.kubernetes.io/name: opentelemetry-agent-eks-fargate-monitoring
@@ -960,7 +960,7 @@ spec:
960960
template:
961961
metadata:
962962
annotations:
963-
checksum/config: 7cf19fabd13bfdd4838efa71683b6eb30f4429d56270b3f3fe3f23cf3a9ccc56
963+
checksum/config: af455766d1210019411545cffae36334aed795289441f1063fc8e1d89aeeb983
964964

965965
labels:
966966
app.kubernetes.io/name: opentelemetry-agent-eks-fargate

0 commit comments

Comments
 (0)