|
| 1 | +--- |
| 2 | +title: "Tutorial: Configure Application Performance Management (APM) Java agent with init-container in Azure Container Apps" |
| 3 | +description: Learn to configure Application Performance Management (APM) Java agent with init-container in Azure Container Apps |
| 4 | +services: container-apps |
| 5 | +author: croffz |
| 6 | +ms.service: azure-container-apps |
| 7 | +ms.custom: devx-track-azurecli |
| 8 | +ms.topic: tutorial |
| 9 | +ms.date: 11/4/2024 |
| 10 | +ms.author: kuzhong |
| 11 | +--- |
| 12 | + |
| 13 | +# Tutorial: Configure Application Performance Management (APM) Java agent with init-container in Azure Container Apps |
| 14 | + |
| 15 | +Application Performance Management (APM) helps power observability for your container apps. You can package the APM plugin in the same image or Dockerfile with your app, but it binds the management efforts together, like release and Common Vulnerabilities and Exposures (CVE) mitigation. Rather than binding the concerns together, you can apply Java agent and init containers in Azure Container Apps to inject APM solutions without modifying your app image. |
| 16 | + |
| 17 | +In this tutorial, you learn how to: |
| 18 | + |
| 19 | +> [!div class="checklist"] |
| 20 | +> * Prepare an image to set up Java agent and push to Azure Container Registry |
| 21 | +> * Create a Container Apps environment and a container app as the target Java app |
| 22 | +> * Configure init containers and volume mounts to set up Application Insights integration |
| 23 | +
|
| 24 | +## Prerequisites |
| 25 | + |
| 26 | +- Have an instance of [Application Insights](/azure/azure-monitor/app/app-insights-overview) |
| 27 | +- Have an instance of Azure Container Registry or other container image registries |
| 28 | +- Install [Docker](https://www.docker.com/) to build image |
| 29 | +- Install the latest version of the [Azure CLI](/cli/azure/install-azure-cli) |
| 30 | + |
| 31 | +## Set up the environment |
| 32 | + |
| 33 | +The following commands help you define variables and ensure your Container Apps extension is up to date. |
| 34 | + |
| 35 | +1. Set up environment variables used in following commands. |
| 36 | + |
| 37 | + # [Bash](#tab/bash) |
| 38 | + |
| 39 | + ```bash |
| 40 | + SUBSCRIPTION_ID="<SUBSCRIPTION_ID>" # Replace with your own Azure subscription ID |
| 41 | + APP_INSIGHTS_RESOURCE_ID="/subscriptions/$SUBSCRIPTION_ID/resourceGroups/my-resource-group/providers/microsoft.insights/components/my-app-insights" |
| 42 | + CONTAINER_REGISTRY_NAME="myacr" |
| 43 | + RESOURCE_GROUP="my-resource-group" |
| 44 | + ENVIRONMENT_NAME="my-environment" |
| 45 | + CONTAINER_APP_NAME="my-container-app" |
| 46 | + LOCATION="eastus" |
| 47 | + ``` |
| 48 | + |
| 49 | + # [PowerShell](#tab/powershell) |
| 50 | + |
| 51 | + ```powershell |
| 52 | + $SUBSCRIPTION_ID="<SUBSCRIPTION_ID>" # Replace with your own Azure subscription ID |
| 53 | + $APP_INSIGHTS_RESOURCE_ID="/subscriptions/$SUBSCRIPTION_ID/resourceGroups/my-resource-group/providers/microsoft.insights/components/my-app-insights" |
| 54 | + $CONTAINER_REGISTRY_NAME="myacr" |
| 55 | + $RESOURCE_GROUP="my-resource-group" |
| 56 | + $ENVIRONMENT_NAME="my-environment" |
| 57 | + $CONTAINER_APP_NAME="my-container-app" |
| 58 | + $LOCATION="eastus" |
| 59 | + ``` |
| 60 | + |
| 61 | +1. Sign in to the Azure CLI. |
| 62 | + |
| 63 | + # [Bash](#tab/bash) |
| 64 | + |
| 65 | + ```bash |
| 66 | + az login |
| 67 | + az account set --subscription $SUBSCRIPTION_ID |
| 68 | + ``` |
| 69 | + |
| 70 | + # [PowerShell](#tab/powershell) |
| 71 | + |
| 72 | + ```powershell |
| 73 | + az login |
| 74 | + az account set --subscription $SUBSCRIPTION_ID |
| 75 | + ``` |
| 76 | + |
| 77 | +1. Ensure you have the latest version of Azure CLI extensions for Container Apps and Application Insights. |
| 78 | + |
| 79 | + # [Bash](#tab/bash) |
| 80 | + |
| 81 | + ```bash |
| 82 | + az extension add -n containerapp --upgrade |
| 83 | + az extension add -n application-insights --upgrade |
| 84 | + ``` |
| 85 | + |
| 86 | + # [PowerShell](#tab/powershell) |
| 87 | + |
| 88 | + ```powershell |
| 89 | + az extension add -n containerapp --upgrade |
| 90 | + az extension add -n application-insights --upgrade |
| 91 | + ``` |
| 92 | + |
| 93 | +1. Retrieve the connection string of Application Insights. |
| 94 | + |
| 95 | + # [Bash](#tab/bash) |
| 96 | + |
| 97 | + ```bash |
| 98 | + CONNECTION_STRING=$(az monitor app-insights component show \ |
| 99 | + --ids $APP_INSIGHTS_RESOURCE_ID \ |
| 100 | + --query connectionString) |
| 101 | + ``` |
| 102 | + |
| 103 | + # [PowerShell](#tab/powershell) |
| 104 | + |
| 105 | + ```powershell |
| 106 | + $CONNECTION_STRING=(az monitor app-insights component show ` |
| 107 | + --ids $APP_INSIGHTS_RESOURCE_ID ` |
| 108 | + --query connectionString) |
| 109 | + ``` |
| 110 | + |
| 111 | +## Prepare the container image |
| 112 | + |
| 113 | +1. Build setup image for Application Insights Java agent. |
| 114 | + |
| 115 | + Save the Dockerfile along with the setup script, and run `docker build` in the same directory. |
| 116 | + |
| 117 | + ```Dockerfile |
| 118 | + FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 |
| 119 | + |
| 120 | + ARG version="3.5.4" |
| 121 | + |
| 122 | + RUN tdnf update -y && tdnf install -y curl ca-certificates |
| 123 | + |
| 124 | + RUN curl -L "https://github.com/microsoft/ApplicationInsights-Java/releases/download/${version}/applicationinsights-agent-${version}.jar" > agent.jar |
| 125 | + |
| 126 | + ADD setup.sh /setup.sh |
| 127 | + |
| 128 | + ENTRYPOINT ["/bin/sh", "setup.sh"] |
| 129 | + ``` |
| 130 | + |
| 131 | + --- |
| 132 | + |
| 133 | + ```setup.sh |
| 134 | + #!/bin/sh |
| 135 | +
|
| 136 | + if [[ -z "$CONNECTION_STRING" ]]; then |
| 137 | + echo "Environment variable CONNECTION_STRING is not found. Exiting..." |
| 138 | + exit 1 |
| 139 | + else |
| 140 | + echo "{\"connectionString\": \"$CONNECTION_STRING\"}" > /java-agent/applicationinsights.json |
| 141 | + cp agent.jar /java-agent/agent.jar |
| 142 | + fi |
| 143 | + ``` |
| 144 | + |
| 145 | + --- |
| 146 | + |
| 147 | + # [Bash](#tab/bash) |
| 148 | + |
| 149 | + ```bash |
| 150 | + docker build . -t "$CONTAINER_REGISTRY_NAME.azurecr.io/samples/java-agent-setup:1.0.0" |
| 151 | + ``` |
| 152 | + |
| 153 | + # [PowerShell](#tab/powershell) |
| 154 | + |
| 155 | + ```powershell |
| 156 | + docker build . -t "$CONTAINER_REGISTRY_NAME.azurecr.io/samples/java-agent-setup:1.0.0" |
| 157 | + ``` |
| 158 | + |
| 159 | +1. Push the image to Azure Container Registry or other container image registries. |
| 160 | + |
| 161 | + # [Bash](#tab/bash) |
| 162 | + |
| 163 | + ```bash |
| 164 | + az acr login --name $CONTAINER_REGISTRY_NAME |
| 165 | + docker push "$CONTAINER_REGISTRY_NAME.azurecr.io/samples/java-agent-setup:1.0.0" |
| 166 | + ``` |
| 167 | + |
| 168 | + # [PowerShell](#tab/powershell) |
| 169 | + |
| 170 | + ```powershell |
| 171 | + az acr login --name $CONTAINER_REGISTRY_NAME |
| 172 | + docker push "$CONTAINER_REGISTRY_NAME.azurecr.io/samples/java-agent-setup:1.0.0" |
| 173 | + ``` |
| 174 | + |
| 175 | +> [!TIP] |
| 176 | +> You can find related code in this step from [Azure-Samples/azure-container-apps-java-samples](https://github.com/Azure-Samples/azure-container-apps-java-samples). |
| 177 | + |
| 178 | +## Create a Container Apps environment and a Container App as the target Java app |
| 179 | + |
| 180 | +1. Create a Container Apps environment. |
| 181 | + |
| 182 | + # [Bash](#tab/bash) |
| 183 | + |
| 184 | + ```bash |
| 185 | + az containerapp env create \ |
| 186 | + --name $ENVIRONMENT_NAME \ |
| 187 | + --resource-group $RESOURCE_GROUP \ |
| 188 | + --location "$LOCATION" \ |
| 189 | + --query "properties.provisioningState" |
| 190 | + ``` |
| 191 | + |
| 192 | + # [PowerShell](#tab/powershell) |
| 193 | + |
| 194 | + ```powershell |
| 195 | + az containerapp env create ` |
| 196 | + --name $ENVIRONMENT_NAME ` |
| 197 | + --resource-group $RESOURCE_GROUP ` |
| 198 | + --location "$LOCATION" ` |
| 199 | + --query "properties.provisioningState" |
| 200 | + ``` |
| 201 | + |
| 202 | + Once created, the command returns a "Succeeded" message. |
| 203 | + |
| 204 | +1. Create a Container app for further configurations. |
| 205 | + |
| 206 | + # [Bash](#tab/bash) |
| 207 | + |
| 208 | + ```bash |
| 209 | + az containerapp create \ |
| 210 | + --name $CONTAINER_APP_NAME \ |
| 211 | + --environment $ENVIRONMENT_NAME \ |
| 212 | + --resource-group $RESOURCE_GROUP \ |
| 213 | + --query "properties.provisioningState" |
| 214 | + ``` |
| 215 | + |
| 216 | + # [PowerShell](#tab/powershell) |
| 217 | + |
| 218 | + ```powershell |
| 219 | + az containerapp create ` |
| 220 | + --name $CONTAINER_APP_NAME ` |
| 221 | + --environment $ENVIRONMENT_NAME ` |
| 222 | + --resource-group $RESOURCE_GROUP ` |
| 223 | + --query "properties.provisioningState" |
| 224 | + ``` |
| 225 | + |
| 226 | + Once created, the command returns a "Succeeded" message. |
| 227 | + |
| 228 | +## Configure init-container, secrets, environment variables, and volumes to set up Application Insights integration |
| 229 | + |
| 230 | +1. Get current configurations of the running Container App. |
| 231 | + |
| 232 | + # [Bash](#tab/bash) |
| 233 | + |
| 234 | + ```bash |
| 235 | + az containerapp show \ |
| 236 | + --name $CONTAINER_APP_NAME \ |
| 237 | + --resource-group $RESOURCE_GROUP \ |
| 238 | + -o yaml > app.yaml |
| 239 | + ``` |
| 240 | + |
| 241 | + # [PowerShell](#tab/powershell) |
| 242 | + |
| 243 | + ```powershell |
| 244 | + az containerapp show ` |
| 245 | + --name $CONTAINER_APP_NAME ` |
| 246 | + --resource-group $RESOURCE_GROUP ` |
| 247 | + -o yaml > app.yaml |
| 248 | + ``` |
| 249 | + |
| 250 | + The YAML file `app.yaml` is created in current directory. |
| 251 | + |
| 252 | +1. Edit the app YAML file. |
| 253 | + |
| 254 | + - Add secret for Application Insights connection string |
| 255 | + |
| 256 | + ```yaml |
| 257 | + properties: |
| 258 | + configuration: |
| 259 | + secrets: |
| 260 | + - name: app-insights-connection-string |
| 261 | + value: $CONNECTION_STRING |
| 262 | + ``` |
| 263 | + |
| 264 | + Replace $CONNECTION_STRING with your Azure Application Insights connection string. |
| 265 | + |
| 266 | + - Add ephemeral storage volume for Java agent files |
| 267 | + |
| 268 | + ```yaml |
| 269 | + properties: |
| 270 | + template: |
| 271 | + volumes: |
| 272 | + - name: java-agent-volume |
| 273 | + storageType: EmptyDir |
| 274 | + ``` |
| 275 | + |
| 276 | + - Add init-container with volume mounts and environment variables |
| 277 | + |
| 278 | + ```yaml |
| 279 | + properties: |
| 280 | + template: |
| 281 | + initContainers: |
| 282 | + - image: <CONTAINER_REGISTRY_NAME>.azurecr.io/samples/java-agent-setup:1.0.0 |
| 283 | + name: java-agent-setup |
| 284 | + resources: |
| 285 | + cpu: 0.25 |
| 286 | + memory: 0.5Gi |
| 287 | + env: |
| 288 | + - name: CONNECTION_STRING |
| 289 | + secretRef: app-insights-connection-string |
| 290 | + volumeMounts: |
| 291 | + - mountPath: /java-agent |
| 292 | + volumeName: java-agent-volume |
| 293 | + ``` |
| 294 | + |
| 295 | + Replace `<CONTAINER_REGISTRY_NAME>` with your Azure Container Registry name. |
| 296 | + |
| 297 | + - Update app container with volume mounts and environment variables |
| 298 | + |
| 299 | + ```yaml |
| 300 | + properties: |
| 301 | + template: |
| 302 | + containers: |
| 303 | + - name: test-java-app |
| 304 | + image: mcr.microsoft.com/azurespringapps/samples/hello-world:0.0.1 |
| 305 | + resources: |
| 306 | + cpu: 0.5 |
| 307 | + memory: 1Gi |
| 308 | + env: |
| 309 | + - name: JAVA_TOOL_OPTIONS |
| 310 | + value: -javaagent:/java-agent/agent.jar |
| 311 | + volumeMounts: |
| 312 | + - mountPath: /java-agent |
| 313 | + volumeName: java-agent-volume |
| 314 | + ``` |
| 315 | + |
| 316 | +1. Update the container app with modified YAML file. |
| 317 | + |
| 318 | + # [Bash](#tab/bash) |
| 319 | + |
| 320 | + ```bash |
| 321 | + az containerapp update \ |
| 322 | + --name $CONTAINER_APP_NAME \ |
| 323 | + --resource-group $RESOURCE_GROUP \ |
| 324 | + --yaml app.yaml \ |
| 325 | + --query "properties.provisioningState" |
| 326 | + ``` |
| 327 | + |
| 328 | + # [PowerShell](#tab/powershell) |
| 329 | + |
| 330 | + ```powershell |
| 331 | + az containerapp update ` |
| 332 | + --name $CONTAINER_APP_NAME ` |
| 333 | + --resource-group $RESOURCE_GROUP ` |
| 334 | + --yaml app.yaml ` |
| 335 | + --query "properties.provisioningState" |
| 336 | + ``` |
| 337 | + |
| 338 | + Once updated, the command returns a "Succeeded" message. Then you can check out your Application Insights in Azure portal to see your Container App is connected. |
| 339 | + |
| 340 | +## Clean up resources |
| 341 | + |
| 342 | +The resources created in this tutorial contribute to your Azure bill. If you aren't going to keep them in the long term, run the following commands to clean them up. |
| 343 | +
|
| 344 | +# [Bash](#tab/bash) |
| 345 | +```bash |
| 346 | +az group delete --resource-group $RESOURCE_GROUP |
| 347 | +``` |
| 348 | +# [PowerShell](#tab/powershell) |
| 349 | +```powershell |
| 350 | +az group delete --resource-group $RESOURCE_GROUP |
| 351 | +``` |
| 352 | +
|
| 353 | +--- |
| 354 | +
|
| 355 | +## Other APM solutions |
| 356 | +
|
| 357 | +Other than [Azure Application Insights](/azure/azure-monitor/app/java-standalone-config), there are other popular APM solutions in the community. If you want to integrate your Azure Container App with other APM providers, just replace the Java agent JAR and related config files. |
| 358 | +
|
| 359 | +- [AppDynamics](https://docs.appdynamics.com/appd/21.x/21.4/en/application-monitoring/install-app-server-agents/java-agent/install-the-java-agent) |
| 360 | +- [Dynatrace](https://docs.dynatrace.com/docs/setup-and-configuration/technology-support/application-software/java) |
| 361 | +- [Elastic](https://www.elastic.co/guide/en/apm/agent/java/index.html) |
| 362 | +- [NewRelic](https://docs.newrelic.com/docs/apm/agents/java-agent/getting-started/introduction-new-relic-java/) |
0 commit comments