Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Assignment 4 - Deploying to Azure Container Apps

Table of contents

This assignment is about deploying the 3 microservices to Azure Container Apps with Dapr enabled for pub/sub. This is the first deployment of the microservices to Azure. The next assignments provide step by step instructions for deploying the microservices using more Dapr building blocks. The camera simulation runs locally and is not deployed to Azure.

Azure Container Apps Challenge - First Deployment

Setup

Now, let’s create the infrastructure for our application, so you can later deploy our microservices to Azure Container Apps.

Log Analytics Workspace

Log Analytics workspace is the environment for Azure Monitor log data. Each workspace has its own data repository and configuration, and data sources and solutions are configured to store their data in a particular workspace. You will use the same workspace for most of the Azure resources you will be creating.

  1. Create a Log Analytics workspace with the following command:

     az monitor log-analytics workspace create \
       --resource-group rg-dapr-workshop-java \
       --location eastus \
       --workspace-name log-dapr-workshop-java
    
  2. Retrieve the Log Analytics Client ID and client secret and store them in environment variables:

    • Linux/Unix shell:

       LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID=$(
         az monitor log-analytics workspace show \
           --resource-group rg-dapr-workshop-java \
           --workspace-name log-dapr-workshop-java \
           --query customerId  \
           --output tsv | tr -d '[:space:]'
       )
       echo "LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID=$LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID"
      
       LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET=$(
         az monitor log-analytics workspace get-shared-keys \
           --resource-group rg-dapr-workshop-java \
           --workspace-name log-dapr-workshop-java \
           --query primarySharedKey \
           --output tsv | tr -d '[:space:]'
       )
       echo "LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET=$LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET"
      
    • Powershell:

       $LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID= `
         az monitor log-analytics workspace show `
           --resource-group rg-dapr-workshop-java `
           --workspace-name log-dapr-workshop-java `
           --query customerId  `
           --output tsv
       Write-Output "LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID=$LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID"
      
       $LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET= `
         az monitor log-analytics workspace get-shared-keys `
           --resource-group rg-dapr-workshop-java `
           --workspace-name log-dapr-workshop-java `
           --query primarySharedKey `
           --output tsv
       Write-Output "LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET=$LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET"
      

Application Insights

Application Insights is used to enable Dapr service-to-service telemetry. The telemetry is used to visualize the microservices communication in the Application Insigts Application Map. When creating the Azure Container Apps environment, you can set Application Insights instrumentation key that is used by Dapr to export service-to-service telemetry to Application Insights.

  1. Create an Application Insights resource:

     az monitor app-insights component create --app appi-dapr-workshop-java --location eastus --kind web -g rg-dapr-workshop-java --application-type web
    

    You may receive a message to install the application-insights extension, if so please install the extension for this exercise.

  2. Get the instrumentation key for the Application Insights and set it to the INSTRUMENTATION_KEY variable:

    • Linux/Unix shell:

      INSTRUMENTATION_KEY=$(az monitor app-insights component show --app appi-dapr-workshop-java -g rg-dapr-workshop-java --query instrumentationKey)
      echo $INSTRUMENTATION_KEY
      
    • PowerShell:

      $INSTRUMENTATION_KEY = az monitor app-insights component show --app appi-dapr-workshop-java -g rg-dapr-workshop-java --query instrumentationKey
      $INSTRUMENTATION_KEY
      

Azure Container Registry

