Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaomi7732 committed Aug 19, 2022
2 parents ad92fb8 + d366d6b commit 07c6684
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 58 deletions.
8 changes: 3 additions & 5 deletions examples/WorkerExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// using System.Diagnostics;
// using Microsoft.ApplicationInsights.Kubernetes.Debugging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ApplicationInsights.Kubernetes.Examples;
Expand All @@ -23,7 +21,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) =>
// ApplicationInsightsKubernetesDiagnosticSource.Instance.Observable.SubscribeWithAdapter(observer);

services.AddApplicationInsightsTelemetryWorkerService();
services.AddApplicationInsightsKubernetesEnricher();
services.AddApplicationInsightsKubernetesEnricher(diagnosticLogLevel: Microsoft.Extensions.Logging.LogLevel.Information);
services.AddHostedService<Worker>();
});
}
}
35 changes: 29 additions & 6 deletions examples/WorkerExample/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This is what it looks like when `ApplicationInsights.Kubernetes` is turned on fo

![A image shows request telemetry with kubernetes properties](./images/RequestQuery.png)

And this example will walk you through the key steps.
And in this example, we will walk you through the key steps.

## Prerequisite

Expand Down Expand Up @@ -80,7 +80,7 @@ To finish the walk-through, there are some prerequisites.
```

You will see logs like this:

```shell
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
Expand All @@ -106,25 +106,48 @@ To finish the walk-through, there are some prerequisites.

_Notes: we are using dockerhub here as an example. you could use any container registry that deploys to your Kubernetes cluster._

* Tag the image properly, for example:
* Tag the image, bump up the version accordingly, for example:
```shell
docker tag workerapp dockerhub_account_name/ai-k8s-worker-example:0.0.1
docker tag workerapp dockerhub_account_name/ai-k8s-worker-example:1.0.0
```

* Push the image:

```shell
docker push dockerhub_account_name/ai-k8s-worker-example:0.0.1
docker push dockerhub_account_name/ai-k8s-worker-example:1.0.0
```

## Deploy the container to K8s cluster

* You could use default namespace, but it is recommended to put the test application in a dedicated namespace, for example 'ai-k8s-demo'. To deploy a namespace, use content in [k8s-namespace.yaml](../k8s-namespace.yaml):

```
kubectl create -f k8s-namespace.yaml
```

* Build a deployment yaml file, refer to [k8s.yml](./k8s.yml).

* Update the image property to pointing to the one that you intend to use.
* Update the namespace and the image to pointing to the one that you intend to use.

* Setup proper role binding for RBAC enabled clusters

If you have RBAC enabled for your cluster, permissions need to be granted to the service account to access the cluster info for telemetries. Refer to [Configure RBAC permissions](../../docs/configure-rbac-permissions.md) for details.

For example, deploy a role assignment in namespace of `ai-k8s-demo` by calling:

```shell
kubectl create -f ..\..\docs\sa-role.yaml
```

The output looks like this:

> clusterrole.rbac.authorization.k8s.io/appinsights-k8s-property-reader created
clusterrolebinding.rbac.authorization.k8s.io/appinsights-k8s-property-reader-binding created

* Deploy it:

Making sure the `image` is up to date, including the version in [k8s.yml](./k8s.yml), and then:

```shell
kubectl create -f .\k8s.yml
```
Expand Down
2 changes: 1 addition & 1 deletion examples/WorkerExample/WorkerExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.*" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.20.0" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.21.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
</ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion examples/WorkerExample/k8s.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-k8s-worker-example-deployment
namespace: ai-k8s-demo
labels:
app: ai-k8s-worker-example
spec:
Expand All @@ -16,4 +17,4 @@ spec:
spec:
containers:
- name: ai-k8s-worker-example
image: dockerhub_account_name/ai-k8s-worker-example:0.0.8
image: docker_registry_account_name/ai-k8s-worker-example:1.0.0
115 changes: 84 additions & 31 deletions examples/ZeroUserCodeLightup.Net6/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@

This example shows how to enable application insights for Kubernetes for ASP.NET Core 6.x WebAPI without code change for the existing project.

## Add Dockerfile
It can be accomplished in 2 steps:

All you need to do is to add a few lines in the [Dockerfile](./dockerfile), and they are:
* Add the proper NuGet Package
* Add Environment Variables

The example below shows the details.

## Reference hosting startup package in Dockerfile

Add this line in the [Dockerfile](./dockerfile):

