How to deploy a Hello World web app with Elastic Observability on Azure Container Apps

library-branding-elastic-observability-midnight-1680x980.png

Elastic Observability is the optimal tool to provide visibility into your running web apps. Microsoft Azure Container Apps is a fully managed environment that enables you to run containerized applications on a serverless platform so that your applications scale up and down. This allows you to accomplish the dual objective of serving every customer’s need for availability while meeting your needs to do so as efficiently as possible.

Using Elastic Observability and Azure Container Apps is a perfect combination for developers to deploy web apps that are auto-scaled with fully observable operations.

This blog post will show you how to deploy a simple Hello World web app to Azure Container Apps and then walk you through the steps to instrument the Hello World web app to enable observation of the application’s operations with Elastic Cloud.

Elastic Observability setup

We’ll start with setting up an Elastic Cloud deployment, which is where observability will take place for the web app we’ll be deploying.

From the Elastic Cloud console, select Create deployment.

create deployment

Enter a deployment name and click Create deployment. It takes a few minutes for your deployment to be created. While waiting, you are prompted to save the admin credentials for your deployment, which provides you with superuser access to your Elastic® deployment. Keep these credentials safe as they are shown only once.

Elastic Observability requires an APM Server URL and an APM Secret token for an app to send observability data to Elastic Cloud. Once the deployment is created, we’ll copy the Elastic Observability server URL and secret token and store them somewhere safely for adding to our web app code in a later step.

To copy the APM Server URL and the APM Secret Token, go to Elastic Cloud . Then go to the Deployments page, which lists all of the deployments you have created. Select the deployment you want to use, which will open the deployment details page. In the Kibana row of links, click on Open to open Kibana® for your deployment.

my deployment

Select Integrations from the top-level menu. Then click the APM tile.

apm

On the APM Agents page, copy the secretToken and the serverUrl values and save them for use in a later step.

apm agents

Now that we’ve completed the Elastic Cloud setup, the next step is to set up our account in Azure for deploying apps to the Container Apps service.

Azure Container Apps setup

First we’ll need an Azure account, so let’s create one by going to the Microsoft Azure portal and creating a new project. Click the Start free button and follow the steps to sign in or create a new account.

azure start free

Deploy a Hello World web app to Container Apps

We’ll perform the process of deploying a C# Hello World web app to Container Apps using the handy Azure tool called Cloud Shell. To deploy the Hello World app, we’ll perform the following 12 steps:

1. From the Azure portal, click the Cloud Shell icon at the top of the portal to open Cloud Shell…

cloud shell

… and when the Cloud Shell first opens, select Bash as the shell type to use.

bash

2. If you’re prompted that “You have no storage mounted,” then click the Create storage button to create a file store to be used for saving and editing files from Cloud Shell.

create storage

3. In Cloud Shell, clone a C# Hello World sample app repo from GitHub by entering the following command.

git clone https://github.com/elastic/observability-examples

4. Change directory to the location of the Hello World web app code.

cd observability-examples/azure/container-apps/helloworld

5. Define the environment variables that we’ll be using in the commands throughout this blog post.

RESOURCE_GROUP="helloworld-containerapps"
LOCATION="centralus"
ENVIRONMENT="env-helloworld-containerapps"
APP_NAME="elastic-helloworld"

6. Define a registry container name that is unique by running the following command.

ACR_NAME="helloworld"$RANDOM

7. Create an Azure resource group by running the following command.

az group create --name $RESOURCE_GROUP --location "$LOCATION"

8. Run the following command to create a registry container in Azure Container Registry.

az acr create --resource-group $RESOURCE_GROUP \
--name $ACR_NAME --sku Basic --admin-enable true

9. Build the app image and push it to Azure Container Registry by running the following command.

az acr build --registry $ACR_NAME --image $APP_NAME .

10. Register the Microsoft.OperationalInsights namespace as a provider by running the following command.

az provider register -n Microsoft.OperationalInsights --wait

11. Run the following command to create a Container App environment for deploying your app into.