Later, you will be creating Docker containers and pushing them to the Azure Container Registry.

  1. Azure Container Registry is a private registry for hosting container images. Using the Azure Container Registry, you can store Docker images for all types of container deployments. This registry needs to be gloablly unique. Use the following command to generate a unique name:

    • Linux/Unix shell:

        UNIQUE_IDENTIFIER=$(LC_ALL=C tr -dc a-z0-9 </dev/urandom | head -c 5)
        CONTAINER_REGISTRY="crdaprworkshopjava$UNIQUE_IDENTIFIER"
        echo $CONTAINER_REGISTRY
      
    • Powershell:

        $ACCEPTED_CHAR = [Char[]]'abcdefghijklmnopqrstuvwxyz0123456789'
        $UNIQUE_IDENTIFIER = (Get-Random -Count 5 -InputObject $ACCEPTED_CHAR) -join ''
        $CONTAINER_REGISTRY = "crdaprworkshopjava$UNIQUE_IDENTIFIER"
        $CONTAINER_REGISTRY
      
  2. Create an Azure Container Registry with the following command:

     az acr create \
       --resource-group rg-dapr-workshop-java \
       --location eastus \
       --name "$CONTAINER_REGISTRY" \
       --workspace log-dapr-workshop-java \
       --sku Standard \
       --admin-enabled true
    

    Notice that you created the registry with admin rights --admin-enabled true which is not suited for real production, but well for our workshop

  3. Update the registry to allow anonymous users to pull the images ():

     az acr update \
       --resource-group rg-dapr-workshop-java \
       --name "$CONTAINER_REGISTRY" \
       --anonymous-pull-enabled true
    

    This can be handy if you want other attendees of the workshop to use your registry, but this is not suitable for production.

  4. Get the URL of the Azure Container Registry and set it to the CONTAINER_REGISTRY_URL variable with the following command:

    • Linux/Unix shell:

      CONTAINER_REGISTRY_URL=$(
        az acr show \
          --resource-group rg-dapr-workshop-java \
          --name "$CONTAINER_REGISTRY" \
          --query "loginServer" \
          --output tsv
      )
      
      echo "CONTAINER_REGISTRY_URL=$CONTAINER_REGISTRY_URL"
      
    • Powershell:

      $CONTAINER_REGISTRY_URL="$(
        az acr show `
          --resource-group rg-dapr-workshop-java `
          --name "$CONTAINER_REGISTRY" `
          --query "loginServer" `
          --output tsv
      )"
      
      Write-Output "CONTAINER_REGISTRY_URL=$CONTAINER_REGISTRY_URL"
      

Azure Container Apps Environment

A container apps environment acts as a secure boundary around our container apps. Containers deployed on the same environment use the same virtual network and write the log to the same logging destionation, in our case: Log Analytics workspace.

To create the container apps environment with Dapr service-to-service telemetry, you need to set --dapr-instrumentation-key parameter to the Application Insights instrumentation key. Use the following command to create the container apps environment:

az containerapp env create \
  --resource-group rg-dapr-workshop-java \
  --location eastus \
  --name cae-dapr-workshop-java \
  --logs-workspace-id "$LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID" \
  --logs-workspace-key "$LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET" \
  --dapr-instrumentation-key "$INSTRUMENTATION_KEY"

Some Azure CLI commands can take some time to execute. Don’t hesitate to have a look at the next assignments / steps to know what you will have to do. And then, come back to this one when the command is done and execute the next one.

Step 1 - Deploy Dapr Component for pub/sub

You are going to deploy the pubsub Dapr component to use Azure Service Bus as the pub/sub message broker.

In Assignment 3 - Using Dapr for pub/sub with Azure Service Bus, you copied the file dapr/azure-servicebus-pubsub.yaml to dapr/components folder and updated the connectionString value. This file was used to deploy the pubsub Dapr component.

The Dapr component schema for Azure Container Apps is different from the standard Dapr component yaml schema. It has been slightly simplified. Hence the need for a new component yaml file.

  1. Open the file dapr/aca-azure-servicebus-pubsub.yaml in your code editor.

     componentType: pubsub.azure.servicebus
     version: v1
     metadata:
       - name: connectionString
         value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}"
     scopes:
       - traffic-control-service
       - fine-collection-service
    
  2. Copy or Move this file dapr/aca-servicebus-pubsub.yaml to dapr/components folder.

  3. Replace the connectionString value with the value you set in dapr/components/azure-servicebus-pubsub.yaml in Assignment 3 - Using Dapr for pub/sub with Azure Service Bus.

  4. Go to the root folder of the repository.

  5. Enter the following command to deploy the pubsub Dapr component:

     az containerapp env dapr-component set \
       --name cae-dapr-workshop-java \
       --resource-group rg-dapr-workshop-java \
       --dapr-component-name pubsub \
       --yaml ./dapr/components/aca-azure-servicebus-pubsub.yaml
    

Step 2 - Generate Docker images for applications, and push them to ACR

Since you don’t have any container images ready yet, we’ll build and push container images in Azure Container Registry (ACR) to get things running.

  1. Login to your ACR repository

     az acr login --name $CONTAINER_REGISTRY
    
  2. In the root folder of VehicleRegistrationService microservice, run the following command

     mvn spring-boot:build-image
     docker tag vehicle-registration-service:1.0-SNAPSHOT "$CONTAINER_REGISTRY.azurecr.io/vehicle-registration-service:1.0"
     docker push "$CONTAINER_REGISTRY.azurecr.io/vehicle-registration-service:1.0"
    
  3. In the root folder of FineCollectionService microservice, run the following command

     mvn spring-boot:build-image
     docker tag fine-collection-service:1.0-SNAPSHOT "$CONTAINER_REGISTRY.azurecr.io/fine-collection-service:1.0"
     docker push "$CONTAINER_REGISTRY.azurecr.io/fine-collection-service:1.0"
    
  4. In the root folder of TrafficControlService microservice, run the following command

     mvn spring-boot:build-image
     docker tag traffic-control-service:1.0-SNAPSHOT "$CONTAINER_REGISTRY.azurecr.io/traffic-control-service:1.0"
     docker push "$CONTAINER_REGISTRY.azurecr.io/traffic-control-service:1.0"
    