```dockerfile
...
# Adding a reference to hosting startup package
# Adding a reference to hosting startup package. Replace --prerelease with the target version of the package you want to use.
RUN dotnet add package Microsoft.ApplicationInsights.Kubernetes.HostingStartup --prerelease

# Light up Application Insights for Kubernetes using hosting startup.
ENV ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=Microsoft.ApplicationInsights.Kubernetes.HostingStartup
...
```

Reference the full [Dockerfile](./dockerfile).
Notes: for the environment variable of `ASPNETCORE_HOSTINGSTARTUPASSEMBLIES`, you could alternatively add it in Kubernetes yaml file as well. For example, in [k8s.yaml](./k8s.yaml).

Here's the the full [Dockerfile](./dockerfile) example.

*Note: To make your build context as small as possible add a [.dockerignore](./.dockerignore) file to your project folder.*

Expand All @@ -29,36 +38,33 @@ Reference the full [Dockerfile](./dockerfile).
```shell
docker build -t ai-k8s-app .
docker container rm test-ai-k8s-app -f # Making sure any existing container with the same name is deleted
docker run -d -p 8080:80 --name test-ai-k8s-app ai-k8s-app -e APPLICATIONINSIGHTS_CONNECTION_STRING="your-connection-string"
docker run -d -p 8080:80 --name test-ai-k8s-app ai-k8s-app
docker logs test-ai-k8s-app
```