az containerapp env create --name $ENVIRONMENT \
--resource-group $RESOURCE_GROUP --location "$LOCATION"

12. Create a new Container App by deploying the Hello World app’s image to Container Apps, using the following command.

az containerapp create \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --environment $ENVIRONMENT \
  --image $ACR_NAME.azurecr.io/$APP_NAME \
  --target-port 3500 \
  --ingress 'external' \
  --registry-server $ACR_NAME.azurecr.io \
  --query properties.configuration.ingress.fqdn

This command will output the deployed Hello World app's fully qualified domain name (FQDN). Copy and paste the FQDN into a browser to see your running Hello World app.

hello world

Instrument the Hello World web app with Elastic Observability

With a web app successfully running in Container Apps, we’re now ready to add the minimal code necessary to enable observability for the Hello World app in Elastic Cloud. We’ll perform the following eight steps:

1. In Azure Cloud Shell, create a new file named Telemetry.cs by typing the following command.

touch Telemetry.cs

2. Open the Azure Cloud Shell file editor by typing the following command in Cloud Shell.

code .

3. In the Azure Cloud Shell editor, open the Telemetry.cs file and paste in the following code. Save the edited file in Cloud Shell by pressing the [Ctrl] + [s] keys on your keyboard (or if you’re on a macOS computer, use the [⌘] + [s] keys). This class file is used to create a tracer ActivitySource, which can generate trace Activity spans for observability.

using System.Diagnostics;

public static class Telemetry
{
	public static readonly ActivitySource activitySource = new("Helloworld");
}

4. In the Azure Cloud Shell editor, edit the file named Dockerfile to add the following Elastic OpenTelemetry environment variables. Replace the ELASTIC_APM_SERVER_URL text and the ELASTIC_APM_SECRET_TOKEN text with the APM Server URL and the APM Secret Token values that you copied and saved in an earlier step. 

Save the edited file in Cloud Shell by pressing the [Ctrl] + [s] keys on your keyboard (or if you’re on a macOS computer, use the [⌘] + [s] keys).

The updated Dockerfile should look something like this:

FROM ${ARCH}mcr.microsoft.com/dotnet/aspnet:7.0. AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build
ARG TARGETPLATFORM

WORKDIR /src
COPY ["helloworld.csproj", "./"]
RUN dotnet restore "./helloworld.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "helloworld.csproj" -c Release -o /app/build

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

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
EXPOSE 3500
ENV ASPNETCORE_URLS=http://+:3500

ENV OTEL_EXPORTER_OTLP_ENDPOINT='https://******.apm.us-east-2.aws.elastic-cloud.com:443'
ENV OTEL_EXPORTER_OTLP_HEADERS='Authorization=Bearer ***********'
ENV OTEL_LOG_LEVEL=info
ENV OTEL_METRICS_EXPORTER=otlp
ENV OTEL_RESOURCE_ATTRIBUTES=service.version=1.0,deployment.environment=production
ENV OTEL_SERVICE_NAME=helloworld
ENV OTEL_TRACES_EXPORTER=otlp

ENTRYPOINT ["dotnet", "helloworld.dll"]

5. In the Azure Cloud Shell editor, edit the helloworld.csproj file to add the Elastic APM and OpenTelemetry dependencies. The updated helloworld.csproj file should look something like this:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
	<TargetFramework>net7.0</TargetFramework>
	<Nullable>enable</Nullable>
	<ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
	<PackageReference Include="Elastic.Apm" Version="1.24.0" />
	<PackageReference Include="Elastic.Apm.NetCoreAll" Version="1.24.0" />
	<PackageReference Include="OpenTelemetry" Version="1.6.0" />
	<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.6.0" />
	<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.6.0" />
	<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.6.0" />
	<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.5.0-beta.1" />
  </ItemGroup>
 
</Project>

6. In the Azure Cloud Shell editor, edit the Program.cs:

  • Add a using statement at the top of the file to import System.Diagnostics, which is used to create Activities that are equivalent to “spans” in OpenTelemetry. Also import the OpenTelemetry.Resources and OpenTelemetry.Trace packages.
