diff --git a/docs/kubernetes/operator/instrumenting-applications.md b/docs/kubernetes/operator/instrumenting-applications.md index ba815b5a..deda2126 100644 --- a/docs/kubernetes/operator/instrumenting-applications.md +++ b/docs/kubernetes/operator/instrumenting-applications.md @@ -143,6 +143,7 @@ For details on instrumenting specific languages, refer to: - [Instrumenting Java](./instrumenting-java.md) - [Instrumenting Python](./instrumenting-python.md) +- [Instrumenting Node.js](./instrumenting-nodejs.md) ### Namespace based annotations example @@ -170,13 +171,13 @@ Ensure that the `init container`, `volume`, and `environment variables` describe The OpenTelemetry Operator automates the process of instrumenting applications by injecting the necessary libraries and configuration into the application Pods. The process may vary slightly depending on the language, but it generally involves the following steps: -- **Adding an init container**: +- **Creating a shared volume**: - 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. + 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. -- **Creating a shared volume**: +- **Adding an init container**: - 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. + The operator adds an init container into the Pod. This container is responsible for copying the OpenTelemetry instrumentation library to the shared volume. - **Configuring the main container**: diff --git a/docs/kubernetes/operator/instrumenting-nodejs.md b/docs/kubernetes/operator/instrumenting-nodejs.md new file mode 100644 index 00000000..ce5bd137 --- /dev/null +++ b/docs/kubernetes/operator/instrumenting-nodejs.md @@ -0,0 +1,157 @@ +# Instrumenting Node.js applications with EDOT SDKs on Kubernetes + +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. + +- 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). +- For Node.js auto-instrumentation specifics, refer to [OpenTelemetry Operator Node.js auto-instrumentation](https://opentelemetry.io/docs/kubernetes/operator/automatic/#nodejs). +- For general information about instrumenting applications on kubernetes, refer to [instrumenting applications](./instrumenting-applications.md). + +## Instrument a Node.js app with EDOT Node.js SDK on Kubernetes + + + +In this example, you'll learn how to: + +- Enable auto-instrumentation of a Node.js application using one of the following supported methods: + - Adding an annotation to the deployment Pods. + - Adding an annotation to the namespace. +- Verify that auto-instrumentation libraries are injected and configured correctly. +- Confirm data is flowing to **Kibana Observability**. + +For this example, we assume the application you're instrumenting is a deployment named `nodejs-app` running in the `nodejs-ns` namespace. + +1. Ensure you have successfully [installed the OpenTelemetry Operator](./README.md), and confirm that the following `Instrumentation` object exists in the system: + + ```bash + $ kubectl get instrumentation -n opentelemetry-operator-system + NAME AGE ENDPOINT + elastic-instrumentation 107s http://opentelemetry-kube-stack-daemon-collector.opentelemetry-operator-system.svc.cluster.local:4318 + ``` + > [!NOTE] + > 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. + +2. Enable auto-instrumentation of your Node.js application using one of the following methods: + + - Edit your application workload definition and include the annotation under `spec.template.metadata.annotations`: + + ```yaml + kind: Deployment + metadata: + name: nodejs-app + namespace: nodejs-ns + spec: + ... + template: + metadata: + ... + annotations: + instrumentation.opentelemetry.io/inject-nodejs: opentelemetry-operator-system/elastic-instrumentation + ... + ``` + + - Alternatively, add the annotation at namespace level to apply auto-instrumentation in all Pods of the namespace: + + ```bash + kubectl annotate namespace nodejs-ns instrumentation.opentelemetry.io/inject-nodejs=opentelemetry-operator-system/elastic-instrumentation + ``` + +3. Restart application + + Once the annotation has been set, restart the application to create new Pods and inject the instrumentation libraries: + + ```bash + kubectl rollout restart deployment nodejs-app -n nodejs-ns + ``` + +4. Verify the [auto-instrumentation resources](./instrumenting-applications.md#how-auto-instrumentation-works) are injected in the Pods: + + Run a `kubectl describe` of one of your application Pods and check: + + - There should be an init container named `opentelemetry-auto-instrumentation-nodejs` in the Pod. For example: + + ```bash + $ kubectl describe pod nodejs-app-8d84c47b8-8h5z2 -n nodejs-ns + Name: nodejs-app-8d84c47b8-8h5z2 + Namespace: nodejs-ns + ... + ... + Init Containers: + opentelemetry-auto-instrumentation-nodejs: + Container ID: containerd://cbf67d7ca1bd62c25614b905a11e81405bed6fd215f2df21f84b90fd0279230b + Image: docker.elastic.co/observability/elastic-otel-node:0.5.0 + Command: + cp + -r + /autoinstrumentation/. + /otel-auto-instrumentation-nodejs + State: Terminated + Reason: Completed + Exit Code: 0 + Started: Wed, 13 Nov 2024 15:47:02 +0100 + Finished: Wed, 13 Nov 2024 15:47:03 +0100 + Ready: True + Restart Count: 0 + Environment: + Mounts: + /otel-auto-instrumentation-nodejs from opentelemetry-auto-instrumentation-nodejs (rw) + /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-swhn5 (ro) + ``` + + - The main container of the deployment loads the SDK through the `NODE_OPTIONS` environment variable: + + ```bash + ... + Containers: + nodejs-app: + Environment: + ... + NODE_OPTIONS: --require /otel-auto-instrumentation-nodejs/autoinstrumentation.js + OTEL_SERVICE_NAME: nodejs-app + OTEL_EXPORTER_OTLP_ENDPOINT: http://opentelemetry-kube-stack-daemon-collector.opentelemetry-operator-system.svc.cluster.local:4318 + ... + ``` + + Ensure the environment variable `OTEL_EXPORTER_OTLP_ENDPOINT` points to a valid endpoint and there's network communication between the Pod and the endpoint. + + - 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`. + + ```bash + Init Containers: + opentelemetry-auto-instrumentation-nodejs: + ... + Mounts: + /otel-auto-instrumentation-nodejs from opentelemetry-auto-instrumentation-nodejs (rw) + Containers: + nodejs-app: + ... + Mounts: + /otel-auto-instrumentation-nodejs from opentelemetry-auto-instrumentation-nodejs (rw) + ... + Volumes: + ... + opentelemetry-auto-instrumentation-nodejs: + Type: EmptyDir (a temporary directory that shares a pod's lifetime) + ``` + +5. Confirm data is flowing to **Kibana**: + + - Open **Observability** -> **Applications** -> **Service inventory**, and determine if: + - The application appears in the list of services (`nodejs-app` in the example). + - The application shows transactions and metrics. + + > [!TIP] + > You may need to generate traffic to your application to see spans and metrics. + + - 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: + - `k8s.deployment.name: "nodejs-app"` (**adapt the query filter to your use case**) + - `k8s.pod.name: nodejs-app*` (**adapt the query filter to your use case**) + + 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). + +## Troubleshooting + +- Refer to [troubleshoot auto-instrumentation](./troubleshoot-auto-instrumentation.md) for further analysis.