_Tips: Connection string can be fetched from the Azure Portal. See [connection strings](https://docs.microsoft.com/en-us/azure/azure-monitor/app/sdk-connection-string?tabs=net) for more details._

1. Expect the error

1. Delete the running container after the verification is done:
If you follow the steps above correctly, you shall see the following error in the beginning of the log:

```shell
docker container rm test-ai-k8s-app -f
[Error] [2022-06-10T21:23:10.0412107Z] Application is not running inside a Kubernetes cluster.
```

## Expect the error
Congratulations, your image is ready to run inside the Kubernetes! The error, as a matter of fact, is a good sign that Application Insights for Kubernetes is injected and it is trying to get the Kubernetes related data. It failed only because it is running outside of the Kubernetes.

If you follow the steps above, you shall see the following error in the beginning of the log:

```shell
[Error] [2022-06-10T21:23:10.0412107Z] Application is not running inside a Kubernetes cluster.
```
1. Delete the running container after the verification is done:

Congratulations, your image is ready to run inside the Kubernetes! The error, as a matter of fact, is a good sign that Application Insights for Kubernetes is injected and is trying to get the Kubernetes related data. It failed only because it is running outside of the Kubernetes.
```shell
docker container rm test-ai-k8s-app -f
```

## Upload the image to container registry

Once verified, the image is ready to be uploaded. Take docker hub for example, should work with any docker image registry:
Once verified, the image is ready to be uploaded. Here we use docker hub for example, it works with any Docker image registry:

```shell
docker tag ai-k8s-app:latest dockeraccount/ai-k8s-app:0.0.1
docker push dockeraccount/ai-k8s-app:0.0.1
docker tag ai-k8s-app:latest dockeraccount/ai-k8s-app:latest
docker push dockeraccount/ai-k8s-app:latest
```

**Note:** Change the tag properly. For more details, please reference the docker document: [Repositories](https://docs.docker.com/docker-hub/repos/).
Expand All @@ -67,6 +73,12 @@ docker push dockeraccount/ai-k8s-app:0.0.1

Now that the image is in the container registry, it is time to deploy it to Kubernetes.

* You could use default namespace, but it is recommended to put the test application in a dedicated namespace, for example 'ai-k8s-demo'. To deploy a namespace, use content in [k8s-namespace.yaml](../k8s-namespace.yaml):

```
kubectl create -f k8s-namespace.yaml
```

* Create a secret for application insights connection string

Create & deploy a secret using the following yaml.
Expand All @@ -75,13 +87,15 @@ Now that the image is in the container registry, it is time to deploy it to Kube
apiVersion: v1
kind: Secret
metadata:
name: app-env-secret
name: app-env-secret
namespace: ai-k8s-demo # Update to your namespace
type: Opaque
data:
appinsights-connection-string: eW91ci1pa2V5LW5vdC1taW5l #Base64 encoded connection string.
appinsights-connection-string: eW91IGhhdmUgdG8gZG8gdGhpcywgZG9uJ3QgeW91Pw== #Base64 encoded connection string.
```
_Tips: Connection string can be fetched from the Azure Portal. See [connection strings](https://docs.microsoft.com/en-us/azure/azure-monitor/app/sdk-connection-string?tabs=net) for more details._

_Tips: if you are going to create a file in your repository, `secrets.yaml` for example, adding the path to `.gitignore` to avoid check it in by accident._
_Tips: if you are going to create a file in your repository, `secrets.yaml` for example, adding the path to `.gitignore` to avoid checking it in by accident._

For example, you may deploy it like this:

Expand All @@ -91,28 +105,67 @@ Now that the image is in the container registry, it is time to deploy it to Kube

Refer to [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) for more info.

* Deploy the application
* Setup proper role binding for RBAC enabled clusters

If you have RBAC enabled for your cluster, permissions need to be granted to the service account to access the cluster info for telemetries. Refer to [Configure RBAC permissions](../../docs/configure-rbac-permissions.md) for details.

For example, deploy a role assignment in namespace of `ai-k8s-demo` by calling:

```shell
kubectl create -f ..\..\docs\sa-role.yaml
```

The output looks like this:

Create a Kubernetes deployment file. Reference [k8s.yaml](k8s.yaml) as an example, pay attention to the **image** and **environment variables**, making sure they are properly setup.
> clusterrole.rbac.authorization.k8s.io/appinsights-k8s-property-reader created
clusterrolebinding.rbac.authorization.k8s.io/appinsights-k8s-property-reader-binding created

* Deploy the application

Create a Kubernetes deployment file. Reference [k8s.yaml](k8s.yaml) as an example, pay attention to **namespace**, **image** and **environment variables**, making sure they are properly setup.

Then run the following kubectl command to deploy the app:
Then run the following command to deploy the app:

```shell
kubectl create -f deployment.yaml
kubectl create -f k8s.yaml
```

To learn more about Kubernetes deployment, please refer to [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/).

Generate some traffic to your application. After a while (around 2 minutes), you shall see Application Insights data coming with Kubernetes properties on it.
* Port forward for testing

![Application Insights Events with Kubernetes Properties](./.media/AI_K8s_Properties.png)
1. Get Pod name:

```shell
kubectl get pod --namespace ai-k8s-demo
```
Note down the pod name.

2. Use port forward to hit your application. For example, listens locally on 8080, forward it to 80 in the pod:

```shell
kubectl port-forward pod/<podName> 8080:80 --namespace ai-k8s-demo
```

You will see output:

> Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

3. Hit the endpoint to generate some traffic. For example:

```
curl http://localhost:8080/weatherforecast
```

After a while (around 2 minutes), you shall see Application Insights data coming with Kubernetes properties on it.


![Application Insights Events with Kubernetes Properties](./.media/AI_K8s_Properties.png)

## Summary

In this example, we modified the Dockerfile a bit to add the required NuGet packages into the project, then we used the environment variables to enable the feature.

The environment variable could also be managed by Kubernetes in the deployment spec.

We also touched the surface of using secrets to protect sensitive configurations like connection string of the application insights resource.

3 changes: 2 additions & 1 deletion examples/ZeroUserCodeLightup.Net6/k8s.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-k8s-app-deployment
namespace: ai-k8s-demo # Change to your namespace
labels:
app: ai-k8s-app
spec:
Expand All @@ -16,7 +17,7 @@ spec:
spec:
containers:
- name: ai-k8s-app
image: dockerhub_account_name/ai-k8s-app:0.0.8
image: container_registry_account/ai-k8s-app:latest # Your container registry account
env:
- name: APPLICATIONINSIGHTS_CONNECTION_STRING
valueFrom:
Expand Down
6 changes: 6 additions & 0 deletions examples/k8s-namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Namespace
apiVersion: v1
metadata:
name: ai-k8s-demo
labels:
name: ai-k8s-demo
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public KubeHttpClientSettingsBase(
ServiceBaseAddress = new Uri(baseAddress, UriKind.Absolute);
_containerIdProviders = containerIdProviders ?? throw new ArgumentNullException(nameof(containerIdProviders));
_containerIdNormalizer = containerIdNormalizer ?? throw new ArgumentNullException(nameof(containerIdNormalizer));
ContainerId = GetContainerIdOrThrow();
ContainerId = GetContainerIdOrEmpty();
}

/// <summary>
Expand Down Expand Up @@ -154,7 +154,7 @@ protected static string FetchQueryNamespace(string pathToNamespace)
return File.ReadAllText(pathToNamespace);
}

private string GetContainerIdOrThrow()
private string GetContainerIdOrEmpty()
{
foreach (IContainerIdProvider provider in _containerIdProviders)
{
Expand All @@ -172,7 +172,9 @@ private string GetContainerIdOrThrow()
return normalized!;
}
}
throw new InvalidOperationException("Failed fetching container id.");

_logger.LogWarning("Failed fetching container id.");
return string.Empty;
}
}
}
Loading

0 comments on commit 07c6684

Please sign in to comment.