Skip to content

Commit

Permalink
Add .Net Support, add test .Net App, Add documentation for 3 possible…
Browse files Browse the repository at this point in the history
… example demos (work in progress)
  • Loading branch information
jvoravong committed Jan 16, 2024
1 parent 6a9102b commit 0c9a863
Show file tree
Hide file tree
Showing 11 changed files with 387 additions and 5 deletions.
219 changes: 219 additions & 0 deletions examples/enable-operator-and-auto-instrumentation/otel-demo-dotnet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# Example of chart configuration

## How to deploy the OpenTelemetry Operator and .Net auto-instrumentation

In the following example we will show how to instrument a project using
[otel-demo](https://raw.githubusercontent.com/signalfx/splunk-otel-collector-chart/main/examples/enable-operator-and-auto-instrumentation/otel-demo/otel-demo.yaml).

### 1. Setup the OpenTelemetry demo to instrument

The .Net otel-demo demo will create a otel-demo namespace and deploys the related .Net applications to it.
If you have your own .Net application you want to instrument, you can still use the steps below as an example for how
to instrument your application.

#### TODO: Choose one of these examples to use
#### Example 1) Local OpenTelemetry demo for this chart
```bash
kubectl create namespace otel-demo
```

```bash
curl https://raw.githubusercontent.com/signalfx/splunk-otel-collector-chart/main/examples/enable-operator-and-auto-instrumentation/otel-demo/otel-demo.yaml | kubectl apply -n otel-demo -f -
```

#### Example 2) Local test .Net app for this chart that is a webserver and generates traffic

```bash
kubectl apply ../../functional_tests/testdata/dotnet/deployment.yaml -n default
```

#### Example 3) Upstream Operator demo, likely doesn't generate traffic

```bash
curl https://raw.githubusercontent.com/open-telemetry/opentelemetry-operator/main/tests/e2e-instrumentation/instrumentation-dotnet-musl/01-install-app.yaml | kubectl apply -n default -f -
```

### 2. Complete the steps outlined in [Getting started with auto-instrumentation](../../docs/auto-instrumentation-install.md#steps-for-setting-up-auto-instrumentation)

#### 2.1 Deploy the Helm Chart with the Operator enabled

To install the chart with operator in an existing cluster, make sure you have cert-manager installed and available.
Both the cert-manager and operator are subcharts of this chart and can be enabled with `--set certmanager.enabled=true,operator.enabled=true`.
These helm install commands will deploy the chart to the current namespace for this example.

```bash
# Check if a cert-manager is already installed by looking for cert-manager pods.
kubectl get pods -l app=cert-manager --all-namespaces

# If cert-manager is deployed, make sure to remove certmanager.enabled=true to the list of values to set
helm install splunk-otel-collector -f ./my_values.yaml --set operator.enabled=true,certmanager.enabled=true,environment=dev splunk-otel-collector-chart/splunk-otel-collector
```

#### 2.2 Verify all the OpenTelemetry resources (collector, operator, webhook, instrumentation) are deployed successfully

<details>
<summary>Expand for kubectl commands to run and output</summary>

```bash
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# splunk-otel-collector-agent-2mtfn 2/2 Running 0 5m
# splunk-otel-collector-agent-k4gc8 2/2 Running 0 5m
# splunk-otel-collector-agent-wjt98 2/2 Running 0 5m
# splunk-otel-collector-certmanager-69b98cc84d-2vzl7 1/1 Running 0 5m
# splunk-otel-collector-certmanager-cainjector-76db6dcbbf-4625c 1/1 Running 0 5m
# splunk-otel-collector-certmanager-webhook-bc68cd487-dctrf 1/1 Running 0 5m
# splunk-otel-collector-k8s-cluster-receiver-8449bfdc8-hhbvz 1/1 Running 0 5m
# splunk-otel-collector-operator-754c9d78f8-9ztwg 2/2 Running 0 5m

kubectl get mutatingwebhookconfiguration.admissionregistration.k8s.io
# NAME WEBHOOKS AGE
# splunk-otel-collector-certmanager-webhooh 1 8m
# splunk-otel-collector-operator-mutation 3 2m

kubectl get otelinst
# NAME AGE ENDPOINT
# splunk-otel-collector 5m http://$(SPLUNK_OTEL_AGENT):4317

# TODO: Update this section according to what example/demo is used
kubectl get pods -n otel-demo
# NAME READY STATUS RESTARTS AGE
# opentelemetry-demo-frontend-67f5685979-b4ngb 1/1 Running 0 2m11s
```

</details>

#### 2.3 Instrument Application by Setting an Annotation

Apply the instrumentation annotation to instrument the .Net deployment `opentelemetry-demo-frontend`:

#### TODO: Choose one of these examples to use
#### Example 1) Local OpenTelemetry demo for this chart

TODO: Choose one of these. Depending on if you are using linux-64 or linux-muscl-64 you will use one of these annotation apply (patch commands).
The linux-x64 annotation value is used if no instrumentation.opentelemetry.io/otel-dotnet-auto-runtime is supplied.

```bash
kubectl patch deployment opentelemetry-demo-cartservice -n otel-demo -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/otel-dotnet-auto-runtime":"linux-x64"}}}} }'
```

```bash
kubectl patch deployment opentelemetry-demo-cartservice -n otel-demo -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/otel-dotnet-auto-runtime":"linux-musl-x64"}}}} }'
```

Then apply the auto-instrumentation annotation for the instrumentation to happen.

```bash
kubectl patch deployment opentelemetry-demo-cartservice -n otel-demo -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/inject-dotnet":"default/splunk-otel-collector"}}}} }'
```

#### Example 2) Local test .Net app for this chart that is a webserver and generates traffic
TODO: Choose one of these. Depending on if you are using linux-64 or linux-muscl-64 you will use one of these annotation apply (patch commands).
The linux-x64 annotation value is used if no instrumentation.opentelemetry.io/otel-dotnet-auto-runtime is supplied.

```bash
kubectl patch deployment dotnet-test -n default -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/otel-dotnet-auto-runtime":"linux-x64"}}}} }'
```

```bash
kubectl patch deployment dotnet-test -n default -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/otel-dotnet-auto-runtime":"linux-musl-x64"}}}} }'
```

Then apply the auto-instrumentation annotation for the instrumentation to happen.

```bash
kubectl patch deployment dotnet-test -n otel-demo -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/inject-dotnet":"default/splunk-otel-collector"}}}} }'
```

#### Example 3) Upstream Operator demo, likely doesn't generate traffic
TODO: Choose one of these. Depending on if you are using linux-64 or linux-muscl-64 you will use one of these annotation apply (patch commands).
The linux-x64 annotation value is used if no instrumentation.opentelemetry.io/otel-dotnet-auto-runtime is supplied.

```bash
kubectl patch deployment my-deployment-with-sidecar -n default -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/otel-dotnet-auto-runtime":"linux-x64"}}}} }'
```

```bash
kubectl patch deployment my-deployment-with-sidecar -n default -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/otel-dotnet-auto-runtime":"linux-musl-x64"}}}} }'
```

Then apply the auto-instrumentation annotation for the instrumentation to happen.

```bash
kubectl patch deployment my-deployment-with-sidecar -n otel-demo -p '{"spec": {"template":{"metadata":{"annotations":{"instrumentation.opentelemetry.io/inject-dotnet":"default/splunk-otel-collector"}}}} }'
```

#### General Examples Notes
**Note:**
- This will cause the opentelemetry-demo-frontend pod to restart.
- The annotation value "default/splunk-otel-collector" refers to the Instrumentation configuration named `splunk-otel-collector` in the `default` namespace.
- If the chart is not installed in the "default" namespace, modify the annotation value to be "{chart_namespace}/splunk-otel-collector".

Remove the annotation to disable instrumentation:

TODO: Update this for the proper example/demo used
```bash
kubectl patch deployment {deployment_name} -n {deployment_namespace} --type=json -p='[{"op": "remove", "path": "/spec/template/metadata/annotations/instrumentation.opentelemetry.io~1inject-dotnet"}]'
```

You can verify instrumentation was successful on an individual pod with. Check that these bullet points are
true for the instrumented pod using the command below.
- Your instrumented pods should contain an initContainer named `opentelemetry-auto-instrumentation`
- The target application container should have several OTEL_* env variables set that are similar to the output below.

<details>
<summary>Expand for commands to run to verify instrumentation</summary>

TODO: Update this for the proper example/demo used
```bash
kubectl describe pod -n otel-demo -l app.kubernetes.io/name=opentelemetry-demo-frontend
# Name: opentelemetry-demo-frontend-57488c7b9c-4qbfb
# Namespace: otel-demo
# Annotations: instrumentation.opentelemetry.io/inject-nodejs: default/splunk-otel-collector
# Status: Running
# Init Containers:
# opentelemetry-auto-instrumentation:
# Command:
# cp
# -a
# /autoinstrumentation/.
# /otel-auto-instrumentation/
# State: Terminated
# Reason: Completed
# Exit Code: 0
# Containers:
# frontend:
# State: Running
# Ready: True
# Environment:
# FRONTEND_PORT: 8080
# FRONTEND_ADDR: :8080
# AD_SERVICE_ADDR: opentelemetry-demo-adservice:8080
# CART_SERVICE_ADDR: opentelemetry-demo-cartservice:8080
# CHECKOUT_SERVICE_ADDR: opentelemetry-demo-checkoutservice:8080
# CURRENCY_SERVICE_ADDR: opentelemetry-demo-currencyservice:8080
# PRODUCT_CATALOG_SERVICE_ADDR: opentelemetry-demo-productcatalogservice:8080
# RECOMMENDATION_SERVICE_ADDR: opentelemetry-demo-recommendationservice:8080
# SHIPPING_SERVICE_ADDR: opentelemetry-demo-shippingservice:8080
# WEB_OTEL_SERVICE_NAME: frontend-web
# PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: http://localhost:8080/otlp-http/v1/traces
# NODE_OPTIONS: --require /otel-auto-instrumentation/autoinstrumentation.js
# SPLUNK_OTEL_AGENT: (v1:status.hostIP)
# OTEL_SERVICE_NAME: opentelemetry-demo-frontend
# OTEL_EXPORTER_OTLP_ENDPOINT: http://$(SPLUNK_OTEL_AGENT):4317
# OTEL_RESOURCE_ATTRIBUTES_POD_NAME: opentelemetry-demo-frontend-57488c7b9c-4qbfb (v1:metadata.name)
# OTEL_RESOURCE_ATTRIBUTES_NODE_NAME: (v1:spec.nodeName)
# OTEL_PROPAGATORS: tracecontext,baggage,b3
# OTEL_RESOURCE_ATTRIBUTES: splunk.zc.method=autoinstrumentation-nodejs:0.41.1,k8s.container.name=frontend,k8s.deployment.name=opentelemetry-demo-frontend,k8s.namespace.name=otel-demo,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.replicaset.name=opentelemetry-demo-frontend-57488c7b9c,service.version=1.5.0-frontend
# Mounts:
# /otel-auto-instrumentation from opentelemetry-auto-instrumentation (rw)
# Volumes:
# opentelemetry-auto-instrumentation:
# Type: EmptyDir (a temporary directory that shares a pod's lifetime)
```

</details>

#### 2.4 Check out the results at [Splunk Observability APM](https://app.us1.signalfx.com/#/apm)

![APM](auto-instrumentation-dotnet-apm-result.png)
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ spec:
opentelemetry.io/name: opentelemetry-demo-cartservice
template:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-dotnet: "monitoring/splunk-otel-collector"
instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: "linux-musl-x64"
labels:
opentelemetry.io/name: opentelemetry-demo-cartservice
app.kubernetes.io/instance: opentelemetry-demo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ spec:
- name: OTEL_RESOURCE_ATTRIBUTES
value: splunk.zc.method=autoinstrumentation-apache-httpd:1.0.3
dotnet:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-dotnet:1.2.0
image: ghcr.io/signalfx/splunk-otel-dotnet/splunk-otel-dotnet:v1.2.1
env:
- name: OTEL_DOTNET_AUTO_PLUGINS
value: "Splunk.OpenTelemetry.AutoInstrumentation.Plugin, Splunk.OpenTelemetry.AutoInstrumentation"
- name: OTEL_RESOURCE_ATTRIBUTES
value: splunk.zc.method=autoinstrumentation-dotnet:1.2.0
value: splunk.zc.method=splunk-otel-dotnet:v1.2.1
# dotnet auto-instrumentation uses http/proto by default, so data must be sent to 4318 instead of 4317.
# See: https://github.com/open-telemetry/opentelemetry-operator#opentelemetry-auto-instrumentation-injection
- name: OTEL_EXPORTER_OTLP_ENDPOINT
Expand Down
21 changes: 21 additions & 0 deletions functional_tests/testdata/dotnet/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# TODO: Add support for .Net 7 or 8
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 3000

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["DotNetTestApp.csproj", "./"]
RUN dotnet restore "DotNetTestApp.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "DotNetTestApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "DotNetTestApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED=true
ENTRYPOINT ["dotnet", "DotNetTestApp.dll"]
12 changes: 12 additions & 0 deletions functional_tests/testdata/dotnet/DotNetTestApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions functional_tests/testdata/dotnet/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Default image repository
TODO: Set this to quay
IMAGE_REPO ?= jvsplk/dotnet_test
#IMAGE_REPO ?= quay.io/splunko11ytest/dotnet_test

.PHONY: push
push:
docker buildx build --file Dockerfile --platform linux/amd64,linux/arm64 --no-cache --tag $(IMAGE_REPO):latest --push .
46 changes: 46 additions & 0 deletions functional_tests/testdata/dotnet/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace DotNetTestApp
{
public class Program
{
public static async Task Main(string[] args)
{
var serverTask = CreateHostBuilder(args).Build().RunAsync();
var clientTask = RunClientAsync();

await Task.WhenAny(serverTask, clientTask);
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseUrls("http://*:3000"); // Listen on port 3000
});

private static async Task RunClientAsync()
{
var client = new HttpClient();
while (true)
{
try
{
var response = await client.GetAsync("http://localhost:3000");
Console.WriteLine($"Received response: {response.StatusCode}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}

await Task.Delay(1000); // Wait for 1 second
}
}
}
}
15 changes: 15 additions & 0 deletions functional_tests/testdata/dotnet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# .Net test image

This image is used for testing the auto-instrumentation of .Net application through the OpenTelemetry Operator.

This image is pushed to https://quay.io/repository/splunko11ytest/dotnet_test.

The container performs two separate functions:
* It runs a .Net HTTP server on port 3000 of the container host.
* It runs HTTP requests against the server every second.

Running this container inside a Kubernetes cluster under observation of the operator therefore creates traces.

## Develop

Login to quay.io and push with `make push`
27 changes: 27 additions & 0 deletions functional_tests/testdata/dotnet/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace DotNetTestApp
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello from .NET Test App!");
});
});
}
}
}
Loading

0 comments on commit 0c9a863

Please sign in to comment.