using System.Diagnostics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
  • Update the “builder” initialization code block to include configuration to enable Elastic OpenTelemetry observability.
builder.Services.AddOpenTelemetry().WithTracing(builder => builder.AddOtlpExporter()
                	.AddSource("helloworld")
                	.AddAspNetCoreInstrumentation()
                	.AddOtlpExporter()  
    	.ConfigureResource(resource =>
        	resource.AddService(
            	serviceName: "helloworld"))
);
builder.Services.AddControllers();
  • Replace the “Hello World!” HTML output string…
<h1>Hello World!</h1>
  • ...with the “Hello Elastic Observability” HTML output string.
<div style="text-align: center;">
<h1 style="color: #005A9E; font-family:'Verdana'">
Hello Elastic Observability - Azure Container Apps - C#
</h1>
<img src="https://elastichelloworld.blob.core.windows.net/elastic-helloworld/elastic-logo.png">
</div>
  • Add a telemetry trace span around the output response utilizing the Telemetry class’ ActivitySource.
using (Activity activity = Telemetry.activitySource.StartActivity("HelloSpan")!)
   	{
   		Console.Write("hello");
   		await context.Response.WriteAsync(output);
   	}

The updated Program.cs file should look something like this:

using System.Diagnostics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry().WithTracing(builder => builder.AddOtlpExporter()
                	.AddSource("helloworld")
                	.AddAspNetCoreInstrumentation()
                	.AddOtlpExporter()  
    	.ConfigureResource(resource =>
        	resource.AddService(
            	serviceName: "helloworld"))
);
builder.Services.AddControllers();
var app = builder.Build();

string output =
"""
<div style="text-align: center;">
<h1 style="color: #005A9E; font-family:'Verdana'">
Hello Elastic Observability - Azure Container Apps - C#
</h1>
<img src="https://elastichelloworld.blob.core.windows.net/elastic-helloworld/elastic-logo.png">
</div>
""";

app.MapGet("/", async context =>
	{   
    	using (Activity activity = Telemetry.activitySource.StartActivity("HelloSpan")!)
    		{
        		Console.Write("hello");
        		await context.Response.WriteAsync(output);
    		}
	}
);
app.Run();

7. Rebuild the Hello World app image and push the image to the Azure Container Registry by running the following command.

az acr build --registry $ACR_NAME --image $APP_NAME .

8. Redeploy the updated Hello World app to Azure Container Apps, using the following command.

az containerapp create \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --environment $ENVIRONMENT \
  --image $ACR_NAME.azurecr.io/$APP_NAME \
  --target-port 3500 \
  --ingress 'external' \
  --registry-server $ACR_NAME.azurecr.io \
  --query properties.configuration.ingress.fqdn

This command will output the deployed Hello World app's fully qualified domain name (FQDN). Copy and paste the FQDN into a browser to see the updated Hello World app running in Azure Container Apps.

hello observability

Observe the Hello World web app

Now that we’ve instrumented the web app to send observability data to Elastic Observability, we can now use Elastic Cloud to monitor the web app’s operations.

  1. In Elastic Cloud, select the Observability Services menu item. 

  2. Click the helloworld service.

  3. Click the Transactions tab.

  4. Scroll down and click the GET / transaction.Scroll down to the Trace Sample section to see the GET /, HelloSpan trace sample.

latency-distribution

Observability made to scale

You’ve seen the entire process of deploying a web app to Azure Container Apps that is instrumented with Elastic Observability. This web app is now fully available on the web running on a platform that will auto-scale to serve visitors worldwide. And it’s instrumented for Elastic Observability APM using OpenTelemetry to ingest data into Elastic Cloud’s Kibana dashboards. 

Now that you’ve seen how to deploy a Hello World web app with a basic observability setup, visit Elastic Observability to learn more about expanding to a full scale observability coverage solution for your apps. Or visit Getting started with Elastic on Microsoft Azure for more examples of how you can drive the data insights you need by combining Microsoft Azure’s cloud computing services with Elastic’s search-powered platform.

The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.