Skip to content

Commit 73f9833

Browse files
eedugonmdbirnstiehltrentm
authored
K8s auto-instrumentation details and example (Node.js) (#59)
* instrumenting-nodejs.md added --------- Co-authored-by: Mike Birnstiehl <[email protected]> Co-authored-by: Trent Mick <[email protected]>
1 parent 4133780 commit 73f9833

File tree

2 files changed

+162
-4
lines changed

2 files changed

+162
-4
lines changed

docs/kubernetes/operator/instrumenting-applications.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ For details on instrumenting specific languages, refer to:
143143

144144
- [Instrumenting Java](./instrumenting-java.md)
145145
- [Instrumenting Python](./instrumenting-python.md)
146+
- [Instrumenting Node.js](./instrumenting-nodejs.md)
146147
<!-- - [Instrumenting Dotnet](./instrumenting-dotnet.md) -->
147148

148149
### Namespace based annotations example
@@ -170,13 +171,13 @@ Ensure that the `init container`, `volume`, and `environment variables` describe
170171
The OpenTelemetry Operator automates the process of instrumenting applications by injecting the necessary libraries and configuration into the application Pods.
171172
The process may vary slightly depending on the language, but it generally involves the following steps:
172173
173-
- **Adding an init container**:
174+
- **Creating a shared volume**:
174175
175-
The operator adds an init container into the Pod. This container is responsible for copying the OpenTelemetry instrumentation library and make it accessible to the main application container.
176+
The operator declares an `emptyDir` shared volume within the Pod, and mounts it the app container and a new init container. This volume serves as the medium for sharing the instrumentation library between the new init container and the application container.
176177
177-
- **Creating a shared volume**:
178+
- **Adding an init container**:
178179
179-
The operator creates an `emptyDir` shared volume within the Pod, and mounts it in both containers. This volume serves as the medium for sharing the instrumentation library between the init container and the application container.
180+
The operator adds an init container into the Pod. This container is responsible for copying the OpenTelemetry instrumentation library to the shared volume.
180181
181182
- **Configuring the main container**:
182183
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Instrumenting Node.js applications with EDOT SDKs on Kubernetes
2+
3+
This document focuses on instrumenting Node.js applications on Kubernetes, using the OpenTelemetry Operator, the Elastic Distribution of OpenTelemetry (EDOT) Collectors, and the [EDOT Node.js](https://github.com/elastic/elastic-otel-nodejs) SDK.
4+
5+
- For general knowledge about the EDOT Node.js SDK, refer to the [getting started guide](https://github.com/elastic/elastic-otel-node/blob/main/packages/opentelemetry-node/docs/get-started.md) and [configuration](https://github.com/elastic/elastic-otel-node/blob/main/packages/opentelemetry-node/docs/configure.md).
6+
- For Node.js auto-instrumentation specifics, refer to [OpenTelemetry Operator Node.js auto-instrumentation](https://opentelemetry.io/docs/kubernetes/operator/automatic/#nodejs).
7+
- For general information about instrumenting applications on kubernetes, refer to [instrumenting applications](./instrumenting-applications.md).
8+
9+
## Instrument a Node.js app with EDOT Node.js SDK on Kubernetes
10+
11+
<!--
12+
Useful links:
13+
- Example: https://github.com/elastic/elastic-otel-node/tree/main/examples/otel-operator/ documented at https://github.com/elastic/elastic-otel-node/blob/main/DEVELOPMENT.md#testing-k8s-auto-instrumentation-with-otel-operator
14+
(not user friendly, but we could use it in the future if we want to add a proper example here)
15+
-->
16+
17+
In this example, you'll learn how to:
18+
19+
- Enable auto-instrumentation of a Node.js application using one of the following supported methods:
20+
- Adding an annotation to the deployment Pods.
21+
- Adding an annotation to the namespace.
22+
- Verify that auto-instrumentation libraries are injected and configured correctly.
23+
- Confirm data is flowing to **Kibana Observability**.
24+
25+
For this example, we assume the application you're instrumenting is a deployment named `nodejs-app` running in the `nodejs-ns` namespace.
26+
27+
1. Ensure you have successfully [installed the OpenTelemetry Operator](./README.md), and confirm that the following `Instrumentation` object exists in the system:
28+
29+
```bash
30+
$ kubectl get instrumentation -n opentelemetry-operator-system
31+
NAME AGE ENDPOINT
32+
elastic-instrumentation 107s http://opentelemetry-kube-stack-daemon-collector.opentelemetry-operator-system.svc.cluster.local:4318
33+
```
34+
> [!NOTE]
35+
> If your `Instrumentation` object has a different name or is created in a different namespace, you will have to adapt the annotation value in the next step.
36+
37+
2. Enable auto-instrumentation of your Node.js application using one of the following methods:
38+
39+
- Edit your application workload definition and include the annotation under `spec.template.metadata.annotations`:
40+
41+
```yaml
42+
kind: Deployment
43+
metadata:
44+
name: nodejs-app
45+
namespace: nodejs-ns
46+
spec:
47+
...
48+
template:
49+
metadata:
50+
...
51+
annotations:
52+
instrumentation.opentelemetry.io/inject-nodejs: opentelemetry-operator-system/elastic-instrumentation
53+
...
54+
```
55+
56+
- Alternatively, add the annotation at namespace level to apply auto-instrumentation in all Pods of the namespace:
57+
58+
```bash
59+
kubectl annotate namespace nodejs-ns instrumentation.opentelemetry.io/inject-nodejs=opentelemetry-operator-system/elastic-instrumentation
60+
```
61+
62+
3. Restart application
63+
64+
Once the annotation has been set, restart the application to create new Pods and inject the instrumentation libraries:
65+
66+
```bash
67+
kubectl rollout restart deployment nodejs-app -n nodejs-ns
68+
```
69+
70+
4. Verify the [auto-instrumentation resources](./instrumenting-applications.md#how-auto-instrumentation-works) are injected in the Pods:
71+
72+
Run a `kubectl describe` of one of your application Pods and check:
73+
74+
- There should be an init container named `opentelemetry-auto-instrumentation-nodejs` in the Pod. For example:
75+
76+
```bash
77+
$ kubectl describe pod nodejs-app-8d84c47b8-8h5z2 -n nodejs-ns
78+
Name: nodejs-app-8d84c47b8-8h5z2
79+
Namespace: nodejs-ns
80+
...
81+
...
82+
Init Containers:
83+
opentelemetry-auto-instrumentation-nodejs:
84+
Container ID: containerd://cbf67d7ca1bd62c25614b905a11e81405bed6fd215f2df21f84b90fd0279230b
85+
Image: docker.elastic.co/observability/elastic-otel-node:0.5.0
86+
Command:
87+
cp
88+
-r
89+
/autoinstrumentation/.
90+
/otel-auto-instrumentation-nodejs
91+
State: Terminated
92+
Reason: Completed
93+
Exit Code: 0
94+
Started: Wed, 13 Nov 2024 15:47:02 +0100
95+
Finished: Wed, 13 Nov 2024 15:47:03 +0100
96+
Ready: True
97+
Restart Count: 0
98+
Environment: <none>
99+
Mounts:
100+
/otel-auto-instrumentation-nodejs from opentelemetry-auto-instrumentation-nodejs (rw)
101+
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-swhn5 (ro)
102+
```
103+
104+
- The main container of the deployment loads the SDK through the `NODE_OPTIONS` environment variable:
105+
106+
```bash
107+
...
108+
Containers:
109+
nodejs-app:
110+
Environment:
111+
...
112+
NODE_OPTIONS: --require /otel-auto-instrumentation-nodejs/autoinstrumentation.js
113+
OTEL_SERVICE_NAME: nodejs-app
114+
OTEL_EXPORTER_OTLP_ENDPOINT: http://opentelemetry-kube-stack-daemon-collector.opentelemetry-operator-system.svc.cluster.local:4318
115+
...
116+
```
117+
118+
Ensure the environment variable `OTEL_EXPORTER_OTLP_ENDPOINT` points to a valid endpoint and there's network communication between the Pod and the endpoint.
119+
120+
- The Pod has an `EmptyDir` volume named `opentelemetry-auto-instrumentation-nodejs` mounted in both the main and the init containers in path `/otel-auto-instrumentation-nodejs`.
121+
122+
```bash
123+
Init Containers:
124+
opentelemetry-auto-instrumentation-nodejs:
125+
...
126+
Mounts:
127+
/otel-auto-instrumentation-nodejs from opentelemetry-auto-instrumentation-nodejs (rw)
128+
Containers:
129+
nodejs-app:
130+
...
131+
Mounts:
132+
/otel-auto-instrumentation-nodejs from opentelemetry-auto-instrumentation-nodejs (rw)
133+
...
134+
Volumes:
135+
...
136+
opentelemetry-auto-instrumentation-nodejs:
137+
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
138+
```
139+
140+
5. Confirm data is flowing to **Kibana**:
141+
142+
- Open **Observability** -> **Applications** -> **Service inventory**, and determine if:
143+
- The application appears in the list of services (`nodejs-app` in the example).
144+
- The application shows transactions and metrics.
145+
146+
> [!TIP]
147+
> You may need to generate traffic to your application to see spans and metrics.
148+
149+
- For application container logs, open **Kibana Discover** and filter for your Pods' logs. In the provided example, we could filter for them with either of the following:
150+
- `k8s.deployment.name: "nodejs-app"` (**adapt the query filter to your use case**)
151+
- `k8s.pod.name: nodejs-app*` (**adapt the query filter to your use case**)
152+
153+
Note that the container logs are not provided by the instrumentation library, but by the DaemonSet collector deployed as part of the [operator installation](./README.md).
154+
155+
## Troubleshooting
156+
157+
- Refer to [troubleshoot auto-instrumentation](./troubleshoot-auto-instrumentation.md) for further analysis.

0 commit comments

Comments
 (0)