Step 3 - Deploy the Container Apps

Now that you have created the container apps environment and push the images, you can create the container apps. A container app is a containerized application that is deployed to a container apps environment.

You will create three container apps, one for each of our Java services: TrafficControlService, FineCollectionService and VehicleRegistrationService.

  1. Create a Container App for VehicleRegistrationService with the following command:

     az containerapp create \
       --name ca-vehicle-registration-service \
       --resource-group rg-dapr-workshop-java \
       --environment cae-dapr-workshop-java \
       --image "$CONTAINER_REGISTRY_URL/vehicle-registration-service:1.0" \
       --target-port 6002 \
       --ingress internal \
       --min-replicas 1 \
       --max-replicas 1
    

    Notice that internal ingress is enable. This is because we want to provide access to the service only from within the container apps environment. FineCollectionService will be able to access the VehicleRegistrationService using the internal ingress FQDN.

  2. Get the FQDN of VehicleRegistrationService and save it in a variable:

    • Linux/Unix shell:

      VEHICLE_REGISTRATION_SERVICE_FQDN=$(az containerapp show \
        --name ca-vehicle-registration-service \
        --resource-group rg-dapr-workshop-java \
        --query "properties.configuration.ingress.fqdn" \
        -o tsv)
      echo $VEHICLE_REGISTRATION_SERVICE_FQDN
      
    • Powershell:

      $VEHICLE_REGISTRATION_SERVICE_FQDN = az containerapp show `
        --name ca-vehicle-registration-service `
        --resource-group rg-dapr-workshop-java `
        --query "properties.configuration.ingress.fqdn" `
        -o tsv
      $VEHICLE_REGISTRATION_SERVICE_FQDN
      

    Notice that the FQDN is in the format <service-name>.internal.<unique-name>.<region>.azurecontainerapps.io where internal indicates that the service is only accessible from within the container apps environment, i.e. exposed with internal ingress.

  3. Create a Container App for FineCollectionService with the following command:

     az containerapp create \
       --name ca-fine-collection-service \
       --resource-group rg-dapr-workshop-java \
       --environment cae-dapr-workshop-java \
       --image "$CONTAINER_REGISTRY_URL/fine-collection-service:1.0" \
       --min-replicas 1 \
       --max-replicas 1 \
       --enable-dapr \
       --dapr-app-id fine-collection-service \
       --dapr-app-port 6001 \
       --dapr-app-protocol http \
       --env-vars "VEHICLE_REGISTRATION_SERVICE_BASE_URL=https://$VEHICLE_REGISTRATION_SERVICE_FQDN"
    
  4. Create a Container App for TrafficControlService with the following command:

     az containerapp create \
       --name ca-traffic-control-service \
       --resource-group rg-dapr-workshop-java \
       --environment cae-dapr-workshop-java \
       --image "$CONTAINER_REGISTRY_URL/traffic-control-service:1.0" \
       --target-port 6000 \
       --ingress external \
       --min-replicas 1 \
       --max-replicas 1 \
       --enable-dapr \
       --dapr-app-id traffic-control-service \
       --dapr-app-port 6000 \
       --dapr-app-protocol http
    
  5. Get the FQDN of traffic control service and save it in a variable:

    • Linux/Unix shell:

      TRAFFIC_CONTROL_SERVICE_FQDN=$(az containerapp show \
        --name ca-traffic-control-service \
        --resource-group rg-dapr-workshop-java \
        --query "properties.configuration.ingress.fqdn" \
        -o tsv)
      echo $TRAFFIC_CONTROL_SERVICE_FQDN
      
    • Powershell:

      $TRAFFIC_CONTROL_SERVICE_FQDN = $(az containerapp show `
        --name ca-traffic-control-service `
        --resource-group rg-dapr-workshop-java `
        --query "properties.configuration.ingress.fqdn" `
        -o tsv)
      $TRAFFIC_CONTROL_SERVICE_FQDN
      

    Notice that the FQDN is in the format <service-name>.<unique-name>.<region>.azurecontainerapps.io where internal is not present. Indeed, traffic control service is exposed with external ingress, i.e. it is accessible from outside the container apps environment. It will be used by the simulation to test the application.

