---
title: Local SDK Injection
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: Docs > APM > Tracing Guides > Local SDK Injection
---

# Local SDK Injection

## Overview{% #overview %}

Use the [Datadog Admission Controller](https://docs.datadoghq.com/containers/cluster_agent/admission_controller/?tab=datadogoperator) to inject APM tracer libraries into Kubernetes workloads using pod-level annotations and labels.

The Datadog Agent uses the Kubernetes Admission Controller to intercept pod creation requests and inject an init container that installs the tracer library before the application starts. This method provides a manual, pod-level alternative to [Single Step Instrumentation (SSI)](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/single-step-apm/kubernetes/?tab=agentv764recommended), which uses Helm or the Datadog Operator to configure instrumentation across your cluster.

Use this guide if:

- You want to test library injection on a small number of services before rolling out SSI cluster-wide.
- You prefer a lighter-weight integration method.
- You want to control instrumentation directly in your pod specs, rather than through centralized configuration files.

## Requirements{% #requirements %}

- Kubernetes v1.14+
- [Datadog Cluster Agent](https://docs.datadoghq.com/containers/kubernetes/installation/?tab=helm):
  - v7.40+ for Java, Python, and Node.js
  - v7.44+ for .NET and Ruby
- Datadog Admission Controller enabled (enabled by default in Helm chart v2.35.0+ and Operator v1.0.0+)

**Note:** Starting in v7.73.0, the Admission Controller does not inject into pods in the `kube-system` namespace or the namespace where the Cluster Agent is deployed.

### Step 1: Enable pod mutation{% #step-1-enable-pod-mutation %}

By default, the Datadog Admission controller only mutates pods with the label `admission.datadoghq.com/enabled: "true"`:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    # (...)
spec:
  template:
    metadata:
      labels:
        admission.datadoghq.com/enabled: "true"
```

Alternatively, to mutate all pods without requiring the label, do one of the following:

{% tab title="Datadog Operator" %}
Update your `datadog-agent.yaml` to set `features.admissionController.mutateUnlabelled` to `true`.

```yaml
apiVersion: datadoghq.com/v2alpha1
kind: DatadogAgent
metadata:
  name: datadog
spec:
  #(...)
  features:
    admissionController:
      mutateUnlabelled: true
```

After making your changes, apply the new configuration by using the following command:

```shell
kubectl apply -n $DD_NAMESPACE -f datadog-agent.yaml
```

{% /tab %}

{% tab title="Helm" %}
Update your `datadog-values.yaml` to set `clusterAgent.admissionController.mutateUnlabelled` to `true`.

```yaml
clusterAgent:
  admissionController:
    mutateUnlabelled: true
```

After making your changes, upgrade your Datadog Helm chart using the following command:

```shell
helm upgrade -f datadog-values.yaml <RELEASE NAME> datadog/datadog
```

{% /tab %}

After setting the pod label or updating `mutateUnlabelled`, the Admission Controller mutates newly created pods to add APM connectivity configuration. For more details, see the [Datadog Admission Controller documentation](https://docs.datadoghq.com/containers/cluster_agent/admission_controller/?tab=datadogoperator).

### Step 2: Annotate pods for library injection{% #step-2-annotate-pods-for-library-injection %}

#### Specify tracer language and version{% #specify-tracer-language-and-version %}

Use the following pod annotations to specify which language SDK to inject and which version to use:

| Language | Pod annotation                                                        |
| -------- | --------------------------------------------------------------------- |
| Java     | `admission.datadoghq.com/java-lib.version: "<CONTAINER IMAGE TAG>"`   |
| Node.js  | `admission.datadoghq.com/js-lib.version: "<CONTAINER IMAGE TAG>"`     |
| Python   | `admission.datadoghq.com/python-lib.version: "<CONTAINER IMAGE TAG>"` |
| .NET     | `admission.datadoghq.com/dotnet-lib.version: "<CONTAINER IMAGE TAG>"` |
| Ruby     | `admission.datadoghq.com/ruby-lib.version: "<CONTAINER IMAGE TAG>"`   |

Replace `<CONTAINER IMAGE TAG>` with the appropriate value.

For example:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    # (...)
spec:
  template:
    metadata:
      labels:
        admission.datadoghq.com/enabled: "true" 
      annotations:
        admission.datadoghq.com/java-lib.version: "v1.12.0"
    spec:
      containers:
        - # (...)
```

To view available library versions, see the tracer repositories for each language:

- [Java](https://github.com/DataDog/dd-trace-java/releases)
- [Node.js](https://github.com/DataDog/dd-trace-js/releases)
- [Python](https://github.com/DataDog/dd-trace-py/releases)
- [.NET](https://github.com/DataDog/dd-trace-dotnet/releases)
- [Ruby](https://github.com/DataDog/dd-trace-rb/releases)
- [PHP](https://github.com/DataDog/dd-trace-php/releases)

**Note:** If a container already includes a manually installed tracer, the injected version takes precedence at runtime.

#### Add Unified Service Tags{% #add-unified-service-tags %}

Use Unified Service Tagging (UST) to apply consistent tags across traces, metrics, and logs, making it easier to navigate and correlate your observability data. The Admission Controller automatically adds the corresponding `DD_ENV`, `DD_SERVICE`, and `DD_VERSION` environment variables to match your pod labels.

```yaml
    metadata:
      labels:
        admission.datadoghq.com/enabled: "true" 
        tags.datadoghq.com/env: "<ENV>"
        tags.datadoghq.com/service: "<SERVICE>"
        tags.datadoghq.com/version: "<VERSION>" 
      annotations:
        admission.datadoghq.com/java-lib.version: "v1.12.0"
```

See [Unified Service Tagging](https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging/) for more information.

### Step 3: Apply your changes and verify injection{% #step-3-apply-your-changes-and-verify-injection %}

After adding the required pod metadata to your manifest, apply the change in Kubernetes:

```
kubectl apply -f my-deployment.yaml
```

As Kubernetes recreates your pods, they trigger the Admission Controller for injection. When injection is successful, the pod includes two `initContainers` named `datadog-init-apm-inject` and `datadog-lib-<LANGUAGE>-init` for your specified tracer language and version:

{% image
   source="https://datadog-docs.imgix.net/images/tracing/trace_collection/k8s-local-sdk-injection.77f1ff77be228fe1fcd65fb313cfbb57.png?auto=format"
   alt="Pod details in Datadog with `initContainers` listed" /%}

Alternatively, confirm injection and the added environment variables on your pod using:

```
kubectl describe pod <pod-name>
```

You should also see trace data in the [APM](https://app.datadoghq.com/apm/traces) UI shortly after startup.