Step 4 - Run the simulation

  1. Set the following environment variable:

    • Linux/Unix shell:

      export TRAFFIC_CONTROL_SERVICE_BASE_URL=https://$TRAFFIC_CONTROL_SERVICE_FQDN
      
    • Powershell:

      $env:TRAFFIC_CONTROL_SERVICE_BASE_URL = "https://$TRAFFIC_CONTROL_SERVICE_FQDN"
      
  2. In the root folder of the simulation (Simulation), start the simulation:

     mvn spring-boot:run
    

Step 5 - Test the microservices running in ACA

You can access the log of the container apps from the Azure Portal or directly in a terminal window. To access the logs in the portal, you need to go to your resource group rg-dapr-workshop-java and select the container app for which you need the log. Then select Log stream in Monitoring section.

To access the logs from the terminal, follow the instructions below for each microservice.

The logs can take a few minutes to appear in the Log Analytics Workspace. If the logs are not updated, open the log stream in the Azure Portal.

Traffic Control Service

  1. Run the following command to identify the running revision of traffic control service container apps:

    • Linux/Unix shell:

      TRAFFIC_CONTROL_SERVICE_REVISION=$(az containerapp revision list -n ca-traffic-control-service -g rg-dapr-workshop-java --query "[0].name" -o tsv)
      echo $TRAFFIC_CONTROL_SERVICE_REVISION
      
    • Powershell:

      $TRAFFIC_CONTROL_SERVICE_REVISION = az containerapp revision list -n ca-traffic-control-service -g rg-dapr-workshop-java --query "[0].name" -o tsv
      $TRAFFIC_CONTROL_SERVICE_REVISION
      
  2. Run the following command to get the last 10 lines of traffic control service logs from Log Analytics Workspace:

     az monitor log-analytics query \
       --workspace $LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID \
       --analytics-query "ContainerAppConsoleLogs_CL | where RevisionName_s == '$TRAFFIC_CONTROL_SERVICE_REVISION' | project TimeGenerated, Log_s | sort by TimeGenerated desc | take 10" \
       --out table
    

Fine Collection Service

  1. Run the following command to identify the running revision of fine collection service container apps:

    • Linux/Unix shell:

      FINE_COLLECTION_SERVICE_REVISION=$(az containerapp revision list -n ca-fine-collection-service -g rg-dapr-workshop-java --query "[0].name" -o tsv)
      echo $FINE_COLLECTION_SERVICE_REVISION
      
    • Powershell:

      $FINE_COLLECTION_SERVICE_REVISION = az containerapp revision list -n ca-fine-collection-service -g rg-dapr-workshop-java --query "[0].name" -o tsv
      $FINE_COLLECTION_SERVICE_REVISION
      
  2. Run the following command to get the last 10 lines of fine collection service logs from Log Analytics Workspace:

     az monitor log-analytics query \
       --workspace $LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID \
       --analytics-query "ContainerAppConsoleLogs_CL | where RevisionName_s == '$FINE_COLLECTION_SERVICE_REVISION' | project TimeGenerated, Log_s | sort by TimeGenerated desc | take 10" \
       --out table
    

Vehicle Registration Service

  1. Run the following command to identify the running revision of vehicle registration service container apps:

    • Linux/Unix shell:

      VEHICLE_REGISTRATION_SERVICE_REVISION=$(az containerapp revision list -n ca-vehicle-registration-service -g rg-dapr-workshop-java --query "[0].name" -o tsv)
      echo $VEHICLE_REGISTRATION_SERVICE_REVISION
      
    • Powershell:

      $VEHICLE_REGISTRATION_SERVICE_REVISION = az containerapp revision list -n ca-vehicle-registration-service -g rg-dapr-workshop-java --query "[0].name" -o tsv
      $VEHICLE_REGISTRATION_SERVICE_REVISION
      
  2. Run the following command to get the last 10 lines of vehicle registration service logs from Log Analytics Workspace:

     az monitor log-analytics query \
       --workspace $LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID \
       --analytics-query "ContainerAppConsoleLogs_CL | where RevisionName_s == '$VEHICLE_REGISTRATION_SERVICE_REVISION' | project TimeGenerated, Log_s | sort by TimeGenerated desc | take 10" \
       --out table
    

Step 6: View the telemetry in Application Insights

  1. Open the Application Insights resource in the Azure portal.

  2. Go to Application Map, you should see a diagram like the on below

Dapr Telemetry

< Assignment 3 - Pub/sub with Azure Service Bus Assignment 5 - Service invocation >