├── .devcontainer └── devcontainer.json ├── .gitattributes ├── .gitignore ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── FineCollectionService ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src │ └── main │ │ ├── java │ │ ├── dapr │ │ │ ├── fines │ │ │ │ ├── FineCollectionApplication.java │ │ │ │ ├── FineCollectionConfiguration.java │ │ │ │ ├── fines │ │ │ │ │ ├── DaprFineCalculator.java │ │ │ │ │ ├── DefaultFineCalculator.java │ │ │ │ │ ├── EmailGenerator.java │ │ │ │ │ └── FineCalculator.java │ │ │ │ ├── vehicle │ │ │ │ │ ├── DaprVehicleRegistrationClient.java │ │ │ │ │ ├── DefaultVehicleRegistrationClient.java │ │ │ │ │ ├── VehicleInfo.java │ │ │ │ │ └── VehicleRegistrationClient.java │ │ │ │ └── violation │ │ │ │ │ ├── JsonObjectDeserializer.java │ │ │ │ │ ├── KafkaConsumerConfig.java │ │ │ │ │ ├── KafkaViolationConsumer.java │ │ │ │ │ ├── SpeedingViolation.java │ │ │ │ │ ├── ViolationController.java │ │ │ │ │ └── ViolationProcessor.java │ │ │ └── traffic │ │ │ │ └── violation │ │ │ │ └── SpeedingViolation.java │ │ └── finefines │ │ │ ├── FineFines.java │ │ │ └── package-info.java │ │ └── resources │ │ ├── application.yml │ │ └── finefines │ │ └── key.properties └── test.http ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── Simulation ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ └── main │ ├── java │ └── dapr │ │ └── simulation │ │ ├── DefaultTrafficControlService.java │ │ ├── HttpTrafficControlService.java │ │ ├── Simulation.java │ │ ├── SimulationApplication.java │ │ ├── SimulationConfiguration.java │ │ ├── SimulationSettings.java │ │ ├── TrafficControlService.java │ │ └── events │ │ └── VehicleRegistered.java │ └── resources │ └── application.yml ├── TrafficControlService ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src │ └── main │ │ ├── java │ │ └── dapr │ │ │ └── traffic │ │ │ ├── TrafficControlApplication.java │ │ │ ├── TrafficControlConfiguration.java │ │ │ ├── TrafficController.java │ │ │ ├── fines │ │ │ ├── DaprFineCollectionClient.java │ │ │ ├── FineCollectionClient.java │ │ │ ├── JsonObjectSerializer.java │ │ │ ├── KafkaConfig.java │ │ │ └── KafkaFineCollectionClient.java │ │ │ ├── vehicle │ │ │ ├── DaprVehicleStateRepository.java │ │ │ ├── InMemoryVehicleStateRepository.java │ │ │ ├── VehicleRegistered.java │ │ │ ├── VehicleState.java │ │ │ └── VehicleStateRepository.java │ │ │ └── violation │ │ │ ├── DefaultSpeedingViolationCalculator.java │ │ │ ├── SpeedingViolation.java │ │ │ └── SpeedingViolationCalculator.java │ │ └── resources │ │ └── application.yml └── test.http ├── VehicleRegistrationService ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src │ └── main │ │ ├── java │ │ └── dapr │ │ │ └── vehicle │ │ │ ├── InMemoryVehicleInfoRepository.java │ │ │ ├── VehicleInfo.java │ │ │ ├── VehicleInfoController.java │ │ │ ├── VehicleInfoRepository.java │ │ │ └── VehicleRegistrationApplication.java │ │ └── resources │ │ └── application.yml └── test.http ├── dapr ├── aca-azure-cosmosdb-statestore.yaml ├── aca-azure-keyvault-secretstore.yaml ├── aca-azure-servicebus-pubsub.yaml ├── aca-redis-pubsub.yaml ├── azure-cosmosdb-statestore.yaml ├── azure-keyvault-secretstore.yaml ├── azure-servicebus-pubsub.yaml ├── kafka-pubsub.yaml ├── rabbitmq-pubsub.yaml ├── redis-pubsub.yaml └── redis-statestore.yaml ├── deploy ├── collector-config.yaml ├── finecollectionservice-deployment.yaml ├── finecollectionservice-service.yaml ├── kafka-pubsub.yaml ├── kustomization.yaml ├── open-telemetry-collector-appinsights.yaml ├── simulation-deployment.yaml ├── trafficcontrolservice-deployment.yaml ├── trafficcontrolservice-service.yaml ├── vehicleregistrationservice-deployment.yaml └── vehicleregistrationservice.yaml ├── docker-compose.yml ├── docs ├── .gitignore ├── 404.html ├── Gemfile ├── Gemfile.lock ├── README.md ├── SECURITY.markdown ├── SUPPORT.md ├── _config.local.yml ├── _config.yml ├── _includes │ ├── 00-intro │ │ ├── 1-dapr-overview.md │ │ └── 2-prerequisites.md │ ├── 01-assignment-1-lab │ │ ├── 1-spring-for-apache-kafka.md │ │ └── 2-lab-instructions.md │ ├── 02-assignment-2-dapr-pub-sub │ │ └── 1-dapr-pub-sub.md │ ├── 03-assignment-3-azure-pub-sub │ │ └── 1-azure-service-bus.md │ ├── 05-assignment-5-aks-aca │ │ └── 02-aca │ │ │ ├── 0-1-setup-application-insights.md │ │ │ ├── 0-2-setup-container-apps-env.md │ │ │ ├── 0-3-test-application.md │ │ │ ├── 1-setup.md │ │ │ ├── 2-1-dapr-component-service-bus.md │ │ │ ├── 3-build-deploy-test.md │ │ │ └── 4-observability.md │ └── 09-bonus-assignments │ │ ├── 01-service-invocation │ │ ├── 1-use-dapr-to-invoke-vehicle-registration-service.md │ │ └── 3-deploy-to-aca.md │ │ ├── 02-state-store │ │ ├── 1-1-create-cosmos-db.md │ │ ├── 1-3-update-traffic-control-service.md │ │ └── 3-deploy-to-aca.md │ │ ├── 03-secret-store │ │ ├── 1-setup-azure-key-vault.md │ │ ├── 2-use-secret-store-in-code.md │ │ ├── 3-1-create-sb-connection-string-secret.md │ │ ├── 5-1-deploy-secret-store-component-to-aca.md │ │ ├── 5-2-a-rebuild-fine-collection-service.md │ │ ├── 5-2-b-1-use-secret-in-pubsub.md │ │ └── 5-2-b-2-restart-services.md │ │ ├── 04-managed-identities │ │ ├── 2-1-intro.md │ │ └── 2-2-deploy-test-and-discussion.md │ │ └── 05-scaling │ │ ├── 2-1-intro.md │ │ └── 2-2-deploy-and-test.md ├── assets │ └── images │ │ ├── aca-deployment-1.png │ │ ├── aca-deployment-2.png │ │ ├── aca-deployment-3.png │ │ ├── aca-deployment-4.png │ │ ├── aca-deployment-5.png │ │ ├── application-diagram-without-dapr.png │ │ ├── application-insights-application-map.png │ │ ├── application-with-dapr-telemetry.png │ │ ├── application-with-dapr-zipkin.png │ │ ├── dapr-setup.png │ │ ├── dapr-sidecar-model.png │ │ ├── dapr-telemetry.png │ │ ├── eclipse-external-tools-configurations.png │ │ ├── favicon.ico │ │ ├── overview.png │ │ ├── overview_kubernetes.png │ │ ├── replica-count-metric.png │ │ ├── scale-rule.png │ │ ├── sequence-dapr.png │ │ ├── sequence.png │ │ ├── speed-trap-overview.png │ │ ├── workshop-end-state.png │ │ └── zipkin-screenshot.png ├── index.markdown └── modules │ ├── 00-intro │ ├── 1-dapr-overview.md │ ├── 2-prerequisites.md │ └── index.md │ ├── 01-assignment-1-lab │ ├── 1-spring-for-apache-kafka.md │ ├── 2-lab-instructions.md │ └── index.md │ ├── 02-assignment-2-dapr-pub-sub │ └── index.md │ ├── 03-assignment-3-azure-pub-sub │ ├── 1-azure-service-bus.md │ ├── 2-azure-cache-redis.md │ └── index.md │ ├── 04-assignment-4-observability-zipkin │ └── index.md │ ├── 05-assignment-5-aks-aca │ ├── 01-aks │ │ ├── 1-dapr-sidecar-in-k8s.md │ │ ├── 2-aks-instructions.md │ │ ├── 3-observability-with-open-telemetry.md │ │ ├── 4-gitops.md │ │ └── index.md │ ├── 02-aca │ │ ├── 1-aca-instructions.md │ │ ├── 2-observability.md │ │ └── index.md │ └── index.md │ ├── 08-additional-topics │ ├── 1-prevent-port-collisions.md │ ├── 2-dapr-and-service-meshes.md │ └── index.md │ ├── 09-bonus-assignments │ ├── 01-service-invocation │ │ ├── 1-invoke-service-using-dapr.md │ │ ├── 2-deploying-to-aks.md │ │ ├── 3-deploying-to-aca.md │ │ └── index.md │ ├── 02-state-store │ │ ├── 1-azure-cosmos-db-state-store.md │ │ ├── 2-deploying-to-aks.md │ │ ├── 3-deploying-to-aca.md │ │ └── index.md │ ├── 03-secret-store │ │ ├── 1-setup-azure-key-vault.md │ │ ├── 2-use-secret-store-in-code.md │ │ ├── 3-use-secret-in-dapr-component.md │ │ ├── 5-deploying-to-aca.md │ │ └── index.md │ ├── 04-managed-identities │ │ ├── 2-managed-identities-in-aca.md │ │ └── index.md │ ├── 05-scaling │ │ ├── 2-scaling-in-aca.md │ │ └── index.md │ └── index.md │ ├── 10-cleanup │ └── index.md │ └── 11-aca-challenge │ ├── 00-intro │ ├── 1-dapr-overview.md │ ├── 2-prerequisites.md │ └── index.md │ ├── 01-assignment-1-lab │ ├── 1-spring-for-apache-kafka.md │ ├── 2-lab-instructions.md │ └── index.md │ ├── 02-assignment-2-dapr-pub-sub │ └── index.md │ ├── 03-assignment-3-azure-pub-sub │ └── index.md │ ├── 04-deploy-to-aca │ └── index.md │ ├── 05-service-invocation │ └── index.md │ ├── 06-state-store │ └── index.md │ ├── 07-secret-store │ ├── 1-setup-azure-key-vault.md │ ├── 2-use-secret-store-in-code.md │ ├── 3-use-secret-in-dapr-component.md │ └── index.md │ ├── 08-managed-identities │ └── index.md │ ├── 09-scaling │ └── index.md │ └── index.md ├── img ├── application-diagram-without-dapr.png ├── application-with-dapr-telemetry.png ├── dapr-setup.png ├── sequence-dapr.png ├── sequence.png ├── speed-trap-overview.png └── zipkin-screenshot.png ├── mvnw ├── mvnw.cmd ├── pom.xml └── scripts ├── aca_infra.ps1 ├── aca_infra.sh ├── export-variables.ps1 └── export-variables.sh /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Java Dapr-AKS-ACA Workshop", 3 | "image": "mcr.microsoft.com/devcontainers/java:1-17-bullseye", 4 | "features": { 5 | // See https://containers.dev/features for list of features 6 | "ghcr.io/devcontainers/features/docker-in-docker:2": {}, 7 | "ghcr.io/devcontainers/features/azure-cli:1": {}, 8 | "ghcr.io/azure/azure-dev/azd:latest": {}, 9 | "ghcr.io/devcontainers/features/java:1": { 10 | "version": "none", 11 | "installMaven": true, 12 | "mavenVersion": "3.8.8" 13 | }, 14 | "ghcr.io/dapr/cli/dapr-cli:0": {}, 15 | "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {} 16 | }, 17 | "customizations": { 18 | "vscode": { 19 | "extensions": [ 20 | "GitHub.vscode-github-actions", 21 | "ms-azuretools.azure-dev", 22 | "ms-azuretools.vscode-bicep", 23 | "ms-azuretools.vscode-docker", 24 | "vscjava.vscode-java-pack", 25 | "ms-azuretools.vscode-azurecontainerapps", 26 | "ms-vscode.azurecli", 27 | "ms-vscode.azure-account", 28 | "ms-kubernetes-tools.vscode-aks-tools", 29 | "ms-azure-devops.azure-pipelines", 30 | "msazurermtools.azurerm-vscode-tools", 31 | "ms-azuretools.vscode-azureresourcegroups", 32 | "ms-azuretools.vscode-dapr", 33 | "humao.rest-client" 34 | ] 35 | } 36 | }, 37 | "forwardPorts": [ 38 | // Forward ports if needed for local development 39 | ], 40 | "postCreateCommand": "", 41 | "remoteUser": "vscode", 42 | "hostRequirements": { 43 | "memory": "8gb" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | mosquitto.conf text eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | target 4 | .classpath 5 | .settings 6 | .project 7 | .factorypath 8 | .dccache 9 | _site 10 | .sass-cache 11 | .jekyll-cache 12 | .jekyll-metadata 13 | vendor 14 | dapr/components 15 | **/*.jar 16 | **/set-vars.sh 17 | **/set-vars.ps1 -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.8/apache-maven-3.8.8-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "vscjava.vscode-java-pack", 4 | "humao.rest-client" 5 | ] 6 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.compile.nullAnalysis.mode": "automatic" 3 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /FineCollectionService/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.8/apache-maven-3.8.8-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /FineCollectionService/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.infosupport.dapr 7 | dapr-workshop 8 | 1.0-SNAPSHOT 9 | 10 | fine-collection-service 11 | Fine Collection Service 12 | 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-web 17 | 18 | 19 | com.fasterxml.jackson.datatype 20 | jackson-datatype-jsr310 21 | 22 | 23 | io.dapr 24 | dapr-sdk 25 | 26 | 27 | io.dapr 28 | dapr-sdk-springboot 29 | 30 | 31 | org.springframework.kafka 32 | spring-kafka 33 | 2.8.0 34 | 35 | 36 | org.springframework.kafka 37 | spring-kafka-test 38 | 2.8.0 39 | test 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-maven-plugin 48 | 49 | dapr.fines.FineCollectionApplication 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/FineCollectionApplication.java: -------------------------------------------------------------------------------- 1 | package dapr.fines; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class FineCollectionApplication { 8 | public static void main(final String... args) { 9 | SpringApplication.run(FineCollectionApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/FineCollectionConfiguration.java: -------------------------------------------------------------------------------- 1 | package dapr.fines; 2 | 3 | import dapr.fines.fines.DaprFineCalculator; 4 | import dapr.fines.fines.DefaultFineCalculator; 5 | import dapr.fines.fines.FineCalculator; 6 | import dapr.fines.vehicle.DefaultVehicleRegistrationClient; 7 | import dapr.fines.vehicle.VehicleRegistrationClient; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.web.client.RestTemplate; 12 | import dapr.fines.vehicle.DaprVehicleRegistrationClient; 13 | import io.dapr.client.DaprClient; 14 | import io.dapr.client.DaprClientBuilder; 15 | 16 | @Configuration 17 | public class FineCollectionConfiguration { 18 | // We need to pass this key with every invocation of the FineFines library 19 | @Value("${finefines.license-key}") 20 | private String fineCalculatorLicenseKey; 21 | 22 | @Value("${vehicle-information.address}") 23 | private String vehicleInformationAddress; 24 | 25 | @Value("${vehicle-registration-service.name}") 26 | private String vehicleRegistrationServiceName; 27 | 28 | @Bean 29 | public FineCalculator fineCalculator() { 30 | return new DefaultFineCalculator(fineCalculatorLicenseKey); 31 | } 32 | 33 | // @Bean 34 | // public FineCalculator fineCalculator(final DaprClient daprClient) { 35 | // return new DaprFineCalculator(daprClient); 36 | // } 37 | 38 | @Bean 39 | public RestTemplate restTemplate() { 40 | return new RestTemplate(); 41 | } 42 | 43 | // @Bean 44 | // public VehicleRegistrationClient vehicleRegistrationClient(final DaprClient daprClient) { 45 | // return new DaprVehicleRegistrationClient(daprClient, vehicleRegistrationServiceName); 46 | // } 47 | 48 | @Bean 49 | public VehicleRegistrationClient vehicleRegistrationClient(final RestTemplate restTemplate) { 50 | return new DefaultVehicleRegistrationClient(restTemplate, vehicleInformationAddress); 51 | } 52 | 53 | // @Bean 54 | // public DaprClient daprClient() { 55 | // return new DaprClientBuilder().build(); 56 | // } 57 | } 58 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/fines/DaprFineCalculator.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.fines; 2 | 3 | import java.util.Map; 4 | 5 | import finefines.FineFines; 6 | import io.dapr.client.DaprClient; 7 | 8 | public class DaprFineCalculator implements FineCalculator { 9 | private final String fineCalculatorLicenseKey; 10 | private final FineFines fineFines; 11 | 12 | public DaprFineCalculator(final DaprClient daprClient) { 13 | if (daprClient == null) { 14 | throw new IllegalArgumentException("daprClient"); 15 | } 16 | final Map licenseKeySecret = daprClient.getSecret("secretstore", "license-key").block(); 17 | if (licenseKeySecret == null || licenseKeySecret.isEmpty()) { 18 | throw new RuntimeException("'license-key' is not part of the secret store."); 19 | } 20 | this.fineCalculatorLicenseKey = licenseKeySecret.get("license-key"); 21 | this.fineFines = new FineFines(); 22 | } 23 | 24 | @Override 25 | public int calculateFine(final int excessSpeed) { 26 | return fineFines.calculateFine(this.fineCalculatorLicenseKey, excessSpeed); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/fines/DefaultFineCalculator.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.fines; 2 | 3 | import finefines.FineFines; 4 | 5 | public class DefaultFineCalculator implements FineCalculator { 6 | private final String fineCalculatorLicenseKey; 7 | private final FineFines fineFines; 8 | 9 | public DefaultFineCalculator(final String fineCalculatorLicenseKey) { 10 | if (fineCalculatorLicenseKey == null) { 11 | throw new IllegalArgumentException("fineCalculatorLicenseKey"); 12 | } 13 | this.fineCalculatorLicenseKey = fineCalculatorLicenseKey; 14 | this.fineFines = new FineFines(); 15 | } 16 | 17 | @Override 18 | public int calculateFine(final int excessSpeed) { 19 | return fineFines.calculateFine(this.fineCalculatorLicenseKey, excessSpeed); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/fines/FineCalculator.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.fines; 2 | 3 | public interface FineCalculator { 4 | int calculateFine(int excessSpeed); 5 | } 6 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/vehicle/DaprVehicleRegistrationClient.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.vehicle; 2 | 3 | import io.dapr.client.DaprClient; 4 | import io.dapr.client.domain.HttpExtension; 5 | 6 | import java.time.Duration; 7 | 8 | public class DaprVehicleRegistrationClient implements VehicleRegistrationClient { 9 | private final DaprClient daprClient; 10 | private final String vehicleRegistrationServiceName; 11 | 12 | public DaprVehicleRegistrationClient(final DaprClient daprClient, final String vehicleRegistrationServiceName) { 13 | this.daprClient = daprClient; 14 | this.vehicleRegistrationServiceName = vehicleRegistrationServiceName; 15 | } 16 | 17 | @Override 18 | public VehicleInfo getVehicleInfo(String licenseNumber) { 19 | 20 | var result = daprClient.invokeMethod( 21 | vehicleRegistrationServiceName, 22 | "vehicleinfo/" + licenseNumber, 23 | null, 24 | HttpExtension.GET, 25 | VehicleInfo.class 26 | ); 27 | 28 | return result.block(Duration.ofMillis(1000)); 29 | } 30 | } -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/vehicle/DefaultVehicleRegistrationClient.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.vehicle; 2 | 3 | import org.springframework.web.client.RestTemplate; 4 | 5 | import java.util.Map; 6 | 7 | public class DefaultVehicleRegistrationClient implements VehicleRegistrationClient { 8 | private final RestTemplate restTemplate; 9 | private final String vehicleInformationAddress; 10 | 11 | public DefaultVehicleRegistrationClient(final RestTemplate restTemplate, 12 | final String vehicleInformationAddress) { 13 | this.restTemplate = restTemplate; 14 | this.vehicleInformationAddress = vehicleInformationAddress; 15 | } 16 | 17 | @Override 18 | public VehicleInfo getVehicleInfo(final String licenseNumber) { 19 | var params = Map.of("licenseNumber", licenseNumber); 20 | return restTemplate.getForObject(vehicleInformationAddress, VehicleInfo.class, params); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/vehicle/VehicleInfo.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.vehicle; 2 | 3 | public record VehicleInfo(String vehicleId, 4 | String make, 5 | String model, 6 | String ownerName, 7 | String ownerEmail) { 8 | } 9 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/vehicle/VehicleRegistrationClient.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.vehicle; 2 | 3 | public interface VehicleRegistrationClient { 4 | VehicleInfo getVehicleInfo(final String licenseNumber); 5 | } 6 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/violation/JsonObjectDeserializer.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.violation; 2 | 3 | import org.springframework.kafka.support.JacksonUtils; 4 | import org.springframework.kafka.support.serializer.JsonDeserializer; 5 | 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.fasterxml.jackson.databind.SerializationFeature; 8 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 9 | import dapr.traffic.violation.SpeedingViolation; 10 | 11 | public class JsonObjectDeserializer extends JsonDeserializer { 12 | 13 | public JsonObjectDeserializer() { 14 | super(customizedObjectMapper()); 15 | } 16 | 17 | private static ObjectMapper customizedObjectMapper() { 18 | ObjectMapper mapper = JacksonUtils.enhancedObjectMapper(); 19 | // mapper.registerModule(new JavaTimeModule()); 20 | // mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 21 | return mapper; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/violation/KafkaConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.violation; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.apache.kafka.clients.consumer.ConsumerConfig; 7 | import org.apache.kafka.common.serialization.StringDeserializer; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.kafka.annotation.EnableKafka; 11 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 12 | import org.springframework.kafka.core.ConsumerFactory; 13 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory; 14 | import org.springframework.kafka.support.serializer.JsonDeserializer; 15 | import dapr.traffic.violation.SpeedingViolation; 16 | 17 | @EnableKafka 18 | @Configuration 19 | public class KafkaConsumerConfig { 20 | 21 | @Bean 22 | public ConsumerFactory consumerFactory() { 23 | Map props = new HashMap<>(); 24 | props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092"); 25 | props.put(ConsumerConfig.GROUP_ID_CONFIG, "test"); 26 | props.put(JsonObjectDeserializer.TRUSTED_PACKAGES, "*"); 27 | return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), 28 | new JsonObjectDeserializer()); 29 | } 30 | 31 | @Bean 32 | public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { 33 | ConcurrentKafkaListenerContainerFactory 34 | factory = new ConcurrentKafkaListenerContainerFactory<>(); 35 | factory.setConsumerFactory(consumerFactory()); 36 | return factory; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/violation/KafkaViolationConsumer.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.violation; 2 | 3 | import org.springframework.kafka.annotation.KafkaListener; 4 | import org.springframework.stereotype.Component; 5 | import dapr.traffic.violation.SpeedingViolation; 6 | 7 | @Component 8 | public class KafkaViolationConsumer { 9 | private final ViolationProcessor violationProcessor; 10 | 11 | public KafkaViolationConsumer(final ViolationProcessor violationProcessor) { 12 | this.violationProcessor = violationProcessor; 13 | } 14 | 15 | @KafkaListener(topics = "test", groupId = "test", containerFactory = "kafkaListenerContainerFactory") 16 | public void listen(SpeedingViolation violation) { 17 | 18 | violationProcessor.processSpeedingViolation(violation); 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/violation/SpeedingViolation.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.violation; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public record SpeedingViolation(String licenseNumber, 6 | String roadId, 7 | int excessSpeed /* in km/h */, 8 | LocalDateTime timestamp) { 9 | } 10 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/violation/ViolationController.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.violation; 2 | 3 | import org.springframework.http.ResponseEntity; 4 | 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import com.fasterxml.jackson.databind.JsonNode; 9 | import java.time.LocalDateTime; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import java.util.Collections; 12 | import java.util.List; 13 | import java.util.Map; 14 | import dapr.traffic.violation.SpeedingViolation; 15 | 16 | import io.dapr.Topic; 17 | import io.dapr.client.domain.CloudEvent; 18 | 19 | //@RestController 20 | public class ViolationController { 21 | private final ViolationProcessor violationProcessor; 22 | 23 | public ViolationController(final ViolationProcessor violationProcessor) { 24 | this.violationProcessor = violationProcessor; 25 | } 26 | 27 | 28 | // @PostMapping(path = "/collectfine") 29 | // @Topic(name = "test", pubsubName = "pubsub") 30 | // public ResponseEntity registerViolation(@RequestBody final CloudEvent event) { 31 | // var violation = event.getData(); 32 | // violationProcessor.processSpeedingViolation(violation); 33 | // return ResponseEntity.ok().build(); 34 | // } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/fines/violation/ViolationProcessor.java: -------------------------------------------------------------------------------- 1 | package dapr.fines.violation; 2 | 3 | import dapr.fines.fines.FineCalculator; 4 | import dapr.fines.vehicle.VehicleInfo; 5 | import dapr.fines.vehicle.VehicleRegistrationClient; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.time.format.DateTimeFormatter; 11 | import dapr.traffic.violation.SpeedingViolation; 12 | 13 | @Component 14 | public class ViolationProcessor { 15 | private static final Logger log = LoggerFactory.getLogger(ViolationProcessor.class); 16 | 17 | private final FineCalculator fineCalculator; 18 | private final VehicleRegistrationClient vehicleRegistrationClient; 19 | 20 | public ViolationProcessor(final FineCalculator fineCalculator, 21 | final VehicleRegistrationClient vehicleRegistrationClient) { 22 | this.fineCalculator = fineCalculator; 23 | this.vehicleRegistrationClient = vehicleRegistrationClient; 24 | } 25 | 26 | public void processSpeedingViolation(final SpeedingViolation violation) { 27 | var fine = fineCalculator.calculateFine(violation.excessSpeed()); 28 | var fineText = fine == -1 ? "to be decided by the prosecutor" : String.format("EUR %.2f", (float) fine); 29 | var vehicleInfo = vehicleRegistrationClient.getVehicleInfo(violation.licenseNumber()); 30 | 31 | // Send notification of fine by email 32 | // TODO 33 | 34 | log.info(constructLogMessage(violation, vehicleInfo, fineText)); 35 | } 36 | 37 | private final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("LLLL, dd y"); 38 | private final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss"); 39 | private String constructLogMessage(final SpeedingViolation violation, final VehicleInfo vehicleInfo, final String fineText) { 40 | var date = DATE_FORMAT.format(violation.timestamp()); 41 | var time = TIME_FORMAT.format(violation.timestamp()); 42 | 43 | return String.format(""" 44 | Sent fine notification 45 | \t\t\tTo %s, registered owner of license number %s. 46 | \t\t\tViolation of %d km/h detected on the %s road on %s at %s. 47 | \t\t\tFine: %s.%n 48 | """, 49 | vehicleInfo.ownerName(), 50 | violation.licenseNumber(), 51 | violation.excessSpeed(), 52 | violation.roadId(), 53 | date, 54 | time, 55 | fineText 56 | ); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/dapr/traffic/violation/SpeedingViolation.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.violation; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public record SpeedingViolation(String licenseNumber, 6 | String roadId, 7 | int excessSpeed /* in km/h */, 8 | LocalDateTime timestamp) { 9 | } 10 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/finefines/FineFines.java: -------------------------------------------------------------------------------- 1 | package finefines; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.IOException; 7 | import java.util.Properties; 8 | 9 | public class FineFines { 10 | private static final Logger log = LoggerFactory.getLogger(FineFines.class); 11 | 12 | private final String expectedLicenseKey; 13 | 14 | public FineFines() { 15 | try (var stream = getClass().getResourceAsStream("/finefines/key.properties")) { 16 | var properties = new Properties(); 17 | properties.load(stream); 18 | this.expectedLicenseKey = properties.getProperty("finefines.licenseKey"); 19 | } catch (final IOException ioe) { 20 | log.error("Can't determine FineFines license key: {}", ioe.getLocalizedMessage()); 21 | throw new IllegalStateException("Can't determine FineFines license key"); 22 | } 23 | } 24 | 25 | public int calculateFine(final String licenseKey, final int excessSpeed) { 26 | if (!expectedLicenseKey.equals(licenseKey)) { 27 | throw new IllegalArgumentException("No valid license key supplied"); 28 | } 29 | 30 | int fine = 9; // default administration charges 31 | if (excessSpeed < 5) { 32 | fine += 18; 33 | } else if (excessSpeed < 10) { 34 | fine += 31; 35 | } else if (excessSpeed < 15) { 36 | fine += 64; 37 | } else if (excessSpeed < 20) { 38 | fine += 121; 39 | } else if (excessSpeed < 25) { 40 | fine += 174; 41 | } else if (excessSpeed < 30) { 42 | fine += 232; 43 | } else if (excessSpeed < 35) { 44 | fine += 297; 45 | } else if (excessSpeed == 35) { 46 | fine += 372; 47 | } else { 48 | // violation above 35 km/h will be determined by the prosecutor 49 | return -1; 50 | } 51 | 52 | return fine; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FineCollectionService/src/main/java/finefines/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * External library that calculates the fine to pay for a given excess speed. 3 | */ 4 | package finefines; -------------------------------------------------------------------------------- /FineCollectionService/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jackson: 3 | serialization: 4 | write-dates-as-timestamps: false 5 | main: 6 | banner-mode: off 7 | 8 | server: 9 | port: 6001 10 | 11 | finefines: 12 | license-key: HX783-5PN1G-CRJ4A-K2L7V 13 | 14 | vehicle-information.address: ${VEHICLE_REGISTRATION_SERVICE_BASE_URL:http://${VEHICLE_REGISTRATION_SERVICE:localhost}:6002}/vehicleinfo/{licenseNumber} 15 | # Used for service discovery when service invocation is used 16 | vehicle-registration-service.name: ${VEHICLE_REGISTRATION_SERVICE:vehicleregistrationservice} -------------------------------------------------------------------------------- /FineCollectionService/src/main/resources/finefines/key.properties: -------------------------------------------------------------------------------- 1 | finefines.licenseKey=HX783-5PN1G-CRJ4A-K2L7V -------------------------------------------------------------------------------- /FineCollectionService/test.http: -------------------------------------------------------------------------------- 1 | // Publish speeding violation 2 | POST http://127.0.0.1:6001/collectfine 3 | Content-Type: application/json 4 | 5 | { "licenseNumber": "RT-318-K", "roadId": "A12", "excessSpeed": 15, "timestamp": "2020-09-20T08:33:41" } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Dapr-AKS-ACA Workshop 2 | 3 | [![Open in GitHub Codespaces](https://img.shields.io/badge/Github_Codespaces-Open-black?style=for-the-badge&logo=github 4 | )](https://codespaces.new/Azure/java-aks-aca-dapr-workshop) 5 | [![Open in Remote - Dev Containers](https://img.shields.io/badge/Dev_Containers-Open-blue?style=for-the-badge&logo=visualstudiocode 6 | )](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/Azure/java-aks-aca-dapr-workshop) 7 | 8 | ## Introduction 9 | 10 | This workshop teaches you how to apply [Dapr](https://dapr.io) to a Java microservices application and enable developers to move between multiple pub-sub, state stores and secret store components seamlessly. It also demonstrates Dapr's builtin support for [distributed tracing](https://docs.dapr.io/concepts/observability-concept/) using any backend monitoring tools. Finally, the workshop provides hands on experience in deploying the microservices in both [Azure Kubernetes Service (AKS)](https://docs.microsoft.com/en-us/azure/aks/) and [Azure Contaner Apps](https://learn.microsoft.com/en-us/azure/container-apps/overview) 11 | 12 | ### The domain 13 | 14 | For the assignments you will be working with a speeding-camera setup as can be found on several Dutch highways. This is an overview of the fictitious setup you're simulating: 15 | 16 | ![Speeding cameras](img/speed-trap-overview.png) 17 | 18 | There's 1 entry-camera and 1 exit-camera per lane. When a car passes an entry-camera, the license-number of the car and the timestamp is registered. 19 | 20 | When the car passes an exit-camera, this timestamp is also registered by the system. The system then calculates the average speed of the car based on the entry- and exit-timestamp. If a speeding violation is detected, a message is sent to the Central Fine Collection Agency (or CJIB in Dutch). They will retrieve the information of the owner of the vehicle and send him or her a fine. 21 | 22 | 23 | ## Workshop 24 | 25 | The workshop is available [here](https://azure.github.io/java-aks-aca-dapr-workshop/). 26 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /Simulation/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.8/apache-maven-3.8.8-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /Simulation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.infosupport.dapr 7 | dapr-workshop 8 | 1.0-SNAPSHOT 9 | 10 | simulation 11 | 1.0-SNAPSHOT 12 | Simulation 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter 18 | 19 | 20 | org.springframework 21 | spring-web 22 | 23 | 24 | com.fasterxml.jackson.core 25 | jackson-databind 26 | 27 | 28 | com.fasterxml.jackson.datatype 29 | jackson-datatype-jsr310 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-maven-plugin 38 | 39 | dapr.simulation.SimulationApplication 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/DefaultTrafficControlService.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation; 2 | 3 | import dapr.simulation.events.VehicleRegistered; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.http.HttpEntity; 7 | import org.springframework.http.HttpHeaders; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.web.client.RestClientException; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | public class DefaultTrafficControlService implements TrafficControlService { 13 | private static final Logger log = LoggerFactory.getLogger(DefaultTrafficControlService.class); 14 | 15 | private final String trafficEntryAddress; 16 | private final String trafficExitAddress; 17 | private final RestTemplate restTemplate; 18 | 19 | public DefaultTrafficControlService(final String trafficEntryAddress, 20 | final String trafficExitAddress, 21 | final RestTemplate restTemplate) { 22 | this.trafficEntryAddress = trafficEntryAddress; 23 | this.trafficExitAddress = trafficExitAddress; 24 | this.restTemplate = restTemplate; 25 | } 26 | 27 | @Override 28 | public void sendVehicleEntry(final VehicleRegistered vehicleRegistered) { 29 | var headers = new HttpHeaders(); 30 | headers.setContentType(MediaType.APPLICATION_JSON); 31 | var entity = new HttpEntity<>(vehicleRegistered, headers); 32 | 33 | try { 34 | restTemplate.postForObject(trafficEntryAddress, entity, Void.class); 35 | } catch (RestClientException rce) { 36 | log.error("Could not register entry for license number {}: {}", vehicleRegistered.licenseNumber(), 37 | rce.getLocalizedMessage()); 38 | } 39 | } 40 | 41 | @Override 42 | public void sendVehicleExit(final VehicleRegistered vehicleRegistered) { 43 | var headers = new HttpHeaders(); 44 | headers.setContentType(MediaType.APPLICATION_JSON); 45 | var entity = new HttpEntity<>(vehicleRegistered, headers); 46 | 47 | try { 48 | restTemplate.postForObject(trafficExitAddress, entity, Void.class); 49 | } catch (RestClientException rce) { 50 | log.error("Could not register exit for license number {}: {}", vehicleRegistered.licenseNumber(), 51 | rce.getLocalizedMessage()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/HttpTrafficControlService.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation; 2 | 3 | import dapr.simulation.events.VehicleRegistered; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.http.HttpEntity; 7 | import org.springframework.http.HttpHeaders; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.web.client.RestClientException; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | public class HttpTrafficControlService implements TrafficControlService { 13 | private static final Logger log = LoggerFactory.getLogger(HttpTrafficControlService.class); 14 | 15 | private final String trafficEntryAddress; 16 | private final String trafficExitAddress; 17 | private final RestTemplate restTemplate; 18 | 19 | public HttpTrafficControlService(final String trafficEntryAddress, 20 | final String trafficExitAddress, 21 | final RestTemplate restTemplate) { 22 | this.trafficEntryAddress = trafficEntryAddress; 23 | this.trafficExitAddress = trafficExitAddress; 24 | this.restTemplate = restTemplate; 25 | } 26 | 27 | @Override 28 | public void sendVehicleEntry(final VehicleRegistered vehicleRegistered) { 29 | var headers = new HttpHeaders(); 30 | headers.setContentType(MediaType.APPLICATION_JSON); 31 | var entity = new HttpEntity<>(vehicleRegistered, headers); 32 | 33 | try { 34 | restTemplate.postForObject(trafficEntryAddress, entity, Void.class); 35 | } catch (RestClientException rce) { 36 | log.error("Could not register entry for license number {}: {}", vehicleRegistered.licenseNumber(), 37 | rce.getLocalizedMessage()); 38 | } 39 | } 40 | 41 | @Override 42 | public void sendVehicleExit(final VehicleRegistered vehicleRegistered) { 43 | var headers = new HttpHeaders(); 44 | headers.setContentType(MediaType.APPLICATION_JSON); 45 | var entity = new HttpEntity<>(vehicleRegistered, headers); 46 | 47 | try { 48 | restTemplate.postForObject(trafficExitAddress, entity, Void.class); 49 | } catch (RestClientException rce) { 50 | log.error("Could not register exit for license number {}: {}", vehicleRegistered.licenseNumber(), 51 | rce.getLocalizedMessage()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/SimulationApplication.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation; 2 | 3 | import org.springframework.boot.WebApplicationType; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 7 | 8 | @EnableConfigurationProperties({ SimulationSettings.class }) 9 | @SpringBootApplication 10 | public class SimulationApplication { 11 | public static void main(String[] args) { 12 | new SpringApplicationBuilder(SimulationApplication.class) 13 | .web(WebApplicationType.NONE) 14 | .run(args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/SimulationConfiguration.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | 11 | @Configuration 12 | public class SimulationConfiguration { 13 | private final SimulationSettings settings; 14 | private final String trafficEntryAddress; 15 | private final String trafficExitAddress; 16 | 17 | public SimulationConfiguration(final SimulationSettings settings, 18 | @Value("${traffic-control.entry.address}") final String trafficEntryAddress, 19 | @Value("${traffic-control.exit.address}") final String trafficExitAddress) { 20 | this.settings = settings; 21 | this.trafficEntryAddress = trafficEntryAddress; 22 | this.trafficExitAddress = trafficExitAddress; 23 | } 24 | 25 | @Bean 26 | public RestTemplate restTemplate() { 27 | return new RestTemplate(); 28 | } 29 | 30 | @Bean 31 | public ExecutorService executorService() { 32 | return Executors.newFixedThreadPool(settings.getNumLanes()); 33 | } 34 | 35 | @Bean 36 | public TrafficControlService trafficControlService(final RestTemplate restTemplate) { 37 | return new HttpTrafficControlService(trafficEntryAddress, trafficExitAddress, restTemplate); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/SimulationSettings.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.boot.context.properties.ConstructorBinding; 5 | 6 | @ConstructorBinding 7 | @ConfigurationProperties("simulation") 8 | public class SimulationSettings { 9 | private final int numLanes; 10 | private final DelaySettings entryDelay; 11 | private final DelaySettings exitDelay; 12 | 13 | public SimulationSettings(final int numLanes, 14 | final DelaySettings entryDelay, 15 | final DelaySettings exitDelay) { 16 | this.numLanes = numLanes; 17 | this.entryDelay = entryDelay; 18 | this.exitDelay = exitDelay; 19 | } 20 | 21 | public int getNumLanes() { 22 | return numLanes; 23 | } 24 | 25 | public DelaySettings getEntryDelay() { 26 | return entryDelay; 27 | } 28 | 29 | public DelaySettings getExitDelay() { 30 | return exitDelay; 31 | } 32 | 33 | @ConstructorBinding 34 | static class DelaySettings { 35 | private final int minimum; 36 | private final int maximum; 37 | 38 | public DelaySettings(final int minimum, final int maximum) { 39 | this.minimum = minimum; 40 | this.maximum = maximum; 41 | } 42 | 43 | public int getMinimum() { 44 | return minimum; 45 | } 46 | 47 | public int getMaximum() { 48 | return maximum; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/TrafficControlService.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation; 2 | 3 | import dapr.simulation.events.VehicleRegistered; 4 | 5 | public interface TrafficControlService { 6 | void sendVehicleEntry(final VehicleRegistered vehicleRegistered); 7 | void sendVehicleExit(final VehicleRegistered vehicleRegistered); 8 | } 9 | -------------------------------------------------------------------------------- /Simulation/src/main/java/dapr/simulation/events/VehicleRegistered.java: -------------------------------------------------------------------------------- 1 | package dapr.simulation.events; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public record VehicleRegistered(int lane, 6 | String licenseNumber, 7 | LocalDateTime timestamp) { 8 | } 9 | -------------------------------------------------------------------------------- /Simulation/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jackson: 3 | serialization: 4 | write-dates-as-timestamps: false 5 | main: 6 | banner-mode: off 7 | 8 | simulation: 9 | # How much traffic lanes and cameras to simulate 10 | num-lanes: 3 11 | # Minimum and maximum delay before a new vehicle enters a lane (in milliseconds) 12 | entry-delay: 13 | minimum: 50 14 | maximum: 3000 15 | # Minimum and maximum delay after which a vehicle exits the lane (in seconds) 16 | exit-delay: 17 | minimum: 4 18 | maximum: 8 19 | 20 | # Traffic Control Service configuration 21 | # - For local development, use the default configuration => do not set anything 22 | # - For Kubernetes cluster the name of the service can be set to TRAFFIC_CONTROL_SERVICE. 23 | # - For Azure Container Apps with Ingress on Traffic Control Service or other deployments, you can use 24 | # TRAFFIC_CONTROL_SERVICE_BASE_URL to set the URL of the service 25 | traffic-control.entry.address: ${TRAFFIC_CONTROL_SERVICE_BASE_URL:http://${TRAFFIC_CONTROL_SERVICE:localhost}:6000}/entrycam 26 | traffic-control.exit.address: ${TRAFFIC_CONTROL_SERVICE_BASE_URL:http://${TRAFFIC_CONTROL_SERVICE:localhost}:6000}/exitcam 27 | -------------------------------------------------------------------------------- /TrafficControlService/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.8/apache-maven-3.8.8-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /TrafficControlService/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.infosupport.dapr 6 | dapr-workshop 7 | 1.0-SNAPSHOT 8 | 9 | traffic-control-service 10 | 1.0-SNAPSHOT 11 | Traffic Control Service 12 | 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-web 17 | 18 | 19 | com.fasterxml.jackson.datatype 20 | jackson-datatype-jsr310 21 | 22 | 23 | io.dapr 24 | dapr-sdk 25 | 26 | 27 | org.springframework.kafka 28 | spring-kafka 29 | 2.8.0 30 | 31 | 32 | org.springframework.kafka 33 | spring-kafka-test 34 | 2.8.0 35 | test 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-maven-plugin 44 | 45 | dapr.traffic.TrafficControlApplication 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/TrafficControlApplication.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TrafficControlApplication { 8 | public static void main(final String... args) { 9 | SpringApplication.run(TrafficControlApplication.class, args); 10 | } 11 | } -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/TrafficControlConfiguration.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic; 2 | 3 | import dapr.traffic.fines.FineCollectionClient; 4 | import dapr.traffic.fines.KafkaFineCollectionClient; 5 | import dapr.traffic.vehicle.DaprVehicleStateRepository; 6 | import dapr.traffic.vehicle.InMemoryVehicleStateRepository; 7 | import dapr.traffic.vehicle.VehicleStateRepository; 8 | import dapr.traffic.violation.DefaultSpeedingViolationCalculator; 9 | import dapr.traffic.violation.SpeedingViolationCalculator; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.boot.web.client.RestTemplateBuilder; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 15 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | import com.fasterxml.jackson.databind.SerializationFeature; 19 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 20 | import dapr.traffic.fines.DaprFineCollectionClient; 21 | import io.dapr.client.DaprClient; 22 | import io.dapr.client.DaprClientBuilder; 23 | import io.dapr.serializer.DefaultObjectSerializer; 24 | 25 | 26 | 27 | @Configuration 28 | public class TrafficControlConfiguration { 29 | 30 | static class JsonObjectSerializer extends DefaultObjectSerializer { 31 | public JsonObjectSerializer() { 32 | OBJECT_MAPPER.registerModule(new JavaTimeModule()); 33 | OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 34 | } 35 | } 36 | 37 | @Value("${traffic.road-id}") 38 | private String roadId; 39 | 40 | @Value("${traffic.section-length}") 41 | private int sectionLength; 42 | 43 | @Value("${traffic.speed-limit}") 44 | private int speedLimit; 45 | 46 | @Value("${traffic.legal-correction}") 47 | private int legalCorrection; 48 | 49 | 50 | @Bean 51 | public VehicleStateRepository vehicleStateRepository() { 52 | return new InMemoryVehicleStateRepository(); 53 | } 54 | 55 | @Bean 56 | public SpeedingViolationCalculator speedingViolationCalculator() { 57 | return new DefaultSpeedingViolationCalculator(legalCorrection, speedLimit, roadId, sectionLength); 58 | } 59 | 60 | // @Bean 61 | // public FineCollectionClient fineCollectionClient(final DaprClient daprClient) { 62 | // return new DaprFineCollectionClient(daprClient); 63 | // } 64 | 65 | @Bean 66 | public FineCollectionClient fineCollectionClient() { 67 | return new KafkaFineCollectionClient(); 68 | } 69 | 70 | // @Bean 71 | // public DaprClient daprClient() { 72 | // return new DaprClientBuilder() 73 | // .withObjectSerializer(new JsonObjectSerializer()) 74 | // .build(); 75 | // } 76 | } 77 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/fines/DaprFineCollectionClient.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.fines; 2 | 3 | import dapr.traffic.violation.SpeedingViolation; 4 | import io.dapr.client.DaprClient; 5 | 6 | public class DaprFineCollectionClient implements FineCollectionClient{ 7 | private final DaprClient daprClient; 8 | 9 | public DaprFineCollectionClient(final DaprClient daprClient) { 10 | this.daprClient = daprClient; 11 | } 12 | 13 | @Override 14 | public void submitForFine(SpeedingViolation speedingViolation) { 15 | 16 | 17 | daprClient.publishEvent("pubsub", "test", speedingViolation).block(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/fines/FineCollectionClient.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.fines; 2 | 3 | import dapr.traffic.violation.SpeedingViolation; 4 | 5 | public interface FineCollectionClient { 6 | void submitForFine(final SpeedingViolation speedingViolation); 7 | } 8 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/fines/JsonObjectSerializer.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.fines; 2 | 3 | import org.springframework.kafka.support.JacksonUtils; 4 | import org.springframework.kafka.support.serializer.JsonDeserializer; 5 | import org.springframework.kafka.support.serializer.JsonSerializer; 6 | 7 | //import com.fasterxml.jackson.databind.JsonSerializer; 8 | import com.fasterxml.jackson.databind.ObjectMapper; 9 | import com.fasterxml.jackson.databind.SerializationFeature; 10 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 11 | 12 | import dapr.traffic.violation.SpeedingViolation; 13 | 14 | public class JsonObjectSerializer extends JsonSerializer { 15 | 16 | public JsonObjectSerializer() { 17 | super(customizedObjectMapper()); 18 | } 19 | 20 | private static ObjectMapper customizedObjectMapper() { 21 | ObjectMapper mapper = JacksonUtils.enhancedObjectMapper(); 22 | mapper.registerModule(new JavaTimeModule()); 23 | mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 24 | return mapper; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/fines/KafkaConfig.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.fines; 2 | 3 | import dapr.traffic.violation.SpeedingViolation; 4 | import dapr.traffic.fines.JsonObjectSerializer; 5 | import io.dapr.serializer.DefaultObjectSerializer; 6 | 7 | import org.apache.kafka.clients.producer.ProducerConfig; 8 | import org.apache.kafka.common.serialization.StringSerializer; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.kafka.core.DefaultKafkaProducerFactory; 12 | import org.springframework.kafka.core.KafkaTemplate; 13 | import org.springframework.kafka.core.ProducerFactory; 14 | import org.springframework.kafka.support.serializer.JsonSerializer; 15 | 16 | import com.fasterxml.jackson.databind.SerializationFeature; 17 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | @Configuration 23 | public class KafkaConfig { 24 | 25 | @Bean 26 | public ProducerFactory producerFactory() { 27 | Map config = new HashMap<>(); 28 | config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092"); 29 | config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 30 | config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonObjectSerializer.class); 31 | return new DefaultKafkaProducerFactory(config); 32 | } 33 | 34 | @Bean 35 | public KafkaTemplate kafkaTemplate() { 36 | return new KafkaTemplate(producerFactory()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/fines/KafkaFineCollectionClient.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.fines; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.kafka.core.KafkaTemplate; 5 | 6 | import dapr.traffic.violation.SpeedingViolation; 7 | 8 | public class KafkaFineCollectionClient implements FineCollectionClient { 9 | 10 | @Autowired 11 | private KafkaTemplate kafkaTemplate; 12 | 13 | @Override 14 | public void submitForFine(SpeedingViolation speedingViolation) { 15 | kafkaTemplate.send("test", speedingViolation); 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/vehicle/DaprVehicleStateRepository.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.vehicle; 2 | 3 | import io.dapr.client.DaprClient; 4 | import reactor.core.publisher.Mono; 5 | 6 | import java.util.Optional; 7 | 8 | public class DaprVehicleStateRepository implements VehicleStateRepository { 9 | 10 | private static final String DAPR_STORE_NAME = "statestore"; 11 | 12 | private final DaprClient daprClient; 13 | 14 | public DaprVehicleStateRepository(final DaprClient daprClient) { 15 | this.daprClient = daprClient; 16 | } 17 | 18 | @Override 19 | public VehicleState saveVehicleState(VehicleState vehicleState) { 20 | daprClient.saveState(DAPR_STORE_NAME, vehicleState.licenseNumber(), vehicleState).block(); 21 | Mono> result = daprClient.getState(DAPR_STORE_NAME, vehicleState.licenseNumber(), VehicleState.class); 22 | return result.block().getValue(); 23 | } 24 | 25 | @Override 26 | public Optional getVehicleState(String licenseNumber) { 27 | Mono> result = daprClient.getState(DAPR_STORE_NAME, licenseNumber, VehicleState.class); 28 | return Optional.ofNullable(result.block().getValue()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/vehicle/InMemoryVehicleStateRepository.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.vehicle; 2 | 3 | import java.util.Map; 4 | import java.util.Optional; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | public class InMemoryVehicleStateRepository implements VehicleStateRepository { 8 | private final Map state = new ConcurrentHashMap<>(); 9 | 10 | @Override 11 | public VehicleState saveVehicleState(final VehicleState vehicleState) { 12 | return state.merge(vehicleState.licenseNumber(), vehicleState, (oldValue, newValue) -> newValue); 13 | } 14 | 15 | @Override 16 | public Optional getVehicleState(final String licenseNumber) { 17 | return Optional.ofNullable(state.get(licenseNumber)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/vehicle/VehicleRegistered.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.vehicle; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public record VehicleRegistered(int lane, 6 | String licenseNumber, 7 | LocalDateTime timestamp) { 8 | } 9 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/vehicle/VehicleState.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.vehicle; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public record VehicleState(String licenseNumber, 6 | LocalDateTime entryTimestamp, 7 | LocalDateTime exitTimestamp) { 8 | public VehicleState(final String licenseNumber, final LocalDateTime entryTimestamp) { 9 | this(licenseNumber, entryTimestamp, null); 10 | } 11 | 12 | public VehicleState withExit(final LocalDateTime timestamp) { 13 | return new VehicleState(licenseNumber, entryTimestamp, timestamp); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/vehicle/VehicleStateRepository.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.vehicle; 2 | 3 | import java.util.Optional; 4 | 5 | public interface VehicleStateRepository { 6 | VehicleState saveVehicleState(final VehicleState vehicleState); 7 | Optional getVehicleState(final String licenseNumber); 8 | } 9 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/violation/DefaultSpeedingViolationCalculator.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.violation; 2 | 3 | import java.time.Duration; 4 | import java.time.LocalDateTime; 5 | 6 | public class DefaultSpeedingViolationCalculator implements SpeedingViolationCalculator { 7 | private final int legalCorrectionInKmh; 8 | private final int maxAllowedSpeedInKmh; 9 | private final String roadId; 10 | private final int sectionLengthInKm; 11 | 12 | public DefaultSpeedingViolationCalculator(final int legalCorrectionInKmh, 13 | final int maxAllowedSpeedInKmh, 14 | final String roadId, 15 | final int sectionLengthInKm) { 16 | this.legalCorrectionInKmh = legalCorrectionInKmh; 17 | this.maxAllowedSpeedInKmh = maxAllowedSpeedInKmh; 18 | this.roadId = roadId; 19 | this.sectionLengthInKm = sectionLengthInKm; 20 | } 21 | 22 | @Override 23 | public int determineExcessSpeed(final LocalDateTime entryTimestamp, final LocalDateTime exitTimestamp) { 24 | // In this simulation, 1 second clock time == 1 minute simulation time. 25 | final long elapsedMinutes = Duration.between(entryTimestamp, exitTimestamp).getSeconds(); 26 | final double elapsedHours = (double) elapsedMinutes / 60; 27 | final double avgSpeedInKmh = sectionLengthInKm / elapsedHours; 28 | 29 | final int violation = (int) (avgSpeedInKmh - (double) maxAllowedSpeedInKmh - (double) legalCorrectionInKmh); 30 | return Math.max(0, violation); // never return negative violation, doesn't make sense 31 | } 32 | 33 | @Override 34 | public String getRoadId() { 35 | return this.roadId; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/violation/SpeedingViolation.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.violation; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public record SpeedingViolation(String licenseNumber, 6 | String roadId, 7 | int excessSpeed, 8 | LocalDateTime timestamp) { 9 | } 10 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/java/dapr/traffic/violation/SpeedingViolationCalculator.java: -------------------------------------------------------------------------------- 1 | package dapr.traffic.violation; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public interface SpeedingViolationCalculator { 6 | int determineExcessSpeed(final LocalDateTime entryTimestamp, final LocalDateTime exitTimestamp); 7 | String getRoadId(); 8 | } 9 | -------------------------------------------------------------------------------- /TrafficControlService/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jackson: 3 | serialization: 4 | write-dates-as-timestamps: false 5 | main: 6 | banner-mode: off 7 | 8 | server: 9 | port: 6000 10 | 11 | traffic: 12 | # Identifier of the road - free text 13 | road-id: A12 14 | # Length of the track - in kilometers 15 | section-length: 10 16 | # Speed limit - in kilometers/hour 17 | speed-limit: 100 18 | # Legal correction - in kilometers/hour 19 | legal-correction: 5 20 | 21 | -------------------------------------------------------------------------------- /TrafficControlService/test.http: -------------------------------------------------------------------------------- 1 | // Register entry 2 | POST http://127.0.0.1:6000/entrycam 3 | Content-Type: application/json 4 | 5 | { "lane": 1, "licenseNumber": "XT-346-Y", "timestamp": "2020-09-10T10:38:47" } 6 | 7 | ### 8 | 9 | // Register exit (without violation) 10 | POST http://127.0.0.1:6000/exitcam 11 | Content-Type: application/json 12 | 13 | { "lane": 1, "licenseNumber": "XT-346-Y", "timestamp": "2020-09-10T10:38:53" } 14 | 15 | ### 16 | 17 | // Register exit (with violation) 18 | POST http://127.0.0.1:6000/exitcam 19 | Content-Type: application/json 20 | 21 | { "lane": 1, "licenseNumber": "XT-346-Y", "timestamp": "2020-09-10T10:38:52" } 22 | -------------------------------------------------------------------------------- /VehicleRegistrationService/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.8/apache-maven-3.8.8-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 19 | -------------------------------------------------------------------------------- /VehicleRegistrationService/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.infosupport.dapr 7 | dapr-workshop 8 | 1.0-SNAPSHOT 9 | 10 | vehicle-registration-service 11 | 1.0-SNAPSHOT 12 | Vehicle Registration Service 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.ajbrown 21 | name-machine 22 | 1.0.0 23 | 24 | 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-maven-plugin 31 | 32 | dapr.vehicle.VehicleRegistrationApplication 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /VehicleRegistrationService/src/main/java/dapr/vehicle/InMemoryVehicleInfoRepository.java: -------------------------------------------------------------------------------- 1 | package dapr.vehicle; 2 | 3 | import org.ajbrown.namemachine.NameGenerator; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.security.SecureRandom; 7 | import java.util.Map; 8 | import java.util.Random; 9 | 10 | @Component 11 | public class InMemoryVehicleInfoRepository implements VehicleInfoRepository { 12 | private final Random random = new SecureRandom(); 13 | 14 | private final String[] vehicleMakes = new String[] { 15 | "Mercedes", "Toyota", "Audi", "Volkswagen", "Seat", "Renault", "Skoda", 16 | "Kia", "Citroën", "Suzuki", "Mitsubishi", "Fiat", "Opel" 17 | }; 18 | 19 | private final Map modelsByMake = Map.ofEntries( 20 | Map.entry("Mercedes", new String[] { "A Class", "B Class", "C Class", "E Class", "SLS", "SLK" }), 21 | Map.entry("Toyota", new String[] { "Yaris", "Avensis", "Rav 4", "Prius", "Celica" }), 22 | Map.entry("Audi", new String[] { "A3", "A4", "A6", "A8", "Q5", "Q7" }), 23 | Map.entry("Volkswagen", new String[] { "Golf", "Pasat", "Tiguan", "Caddy" }), 24 | Map.entry("Seat", new String[] { "Leon", "Arona", "Ibiza", "Alhambra" }), 25 | Map.entry("Renault", new String[] { "Megane", "Clio", "Twingo", "Scenic", "Captur" }), 26 | Map.entry("Skoda", new String[] { "Octavia", "Fabia", "Superb", "Karoq", "Kodiaq" }), 27 | Map.entry("Kia", new String[] { "Picanto", "Rio", "Ceed", "XCeed", "Niro", "Sportage" }), 28 | Map.entry("Citroën", new String[] { "C1", "C2", "C3", "C4", "C4 Cactus", "Berlingo" }), 29 | Map.entry("Suzuki", new String[] { "Ignis", "Swift", "Vitara", "S-Cross", "Swace", "Jimny" }), 30 | Map.entry("Mitsubishi", new String[] { "Space Star", "ASX", "Eclipse Cross", "Outlander PHEV" }), 31 | Map.entry("Ford", new String[] { "Focus", "Ka", "C-Max", "Fusion", "Fiesta", "Mondeo", "Kuga" }), 32 | Map.entry("BMW", new String[] { "1 Serie", "2 Serie", "3 Serie", "5 Serie", "7 Serie", "X5" }), 33 | Map.entry("Fiat", new String[] { "500", "Panda", "Punto", "Tipo", "Multipla" }), 34 | Map.entry("Opel", new String[] { "Karl", "Corsa", "Astra", "Crossland X", "Insignia" }) 35 | ); 36 | 37 | private final NameGenerator nameGenerator = new NameGenerator(); 38 | 39 | @Override 40 | public VehicleInfo getVehicleInfo(final String licenseNumber) { 41 | var make = selectRandom(vehicleMakes); 42 | var model = selectRandom(modelsByMake.get(make)); 43 | var name = nameGenerator.generateNames(1).get(0).toString(); 44 | var email = name.toLowerCase().replace(' ', '.') + "@gmail.com"; 45 | 46 | return new VehicleInfo( 47 | licenseNumber, 48 | make, 49 | model, 50 | name, 51 | email 52 | ); 53 | } 54 | 55 | private String selectRandom(final String[] options) { 56 | var idx = random.nextInt(options.length); 57 | return options[idx]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /VehicleRegistrationService/src/main/java/dapr/vehicle/VehicleInfo.java: -------------------------------------------------------------------------------- 1 | package dapr.vehicle; 2 | 3 | public record VehicleInfo(String vehicleId, 4 | String make, 5 | String model, 6 | String ownerName, 7 | String ownerEmail) { 8 | } 9 | 10 | -------------------------------------------------------------------------------- /VehicleRegistrationService/src/main/java/dapr/vehicle/VehicleInfoController.java: -------------------------------------------------------------------------------- 1 | package dapr.vehicle; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class VehicleInfoController { 12 | private static final Logger log = LoggerFactory.getLogger(VehicleInfoController.class); 13 | 14 | private final VehicleInfoRepository vehicleInfoRepository; 15 | 16 | public VehicleInfoController(final VehicleInfoRepository vehicleInfoRepository) { 17 | this.vehicleInfoRepository = vehicleInfoRepository; 18 | } 19 | 20 | @GetMapping("/vehicleinfo/{licenseNumber}") 21 | public ResponseEntity getVehicleInformation(@PathVariable("licenseNumber") final String licenseNumber) { 22 | log.info("Retrieving vehicle-info for license number {}", licenseNumber); 23 | var info = vehicleInfoRepository.getVehicleInfo(licenseNumber); 24 | return ResponseEntity.ok(info); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /VehicleRegistrationService/src/main/java/dapr/vehicle/VehicleInfoRepository.java: -------------------------------------------------------------------------------- 1 | package dapr.vehicle; 2 | 3 | public interface VehicleInfoRepository { 4 | VehicleInfo getVehicleInfo(final String licenseNumber); 5 | } 6 | -------------------------------------------------------------------------------- /VehicleRegistrationService/src/main/java/dapr/vehicle/VehicleRegistrationApplication.java: -------------------------------------------------------------------------------- 1 | package dapr.vehicle; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class VehicleRegistrationApplication { 8 | public static void main(final String... args) { 9 | SpringApplication.run(VehicleRegistrationApplication.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /VehicleRegistrationService/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jackson: 3 | serialization: 4 | write-dates-as-timestamps: false 5 | main: 6 | banner-mode: off 7 | 8 | server: 9 | port: 6002 10 | -------------------------------------------------------------------------------- /VehicleRegistrationService/test.http: -------------------------------------------------------------------------------- 1 | // Get vehicle info by license-number 2 | GET http://127.0.0.1:6002/vehicleinfo/KZ-49-VX 3 | -------------------------------------------------------------------------------- /dapr/aca-azure-cosmosdb-statestore.yaml: -------------------------------------------------------------------------------- 1 | componentType: state.azure.cosmosdb 2 | version: v1 3 | metadata: 4 | - name: url 5 | value: 6 | - name: masterKey 7 | value: 8 | - name: database 9 | value: dapr-workshop-java-database 10 | - name: collection 11 | value: vehicle-state 12 | - name: actorStateStore 13 | value: "true" 14 | scopes: 15 | - traffic-control-service 16 | -------------------------------------------------------------------------------- /dapr/aca-azure-keyvault-secretstore.yaml: -------------------------------------------------------------------------------- 1 | componentType: secretstores.azure.keyvault 2 | version: v1 3 | metadata: 4 | - name: vaultName 5 | value: "[your_keyvault_name]" 6 | - name: azureTenantId 7 | value: "[your_tenant_id]" 8 | - name: azureClientId 9 | value: "[your_client_id]" 10 | - name: azureClientSecret 11 | secretRef: azure-client-secret 12 | secrets: 13 | - name: azure-client-secret 14 | value: "[your_client_secret]" 15 | scopes: 16 | - traffic-control-service 17 | - fine-collection-service -------------------------------------------------------------------------------- /dapr/aca-azure-servicebus-pubsub.yaml: -------------------------------------------------------------------------------- 1 | componentType: pubsub.azure.servicebus 2 | version: v1 3 | metadata: 4 | - name: connectionString 5 | value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}" 6 | scopes: 7 | - traffic-control-service 8 | - fine-collection-service 9 | -------------------------------------------------------------------------------- /dapr/aca-redis-pubsub.yaml: -------------------------------------------------------------------------------- 1 | componentType: pubsub.redis 2 | version: v1 3 | metadata: 4 | - name: redisHost 5 | value: : 6 | - name: redisPassword 7 | value: 8 | - name: enableTLS 9 | value: "true" 10 | scopes: 11 | - traffic-control-service 12 | - fine-collection-service 13 | -------------------------------------------------------------------------------- /dapr/azure-cosmosdb-statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.azure.cosmosdb 7 | version: v1 8 | metadata: 9 | - name: url 10 | value: 11 | - name: masterKey 12 | value: 13 | - name: database 14 | value: dapr-workshop-java-database 15 | - name: collection 16 | value: vehicle-state 17 | - name: actorStateStore 18 | value: "true" 19 | scopes: 20 | - trafficcontrolservice -------------------------------------------------------------------------------- /dapr/azure-keyvault-secretstore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: secretstore 5 | spec: 6 | type: secretstores.azure.keyvault 7 | version: v1 8 | metadata: 9 | - name: vaultName 10 | value: "[your_keyvault_name]" 11 | - name: azureTenantId 12 | value: "[your_tenant_id]" 13 | - name: azureClientId 14 | value: "[your_client_id]" 15 | - name: azureClientSecret 16 | value : "[your_client_secret]" 17 | -------------------------------------------------------------------------------- /dapr/azure-servicebus-pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | spec: 6 | type: pubsub.azure.servicebus 7 | version: v1 8 | metadata: 9 | - name: connectionString # Required when not using Azure Authentication. 10 | value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}" 11 | scopes: 12 | - trafficcontrolservice 13 | - finecollectionservice -------------------------------------------------------------------------------- /dapr/kafka-pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | # namespace: default 6 | spec: 7 | type: pubsub.kafka 8 | version: v1 9 | metadata: 10 | - name: brokers # Required. Kafka broker connection setting 11 | value: "localhost:9092" 12 | # - name: consumerGroup # Optional. Used for input bindings. 13 | # value: "test" 14 | # - name: clientID # Optional. Used as client tracing ID by Kafka brokers. 15 | # value: "my-dapr-app-id" 16 | # - name: authType # Required. 17 | - name: authRequired 18 | value: "false" 19 | - name: maxMessageBytes # Optional. 20 | value: 1024 21 | - name: consumeRetryInterval # Optional. 22 | value: 200ms 23 | # - name: version # Optional. 24 | # value: 0.10.2.0 25 | - name: disableTls # Optional. Disable TLS. This is not safe for production!! You should read the `Mutual TLS` section for how to use TLS. 26 | value: "true" 27 | 28 | -------------------------------------------------------------------------------- /dapr/rabbitmq-pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | spec: 6 | type: pubsub.rabbitmq 7 | version: v1 8 | metadata: 9 | - name: host 10 | value: "amqp://localhost:5672" 11 | - name: durable 12 | value: "false" 13 | - name: deletedWhenUnused 14 | value: "false" 15 | - name: autoAck 16 | value: "false" 17 | - name: reconnectWait 18 | value: "0" 19 | - name: concurrency 20 | value: parallel 21 | scopes: 22 | - trafficcontrolservice 23 | - finecollectionservice -------------------------------------------------------------------------------- /dapr/redis-pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | spec: 6 | type: pubsub.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: : 11 | - name: redisPassword 12 | value: 13 | - name: enableTLS 14 | value: "true" 15 | scopes: 16 | - trafficcontrolservice 17 | - finecollectionservice -------------------------------------------------------------------------------- /dapr/redis-statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: statestore 5 | spec: 6 | type: state.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | - name: actorStateStore 14 | value: "true" 15 | scopes: 16 | - trafficcontrolservice 17 | -------------------------------------------------------------------------------- /deploy/collector-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Configuration 3 | metadata: 4 | name: appconfig 5 | namespace: default 6 | spec: 7 | tracing: 8 | samplingRate: "1" 9 | zipkin: 10 | endpointAddress: "http://otel-collector.default.svc.cluster.local:9411/api/v2/spans" -------------------------------------------------------------------------------- /deploy/finecollectionservice-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: finecollectionservice 7 | name: finecollectionservice 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: finecollectionservice 13 | strategy: {} 14 | template: 15 | metadata: 16 | creationTimestamp: null 17 | labels: 18 | app: finecollectionservice 19 | annotations: 20 | dapr.io/enabled: "true" 21 | dapr.io/app-id: "finecollectionservice" 22 | dapr.io/app-port: "6001" 23 | spec: 24 | containers: 25 | - image: .azurecr.io/fine-collection-service:latest 26 | name: fine-collection-service 27 | resources: {} 28 | env: 29 | - name: VEHICLE_REGISTRATION_SERVICE 30 | value: vehicleregistrationservice 31 | status: {} 32 | -------------------------------------------------------------------------------- /deploy/finecollectionservice-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: finecollectionservice 6 | name: finecollectionservice 7 | spec: 8 | ports: 9 | - name: 6001-6001 10 | port: 6001 11 | protocol: TCP 12 | targetPort: 6001 13 | selector: 14 | app: finecollectionservice 15 | type: ClusterIP 16 | status: 17 | loadBalancer: {} -------------------------------------------------------------------------------- /deploy/kafka-pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: pubsub 5 | namespace: default 6 | spec: 7 | type: pubsub.kafka 8 | version: v1 9 | metadata: 10 | - name: brokers # Required. Kafka broker connection setting 11 | value: my-release-kafka.default.svc.cluster.local:9092 12 | - name: consumerGroup # Optional. Used for input bindings. 13 | value: "test" 14 | # - name: clientID # Optional. Used as client tracing ID by Kafka brokers. 15 | # value: "my-dapr-app-id" 16 | - name: authRequired 17 | value: "false" 18 | # - name: maxMessageBytes # Optional. 19 | # value: 1024 20 | # - name: consumeRetryInterval # Optional. 21 | # value: 200ms 22 | # - name: version # Optional. 23 | # value: 0.10.2.0 24 | - name: disableTls # Optional. Disable TLS. This is not safe for production!! You should read the `Mutual TLS` section for how to use TLS. 25 | value: "true" 26 | -------------------------------------------------------------------------------- /deploy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | namespace: default 4 | resources: 5 | - finecollectionservice-deployment.yaml 6 | - finecollectionservice-service.yaml 7 | - kafka-pubsub.yaml 8 | - simulation-deployment.yaml 9 | - trafficcontrolservice-deployment.yaml 10 | - trafficcontrolservice-service.yaml 11 | - vehicleregistrationservice-deployment.yaml 12 | - vehicleregistrationservice.yaml -------------------------------------------------------------------------------- /deploy/open-telemetry-collector-appinsights.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: otel-collector-conf 5 | labels: 6 | app: opentelemetry 7 | component: otel-collector-conf 8 | data: 9 | otel-collector-config: | 10 | receivers: 11 | zipkin: 12 | endpoint: 0.0.0.0:9411 13 | extensions: 14 | health_check: 15 | pprof: 16 | endpoint: :1888 17 | zpages: 18 | endpoint: :55679 19 | exporters: 20 | logging: 21 | loglevel: debug 22 | azuremonitor: 23 | endpoint: "https://dc.services.visualstudio.com/v2/track" 24 | instrumentation_key: "" 25 | # maxbatchsize is the maximum number of items that can be 26 | # queued before calling to the configured endpoint 27 | maxbatchsize: 100 28 | # maxbatchinterval is the maximum time to wait before calling 29 | # the configured endpoint. 30 | maxbatchinterval: 10s 31 | service: 32 | extensions: [pprof, zpages, health_check] 33 | pipelines: 34 | traces: 35 | receivers: [zipkin] 36 | exporters: [azuremonitor,logging] 37 | --- 38 | apiVersion: v1 39 | kind: Service 40 | metadata: 41 | name: otel-collector 42 | labels: 43 | app: opencesus 44 | component: otel-collector 45 | spec: 46 | ports: 47 | - name: zipkin # Default endpoint for Zipkin receiver. 48 | port: 9411 49 | protocol: TCP 50 | targetPort: 9411 51 | selector: 52 | component: otel-collector 53 | --- 54 | apiVersion: apps/v1 55 | kind: Deployment 56 | metadata: 57 | name: otel-collector 58 | labels: 59 | app: opentelemetry 60 | component: otel-collector 61 | spec: 62 | replicas: 1 # scale out based on your usage 63 | selector: 64 | matchLabels: 65 | app: opentelemetry 66 | template: 67 | metadata: 68 | labels: 69 | app: opentelemetry 70 | component: otel-collector 71 | spec: 72 | containers: 73 | - name: otel-collector 74 | image: otel/opentelemetry-collector-contrib:0.50.0 75 | command: 76 | - "/otelcol-contrib" 77 | - "--config=/conf/otel-collector-config.yaml" 78 | resources: 79 | limits: 80 | cpu: 1 81 | memory: 2Gi 82 | requests: 83 | cpu: 200m 84 | memory: 400Mi 85 | ports: 86 | - containerPort: 9411 # Default endpoint for Zipkin receiver. 87 | volumeMounts: 88 | - name: otel-collector-config-vol 89 | mountPath: /conf 90 | livenessProbe: 91 | httpGet: 92 | path: / 93 | port: 13133 94 | readinessProbe: 95 | httpGet: 96 | path: / 97 | port: 13133 98 | volumes: 99 | - configMap: 100 | name: otel-collector-conf 101 | items: 102 | - key: otel-collector-config 103 | path: otel-collector-config.yaml 104 | name: otel-collector-config-vol -------------------------------------------------------------------------------- /deploy/simulation-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: simulation 7 | name: simulation 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: simulation 13 | strategy: {} 14 | template: 15 | metadata: 16 | creationTimestamp: null 17 | labels: 18 | app: simulation 19 | spec: 20 | containers: 21 | - image: .azurecr.io/simulation:latest 22 | name: simulation 23 | resources: {} 24 | env: 25 | - name: TRAFFIC_CONTROL_SERVICE 26 | value: trafficcontrolservice 27 | status: {} 28 | -------------------------------------------------------------------------------- /deploy/trafficcontrolservice-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: trafficcontrolservice 7 | name: trafficcontrolservice 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: trafficcontrolservice 13 | strategy: {} 14 | template: 15 | metadata: 16 | creationTimestamp: null 17 | labels: 18 | app: trafficcontrolservice 19 | annotations: 20 | dapr.io/enabled: "true" 21 | dapr.io/app-id: "trafficcontrolservice" 22 | dapr.io/app-port: "6000" 23 | spec: 24 | containers: 25 | - image: .azurecr.io/traffic-control-service:latest 26 | name: traffic-control-service 27 | resources: {} 28 | status: {} 29 | -------------------------------------------------------------------------------- /deploy/trafficcontrolservice-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: trafficcontrolservice 7 | name: trafficcontrolservice 8 | spec: 9 | ports: 10 | - name: 6000-6000 11 | port: 6000 12 | protocol: TCP 13 | targetPort: 6000 14 | selector: 15 | app: trafficcontrolservice 16 | type: ClusterIP 17 | status: 18 | loadBalancer: {} 19 | -------------------------------------------------------------------------------- /deploy/vehicleregistrationservice-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: vehicleregistrationservice 7 | name: vehicleregistrationservice 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: vehicleregistrationservice 13 | strategy: {} 14 | template: 15 | metadata: 16 | creationTimestamp: null 17 | labels: 18 | app: vehicleregistrationservice 19 | # annotations: 20 | # dapr.io/enabled: "true" 21 | # dapr.io/app-id: "vehicleregistrationservice" 22 | # dapr.io/app-port: "6002" 23 | spec: 24 | containers: 25 | - image: .azurecr.io/vehicle-registration-service:latest 26 | name: vehicle-registration-service 27 | resources: {} 28 | status: {} 29 | -------------------------------------------------------------------------------- /deploy/vehicleregistrationservice.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: vehicleregistrationservice 7 | name: vehicleregistrationservice 8 | spec: 9 | ports: 10 | - name: 6002-6002 11 | port: 6002 12 | protocol: TCP 13 | targetPort: 6002 14 | selector: 15 | app: vehicleregistrationservice 16 | type: ClusterIP 17 | status: 18 | loadBalancer: {} 19 | 20 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | zookeeper: 4 | image: 'bitnami/zookeeper:3.8.0' 5 | ports: 6 | - '2181:2181' 7 | environment: 8 | - ALLOW_ANONYMOUS_LOGIN=yes 9 | kafka: 10 | image: 'bitnami/kafka:3.3.1' 11 | ports: 12 | - '9092:9092' 13 | environment: 14 | - KAFKA_BROKER_ID=1 15 | - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092 16 | - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092 17 | - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 18 | - ALLOW_PLAINTEXT_LISTENER=yes 19 | depends_on: 20 | - zookeeper -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | *.local.* -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found :(

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | gem "jekyll", "~> 4.2.2" 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 12 | gem "minima", "~> 2.5" 13 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 14 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 15 | # gem "github-pages", group: :jekyll_plugins 16 | # If you have any plugins, put them here! 17 | group :jekyll_plugins do 18 | gem "jekyll-feed", "~> 0.12" 19 | end 20 | 21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem 22 | # and associated library. 23 | platforms :mingw, :x64_mingw, :mswin, :jruby do 24 | gem "tzinfo", "~> 1.2" 25 | gem "tzinfo-data" 26 | end 27 | 28 | # Performance-booster for watching directories on Windows 29 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 30 | 31 | # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem 32 | # do not have a Java counterpart. 33 | gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] 34 | 35 | gem "just-the-docs", "0.4.0.rc4" 36 | 37 | gem "webrick", "~> 1.7" 38 | -------------------------------------------------------------------------------- /docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.8.1) 5 | public_suffix (>= 2.0.2, < 6.0) 6 | colorator (1.1.0) 7 | concurrent-ruby (1.1.10) 8 | em-websocket (0.5.3) 9 | eventmachine (>= 0.12.9) 10 | http_parser.rb (~> 0) 11 | eventmachine (1.2.7) 12 | ffi (1.15.5) 13 | forwardable-extended (2.6.0) 14 | http_parser.rb (0.8.0) 15 | i18n (1.12.0) 16 | concurrent-ruby (~> 1.0) 17 | jekyll (4.2.2) 18 | addressable (~> 2.4) 19 | colorator (~> 1.0) 20 | em-websocket (~> 0.5) 21 | i18n (~> 1.0) 22 | jekyll-sass-converter (~> 2.0) 23 | jekyll-watch (~> 2.0) 24 | kramdown (~> 2.3) 25 | kramdown-parser-gfm (~> 1.0) 26 | liquid (~> 4.0) 27 | mercenary (~> 0.4.0) 28 | pathutil (~> 0.9) 29 | rouge (~> 3.0) 30 | safe_yaml (~> 1.0) 31 | terminal-table (~> 2.0) 32 | jekyll-feed (0.17.0) 33 | jekyll (>= 3.7, < 5.0) 34 | jekyll-sass-converter (2.2.0) 35 | sassc (> 2.0.1, < 3.0) 36 | jekyll-seo-tag (2.8.0) 37 | jekyll (>= 3.8, < 5.0) 38 | jekyll-watch (2.2.1) 39 | listen (~> 3.0) 40 | just-the-docs (0.4.0.rc4) 41 | jekyll (>= 3.8.5) 42 | jekyll-seo-tag (>= 2.0) 43 | rake (>= 12.3.1) 44 | kramdown (2.4.0) 45 | rexml 46 | kramdown-parser-gfm (1.1.0) 47 | kramdown (~> 2.0) 48 | liquid (4.0.3) 49 | listen (3.8.0) 50 | rb-fsevent (~> 0.10, >= 0.10.3) 51 | rb-inotify (~> 0.9, >= 0.9.10) 52 | mercenary (0.4.0) 53 | minima (2.5.1) 54 | jekyll (>= 3.5, < 5.0) 55 | jekyll-feed (~> 0.9) 56 | jekyll-seo-tag (~> 2.1) 57 | pathutil (0.16.2) 58 | forwardable-extended (~> 2.6) 59 | public_suffix (5.0.1) 60 | rake (13.0.6) 61 | rb-fsevent (0.11.2) 62 | rb-inotify (0.10.1) 63 | ffi (~> 1.0) 64 | rexml (3.2.5) 65 | rouge (3.30.0) 66 | safe_yaml (1.0.5) 67 | sassc (2.4.0) 68 | ffi (~> 1.9) 69 | terminal-table (2.0.0) 70 | unicode-display_width (~> 1.1, >= 1.1.1) 71 | unicode-display_width (1.8.0) 72 | webrick (1.7.0) 73 | 74 | PLATFORMS 75 | x86_64-linux 76 | 77 | DEPENDENCIES 78 | http_parser.rb (~> 0.6.0) 79 | jekyll (~> 4.2.2) 80 | jekyll-feed (~> 0.12) 81 | just-the-docs (= 0.4.0.rc4) 82 | minima (~> 2.5) 83 | tzinfo (~> 1.2) 84 | tzinfo-data 85 | wdm (~> 0.1.1) 86 | webrick (~> 1.7) 87 | 88 | BUNDLED WITH 89 | 2.4.3 90 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Java Dapr-AKS-ACA Workshop Documentation 2 | 3 | ## Generate locally 4 | 5 | To generate the documentation locally, [Ruby](https://www.ruby-lang.org/) and [Ruby Gems](https://rubygems.org/) are required. 6 | 7 | Jekyll and Bundler are required to generate the documentation locally. To [install](https://jekyllrb.com/docs/installation/) them, run the following commands: 8 | 9 | ```bash 10 | gem install jekyll bundler 11 | ``` 12 | 13 | To run a local server, run the following command: 14 | 15 | ```bash 16 | bundle install 17 | bundle exec jekyll serve --config _config.local.yml 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/SECURITY.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | nav_exclude: true 3 | --- 4 | 5 | 6 | 7 | ## Security 8 | 9 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 10 | 11 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 12 | 13 | ## Reporting Security Issues 14 | 15 | **Please do not report security vulnerabilities through public GitHub issues.** 16 | 17 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 18 | 19 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 20 | 21 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 22 | 23 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 24 | 25 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 26 | * Full paths of source file(s) related to the manifestation of the issue 27 | * The location of the affected source code (tag/branch/commit or direct URL) 28 | * Any special configuration required to reproduce the issue 29 | * Step-by-step instructions to reproduce the issue 30 | * Proof-of-concept or exploit code (if possible) 31 | * Impact of the issue, including how an attacker might exploit the issue 32 | 33 | This information will help us triage your report more quickly. 34 | 35 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 36 | 37 | ## Preferred Languages 38 | 39 | We prefer all communications to be in English. 40 | 41 | ## Policy 42 | 43 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 44 | 45 | -------------------------------------------------------------------------------- /docs/SUPPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | nav_exclude: true 3 | --- 4 | 5 | # Support 6 | 7 | ## How to file issues and get help 8 | 9 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 10 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 11 | feature request as a new Issue. 12 | 13 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 14 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 15 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 16 | 17 | ## Microsoft Support Policy 18 | 19 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. -------------------------------------------------------------------------------- /docs/_includes/00-intro/1-dapr-overview.md: -------------------------------------------------------------------------------- 1 | Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to build resilient, stateless and stateful microservices that run on the cloud and edge and embraces the diversity of languages and developer frameworks. 2 | 3 | Dapr codifies the *best practices* for building microservice applications into open, independent, building blocks that enable you to build portable applications with the language and framework of your choice. Each building block is independent and you can use one, some, or all of them in your application. 4 | 5 | ![Dapr overview]({{ include.relativeAssetsPath }}images/overview.png) 6 | 7 | ## How it works 8 | 9 | Dapr injects a side-car (container or process) to each compute unit. The side-car interacts with event triggers and communicates with the compute unit via standard HTTP or gRPC protocols. This enables Dapr to support all existing and future programming languages without requiring you to import frameworks or libraries. 10 | 11 | Dapr offers built-in state management, reliable messaging (at least once delivery), triggers and bindings through standard HTTP verbs or gRPC interfaces. This allows you to write stateless, stateful and actor-like services following the same programming paradigm. You can freely choose consistency model, threading model and message delivery patterns. 12 | 13 | Dapr runs natively on Kubernetes, as a self hosted binary on your machine, on an IoT device, or as a container that can be injected into any system, in the cloud or on-premises. 14 | 15 | Dapr uses pluggable component state stores and message buses such as Redis as well as gRPC to offer a wide range of communication methods, including direct dapr-to-dapr using gRPC and async Pub-Sub with guaranteed delivery and at-least-once semantics. 16 | -------------------------------------------------------------------------------- /docs/_includes/05-assignment-5-aks-aca/02-aca/0-1-setup-application-insights.md: -------------------------------------------------------------------------------- 1 | 1. Create an Application Insights resource: 2 | 3 | ```bash 4 | az monitor app-insights component create --app appi-dapr-workshop-java --location eastus --kind web -g rg-dapr-workshop-java --application-type web 5 | ``` 6 | 7 | You may receive a message to install the application-insights extension, if so please install the extension for this exercise. 8 | 9 | 1. Get the instrumentation key for the Application Insights and set it to the `INSTRUMENTATION_KEY` variable: 10 | 11 | - Linux/Unix shell: 12 | 13 | ```bash 14 | INSTRUMENTATION_KEY=$(az monitor app-insights component show --app appi-dapr-workshop-java -g rg-dapr-workshop-java --query instrumentationKey) 15 | echo $INSTRUMENTATION_KEY 16 | ``` 17 | 18 | - PowerShell: 19 | 20 | ```powershell 21 | $INSTRUMENTATION_KEY = az monitor app-insights component show --app appi-dapr-workshop-java -g rg-dapr-workshop-java --query instrumentationKey 22 | $INSTRUMENTATION_KEY 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/_includes/05-assignment-5-aks-aca/02-aca/0-2-setup-container-apps-env.md: -------------------------------------------------------------------------------- 1 | 3 | A [container apps environment](https://learn.microsoft.com/en-us/azure/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. 4 | 5 | {% if include.showObservability %} 6 | 7 | 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: 8 | 9 | ```bash 10 | az containerapp env create \ 11 | --resource-group rg-dapr-workshop-java \ 12 | --location eastus \ 13 | --name cae-dapr-workshop-java \ 14 | --logs-workspace-id "$LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID" \ 15 | --logs-workspace-key "$LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET" \ 16 | --dapr-instrumentation-key "$INSTRUMENTATION_KEY" 17 | ``` 18 | 19 | {% else %} 20 | 21 | {: .important-title } 22 | > Dapr Telemetry 23 | > 24 | > If you want to enable Dapr telemetry, you need to create the container apps environment with Application Insights. You can follow these instructions instead of the instructions below: [(Optional) Observability with Dapr using Application Insights]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/2-observability.md %}) 25 | > 26 | 27 | Create the container apps environment with the following command: 28 | 29 | ```bash 30 | az containerapp env create \ 31 | --resource-group rg-dapr-workshop-java \ 32 | --location eastus \ 33 | --name cae-dapr-workshop-java \ 34 | --logs-workspace-id "$LOG_ANALYTICS_WORKSPACE_CUSTOMER_ID" \ 35 | --logs-workspace-key "$LOG_ANALYTICS_WORKSPACE_CLIENT_SECRET" 36 | ``` 37 | 38 | {% endif %} 39 | 40 | {: .note } 41 | > 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. 42 | > 43 | -------------------------------------------------------------------------------- /docs/_includes/05-assignment-5-aks-aca/02-aca/2-1-dapr-component-service-bus.md: -------------------------------------------------------------------------------- 1 | {% if include.linkType == "aca-challenge" %} 2 | 3 | In [Assignment 3 - Using Dapr for pub/sub with Azure Service Bus]({{ site.baseurl }}{% link modules/11-aca-challenge/03-assignment-3-azure-pub-sub/index.md %}), 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. 4 | 5 | {% else %} 6 | 7 | In [Assignment 3 - Using Dapr for pub/sub with Azure Service Bus]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}), 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. 8 | 9 | {% endif %} 10 | 11 | The [Dapr component schema for Azure Container Apps](https://learn.microsoft.com/en-us/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#component-schema) is different from the standard Dapr component yaml schema. It has been slightly simplified. Hence the need for a new component yaml file. 12 | 13 | 1. Open the file `dapr/aca-azure-servicebus-pubsub.yaml` in your code editor. 14 | 15 | ```yaml 16 | componentType: pubsub.azure.servicebus 17 | version: v1 18 | metadata: 19 | - name: connectionString 20 | value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}" 21 | scopes: 22 | - traffic-control-service 23 | - fine-collection-service 24 | ``` 25 | 26 | 2. **Copy or Move** this file `dapr/aca-servicebus-pubsub.yaml` to `dapr/components` folder. 27 | 28 | {% if include.linkType == "aca-challenge" %} 29 | 30 | 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]({{ site.baseurl }}{% link modules/11-aca-challenge/03-assignment-3-azure-pub-sub/index.md %}). 31 | 32 | {% else %} 33 | 34 | 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]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}). 35 | 36 | {% endif %} 37 | 38 | 4. Go to the root folder of the repository. 39 | 40 | 5. Enter the following command to deploy the `pubsub` Dapr component: 41 | 42 | ```bash 43 | az containerapp env dapr-component set \ 44 | --name cae-dapr-workshop-java \ 45 | --resource-group rg-dapr-workshop-java \ 46 | --dapr-component-name pubsub \ 47 | --yaml ./dapr/components/aca-azure-servicebus-pubsub.yaml 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/_includes/05-assignment-5-aks-aca/02-aca/4-observability.md: -------------------------------------------------------------------------------- 1 | ## Step {{stepNumber}}: View the telemetry in Application Insights 2 | 3 | 1. Open the Application Insights resource in the [Azure portal]([https](https://portal.azure.com/)). 4 | 5 | 1. Go to `Application Map`, you should see a diagram like the on below 6 | 7 | ![Dapr Telemetry]({{ include.relativeAssetsPath }}images/dapr-telemetry.png) 8 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/01-service-invocation/1-use-dapr-to-invoke-vehicle-registration-service.md: -------------------------------------------------------------------------------- 1 | 3 | ## Step {{stepNumber}}: Use Dapr to invoke the Vehicle Registration Service from the Fine Collection Service 4 | 5 | With Dapr, services can invoke other services using their application id. This is done by using the Dapr client to make calls to the Dapr sidecar. The Vehicle Registration Service will be started with a Dapr sidecar. 6 | 7 | 1. Open the `FineCollectionService` project in your code editor and navigate to the `DaprVehicleRegistrationClient` class. This class implements the `VehicleRegistrationClient` interface and uses the Dapr client to invoke the Vehicle Registration Service. Inspect the implementation of this class. 8 | 9 | 2. Navigate to the `FineCollectionConfiguration` class to switch between the default and Dapr implementation of the `VehicleRegistrationClient`. 10 | 11 | 3. **Uncomment** following @Bean method: 12 | 13 | ```java 14 | // @Bean 15 | // public VehicleRegistrationClient vehicleRegistrationClient(final DaprClient daprClient) { 16 | // return new DaprVehicleRegistrationClient(daprClient); 17 | // } 18 | ``` 19 | 20 | 4. **Uncomment** following @Bean method, if not already done: 21 | 22 | ```java 23 | // @Bean 24 | // public DaprClient daprClient() { 25 | // return new DaprClientBuilder().build(); 26 | // } 27 | ``` 28 | 29 | 5. **Comment out** following @Bean method: 30 | 31 | ```java 32 | @Bean 33 | public VehicleRegistrationClient vehicleRegistrationClient(final RestTemplate restTemplate) { 34 | return new DefaultVehicleRegistrationClient(restTemplate, vehicleInformationAddress); 35 | } 36 | ``` 37 | 38 | 6. Check all your code-changes are correct by building the code. Execute the following command in the terminal window: 39 | 40 | ```bash 41 | mvn package 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/02-state-store/1-1-create-cosmos-db.md: -------------------------------------------------------------------------------- 1 | 1. Open a terminal window. 2 | 3 | 1. Azure Cosmos DB account for SQL API is a globally distributed multi-model database service. This account needs to be globally unique. Use the following command to generate a unique name: 4 | 5 | - Linux/Unix shell: 6 | 7 | ```bash 8 | UNIQUE_IDENTIFIER=$(LC_ALL=C tr -dc a-z0-9 The name of the Cosmos DB account must be unique across all Azure Cosmos DB accounts in the world. If you get an error that the name is already taken, try a different name. In the following steps, please update the name of the Cosmos DB account accordingly. 30 | 31 | 1. Create a SQL API database: 32 | 33 | ```bash 34 | az cosmosdb sql database create --account-name $COSMOS_DB --resource-group rg-dapr-workshop-java --name dapr-workshop-java-database 35 | ``` 36 | 37 | 1. Create a SQL API container: 38 | 39 | ```bash 40 | az cosmosdb sql container create --account-name $COSMOS_DB --resource-group rg-dapr-workshop-java --database-name dapr-workshop-java-database --name vehicle-state --partition-key-path /partitionKey --throughput 400 41 | ``` 42 | 43 | {: .important } 44 | > The partition key path is `/partitionKey` as mentionned in [Dapr documentation](https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-azure-cosmosdb/#setup-azure-cosmosdb). 45 | > 46 | 47 | 1. Get the Cosmos DB account URL and note it down. You will need it in the next step and to deploy it to Azure. 48 | 49 | ```bash 50 | az cosmosdb show --name $COSMOS_DB --resource-group rg-dapr-workshop-java --query documentEndpoint -o tsv 51 | ``` 52 | 53 | 1. Get the master key and note it down. You will need it in the next step and to deploy it to Azure. 54 | 55 | ```bash 56 | az cosmosdb keys list --name $COSMOS_DB --resource-group rg-dapr-workshop-java --type keys --query primaryMasterKey -o tsv 57 | ``` -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/02-state-store/1-3-update-traffic-control-service.md: -------------------------------------------------------------------------------- 1 | 1. Open the `TrafficControlService` project in your code editor and navigate to the `DaprVehicleStateRepository` class. This class use the Dapr client to store and retrieve the state of a vehicle. Inspect the implementation of this class. 2 | 3 | 1. Navigate to the `TrafficControlConfiguration` class to swith from the `InMemoryVehicleStateRepository` to the `DaprVehicleStateRepository`. 4 | 5 | 1. **Update** @Bean method to instantiate `DaprVehicleStateRepository` instead of `InMemoryVehicleStateRepository`: 6 | 7 | ```java 8 | @Bean 9 | public VehicleStateRepository vehicleStateRepository(final DaprClient daprClient) { 10 | return new DaprVehicleStateRepository(daprClient); 11 | } 12 | ``` 13 | 14 | 1. **Uncomment** following @Bean method if not already done: 15 | 16 | ```java 17 | // @Bean 18 | // public DaprClient daprClient() { 19 | // return new DaprClientBuilder() 20 | // .withObjectSerializer(new JsonObjectSerializer()) 21 | // .build(); 22 | // } 23 | ``` 24 | 25 | 1. Check all your code-changes are correct by building the code. Execute the following command in the terminal window: 26 | 27 | ```bash 28 | mvn package 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/02-state-store/3-deploy-to-aca.md: -------------------------------------------------------------------------------- 1 | 3 | ## Step {{stepNumber}}: Build and redeploy traffic control service 4 | 5 | In this step, you will rebuild and redeploy the `TrafficControlService` to use the Azure Cosmos DB state store instead of keeping the state in memory. 6 | 7 | 1. Delete the image from local docker: 8 | 9 | ```bash 10 | docker rmi traffic-control-service:1.0-SNAPSHOT 11 | ``` 12 | 13 | 1. In the root folder of `TrafficControlService`, run the following command to build and push the image: 14 | 15 | ```bash 16 | mvn spring-boot:build-image 17 | docker tag traffic-control-service:1.0-SNAPSHOT "$CONTAINER_REGISTRY.azurecr.io/traffic-control-service:2.0" 18 | docker push "$CONTAINER_REGISTRY.azurecr.io/traffic-control-service:2.0" 19 | ``` 20 | 21 | Where `$CONTAINER_REGISTRY` is the name of your Azure Container Registry. 22 | 23 | 1. Update `TrafficControlService` container with the new image: 24 | 25 | ```bash 26 | az containerapp update \ 27 | --name ca-traffic-control-service \ 28 | --resource-group rg-dapr-workshop-java \ 29 | --image "$CONTAINER_REGISTRY.azurecr.io/traffic-control-service:2.0" 30 | ``` 31 | 32 | Where `$CONTAINER_REGISTRY` is the name of your Azure Container Registry. 33 | 34 | 35 | 36 | {% assign stepNumber = stepNumber | plus: 1 %} 37 | {% include 05-assignment-5-aks-aca/02-aca/0-3-test-application.md %} 38 | 39 | Check Application Map of Application Insights in Azure Portal to see the connection between the `TrafficControlService` and the `aca-azure-cosmosdb-statestore`. Check in Azure Portal the data in Cosmos DB. 40 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/03-secret-store/3-1-create-sb-connection-string-secret.md: -------------------------------------------------------------------------------- 1 | ## Step 1: Create a secret in the Azure Key Vault for the connetion string 2 | 3 | Azure Service Bus' connection string will be store as a string/literal secret: 4 | 5 | 1. Open a terminal window. 6 | 7 | 1. Create a secret in the Azure Key Vault for Azure Service Bus' connection string: 8 | 9 | ```bash 10 | az keyvault secret set --vault-name $KEY_VAULT --name azSericeBusconnectionString --value "" 11 | ``` 12 | Replace `` with the connection string of the Azure Service Bus created in assignement 3. 13 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/03-secret-store/5-1-deploy-secret-store-component-to-aca.md: -------------------------------------------------------------------------------- 1 | ## Step {{stepNumber}}: Deploy Azure Key Vault secret store component 2 | 3 | 1. **Copy or Move** this file `dapr/aca-azure-keyvault-secretstore.yam` to `dapr/components/` folder. 4 | 5 | 1. Open the copied file `dapr/components/aca-azure-keyvault-secretstore.yaml` in your code editor. 6 | 7 | 1. Set the following values in the metadata section of the component: 8 | 9 | - `vaultName`: The name of the Azure Key Vault you created in step 3. 10 | - `azureTenantId`: The value for `tenant` you noted down in step 1. 11 | - `azureClientId`: The value for `appId` you noted down in step 1. 12 | 13 | 1. Set the following values in the secrets section of the component: 14 | 15 | - `azure-client-secret`: The value for `password` you noted down in step 1. 16 | 17 | 1. Go to the root folder of the repository. 18 | 19 | 1. Enter the following command to deploy the `secretstore` Dapr component: 20 | 21 | ```bash 22 | az containerapp env dapr-component set \ 23 | --name cae-dapr-workshop-java \ 24 | --resource-group rg-dapr-workshop-java \ 25 | --dapr-component-name secretstore \ 26 | --yaml ./dapr/components/aca-azure-keyvault-secretstore.yaml 27 | ``` 28 | 29 | {: .important-title } 30 | > Managed Identity 31 | > 32 | > By setting a secret in a Dapr component for Azure Container Apps environmnet, the secret is stored [using platform-managed Kubernetes secrets](https://learn.microsoft.com/en-us/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#using-platform-managed-kubernetes-secrets). This is useful when connecting non-Azure services or in DEV/TEST scenarios for quickly deployment Dapr components. 33 | > 34 | > In production scenarios, it is recommended to use [Azure Key Vault secret store](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/) with a [managed identity](https://docs.dapr.io/developing-applications/integrations/azure/azure-authentication/authenticating-azure/#about-authentication-with-azure-ad) instead and to not store secrets as Kubernetes secrets. 35 | > 36 | 37 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/03-secret-store/5-2-a-rebuild-fine-collection-service.md: -------------------------------------------------------------------------------- 1 | In this step, you will rebuild and redeploy the `FineCollectionService` to use the secret store (i.e. Azure Key Vault) to get the license key of the fine calculator. 2 | 3 | 1. Delete the image from local docker: 4 | 5 | ```bash 6 | docker rmi fine-collection-service:1.0-SNAPSHOT 7 | ``` 8 | 9 | 1. In the root folder of `FineCollectionService`, run the following command to build and push the image: 10 | 11 | ```bash 12 | mvn spring-boot:build-image 13 | docker tag fine-collection-service:1.0-SNAPSHOT "$CONTAINER_REGISTRY.azurecr.io/fine-collection-service:3.0" 14 | docker push "$CONTAINER_REGISTRY.azurecr.io/fine-collection-service:3.0" 15 | ``` 16 | 17 | Where `$CONTAINER_REGISTRY` is the name of your Azure Container Registry. 18 | 19 | 1. Update `FineCollectionService` container app with the new image: 20 | 21 | ```bash 22 | az containerapp update \ 23 | --name ca-fine-collection-service \ 24 | --resource-group rg-dapr-workshop-java \ 25 | --image "$CONTAINER_REGISTRY.azurecr.io/fine-collection-service:3.0" 26 | ``` 27 | 28 | Where `$CONTAINER_REGISTRY` is the name of your Azure Container Registry. -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/03-secret-store/5-2-b-1-use-secret-in-pubsub.md: -------------------------------------------------------------------------------- 1 | 1. Open the file `dapr/components/aca-azure-servicebus-pubsub.yaml` (created in assignment 3) in your code editor, and inspect it. 2 | 3 | 1. Add the following line after`version: v1`: 4 | 5 | ```yaml 6 | secretStoreComponent: "secretstore" 7 | ``` 8 | 9 | This tells Dapr to use the secret store component `secretstore` to retrieve the secret. 10 | 11 | 1. **Replace** value: 12 | 13 | ```yaml 14 | value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}" 15 | ``` 16 | with: 17 | 18 | ```yaml 19 | secretRef: azSericeBusconnectionString 20 | ``` 21 | 22 | This tells Dapr to use the secret `azSericeBusconnectionString` from the secret store. 23 | 24 | It should look like: 25 | 26 | ```yaml 27 | componentType: pubsub.azure.servicebus 28 | version: v1 29 | secretStoreComponent: "secretstore" 30 | metadata: 31 | - name: connectionString 32 | secretRef: azSericeBusconnectionString 33 | scopes: 34 | - traffic-control-service 35 | - fine-collection-service 36 | ``` 37 | 38 | 1. **Update** Darp component using the following command in the root of the project: 39 | 40 | ```bash 41 | az containerapp env dapr-component set \ 42 | --name cae-dapr-workshop-java \ 43 | --resource-group rg-dapr-workshop-java \ 44 | --dapr-component-name pubsub \ 45 | --yaml ./dapr/components/aca-azure-servicebus-pubsub.yaml 46 | ``` 47 | 48 | {: .note } 49 | > To know more about how to use a secret in a Dapr component with Azure Container Apps, please refer to [this documentation](https://learn.microsoft.com/en-us/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#referencing-dapr-secret-store-components). 50 | > 51 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/03-secret-store/5-2-b-2-restart-services.md: -------------------------------------------------------------------------------- 1 | 1. Run the following command to identify the running revision of fine collection service container apps: 2 | 3 | - Linux/Unix shell: 4 | 5 | ```bash 6 | FINE_COLLECTION_SERVICE_REVISION=$(az containerapp revision list -n ca-fine-collection-service -g rg-dapr-workshop-java --query "[0].name" -o tsv) 7 | echo $FINE_COLLECTION_SERVICE_REVISION 8 | ``` 9 | 10 | - Powershell: 11 | 12 | ```powershell 13 | $FINE_COLLECTION_SERVICE_REVISION = az containerapp revision list -n ca-fine-collection-service -g rg-dapr-workshop-java --query "[0].name" -o tsv 14 | $FINE_COLLECTION_SERVICE_REVISION 15 | ``` 16 | 17 | 1. Restart fine collection service revision: 18 | 19 | ```bash 20 | az containerapp revision restart \ 21 | --name ca-fine-collection-service \ 22 | --resource-group rg-dapr-workshop-java \ 23 | --revision $FINE_COLLECTION_SERVICE_REVISION 24 | ``` 25 | 26 | 1. Run the following command to identify the running revision of traffic control service container apps: 27 | 28 | - Linux/Unix shell: 29 | 30 | ```bash 31 | TRAFFIC_CONTROL_SERVICE_REVISION=$(az containerapp revision list -n ca-traffic-control-service -g rg-dapr-workshop-java --query "[0].name" -o tsv) 32 | echo $TRAFFIC_CONTROL_SERVICE_REVISION 33 | ``` 34 | 35 | - Powershell: 36 | 37 | ```powershell 38 | $TRAFFIC_CONTROL_SERVICE_REVISION = az containerapp revision list -n ca-traffic-control-service -g rg-dapr-workshop-java --query "[0].name" -o tsv 39 | $TRAFFIC_CONTROL_SERVICE_REVISION 40 | ``` 41 | 42 | 1. Restart traffic control service revision: 43 | 44 | ```bash 45 | az containerapp revision restart \ 46 | --name ca-traffic-control-service \ 47 | --resource-group rg-dapr-workshop-java \ 48 | --revision $TRAFFIC_CONTROL_SERVICE_REVISION 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/04-managed-identities/2-1-intro.md: -------------------------------------------------------------------------------- 1 | Until now, you have use the connection string of Azure Service Bus and the master key of Cosmos DB to connect to these services. First you put them in the environment variables of the Dapr Component. Then you stored them in Azure Key Vault and referenced them in the Dapr Component using the secret store. This is a good practice for non-Azure services. However, for [Azure services that support Azure AD authentication](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/services-id-authentication-support), you should use [Managed Identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) to access them. With secrets in the secret store (i.e. Key Vault), you still have to manage the connection string of service bus and the master key of Cosmos DB, and their rotation. Even more, the client secret of the Service Principal used to access Key Vault is stored in a [platform-managed Kubernetes secret](https://learn.microsoft.com/en-us/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml#using-platform-managed-kubernetes-secrets)and is not rotated automatically. It is recommended to use managed identity to access key vault information. 2 | 3 | To solve this problem, you will use [Managed Identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) that eliminate the need for developers to manage credentials. They provide an automatically managed identity in Azure Active Directory (Azure AD) that can be used to authenticate to [Azure services that support Azure AD authentication](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/services-id-authentication-support), like Azure Key Vault. Managed Identities can be assigned to Azure resources like Azure Container Apps, Azure Functions, Azure Virtual Machines, etc. 4 | 5 | There are [two types of Managed Identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview#managed-identity-types) that can be assigned to a container app: 6 | - `System-assigned Managed Identity` (SMI): a managed identity that is directrly enable on the container app. It is tied to the lifecycle of the container app and cannot be used by any other resource. 7 | - `User-assigned Managed Identity` (UMI): a managed identity that is created as a standalone Azure resource. It can be assigned to one or more container apps and Azure resources. It is not tied to the lifecylce of a single container app as it is a shared resource. 8 | 9 | In this assignment you will use a `User-assigned Managed Identity` (UMI) to access the Azure Container Registry (ACR) and Azure Service Bus. You will use a `System-assigned Managed Identity` (SMI) to access Azure Key Vault, and another one to access Azure Cosmos DB. You are going to use [Azure built-in roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) and assign them to SMI and/or UMI. This assignment ends with a discussion on the choice between SMI and UMI. 10 | -------------------------------------------------------------------------------- /docs/_includes/09-bonus-assignments/05-scaling/2-1-intro.md: -------------------------------------------------------------------------------- 1 | Fine collection service is a stateless service that could be subject of peaks of request. To ensure that the service can handle the load, it is important to scale the service out to multiple instances when needed. Container Apps can scale up to [300 replicas per revision](https://learn.microsoft.com/en-us/azure/container-apps/scale-app?pivots=azure-cli#scale-definition). For example, if there is an increase in the traffic during the day, the probability of having more speed violation could be higher, the amount of messages in the topic could increase and the service could be subject of peaks of request. In this case, the service should be scaled out to multiple instances to handle the load. 2 | 3 | On an other hand, the service is not used all the time. For example, during the night, there could be less traffic and the service could not be used. If there is no message in the topic (i.e. no speed violation), the service can be scaled to zero replicas to save cost. Indeed if a container app has zero replicas, [no resource consumption charges are incurred](https://learn.microsoft.com/en-us/azure/container-apps/billing#no-replicas-are-running) for this application (if the container app is deploy to a consumption workload). 4 | 5 | In this assignment, you are going to [scale](https://learn.microsoft.com/en-us/azure/container-apps/scale-app?pivots=azure-cli#custom) fine collection service from 0 to 5 replicas, i.e. to define a scaling rule for `ca-fine-collection-service` container apps. To do so, you are going to use [KEDA](https://keda.sh/) that is supported out of the box by Azure Container Apps. This open source project can drove the scaling of any container in Azure Container Apps based on the nummber of events needing to be processed. For fine collection service, [Azure Service Bus scaler](https://keda.sh/docs/2.11/scalers/azure-service-bus/) is used. It scales the container app replicas based on the number of messages on a topic or a queue. -------------------------------------------------------------------------------- /docs/assets/images/aca-deployment-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/aca-deployment-1.png -------------------------------------------------------------------------------- /docs/assets/images/aca-deployment-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/aca-deployment-2.png -------------------------------------------------------------------------------- /docs/assets/images/aca-deployment-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/aca-deployment-3.png -------------------------------------------------------------------------------- /docs/assets/images/aca-deployment-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/aca-deployment-4.png -------------------------------------------------------------------------------- /docs/assets/images/aca-deployment-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/aca-deployment-5.png -------------------------------------------------------------------------------- /docs/assets/images/application-diagram-without-dapr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/application-diagram-without-dapr.png -------------------------------------------------------------------------------- /docs/assets/images/application-insights-application-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/application-insights-application-map.png -------------------------------------------------------------------------------- /docs/assets/images/application-with-dapr-telemetry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/application-with-dapr-telemetry.png -------------------------------------------------------------------------------- /docs/assets/images/application-with-dapr-zipkin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/application-with-dapr-zipkin.png -------------------------------------------------------------------------------- /docs/assets/images/dapr-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/dapr-setup.png -------------------------------------------------------------------------------- /docs/assets/images/dapr-sidecar-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/dapr-sidecar-model.png -------------------------------------------------------------------------------- /docs/assets/images/dapr-telemetry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/dapr-telemetry.png -------------------------------------------------------------------------------- /docs/assets/images/eclipse-external-tools-configurations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/eclipse-external-tools-configurations.png -------------------------------------------------------------------------------- /docs/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/favicon.ico -------------------------------------------------------------------------------- /docs/assets/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/overview.png -------------------------------------------------------------------------------- /docs/assets/images/overview_kubernetes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/overview_kubernetes.png -------------------------------------------------------------------------------- /docs/assets/images/replica-count-metric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/replica-count-metric.png -------------------------------------------------------------------------------- /docs/assets/images/scale-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/scale-rule.png -------------------------------------------------------------------------------- /docs/assets/images/sequence-dapr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/sequence-dapr.png -------------------------------------------------------------------------------- /docs/assets/images/sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/sequence.png -------------------------------------------------------------------------------- /docs/assets/images/speed-trap-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/speed-trap-overview.png -------------------------------------------------------------------------------- /docs/assets/images/workshop-end-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/workshop-end-state.png -------------------------------------------------------------------------------- /docs/assets/images/zipkin-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/docs/assets/images/zipkin-screenshot.png -------------------------------------------------------------------------------- /docs/modules/00-intro/1-dapr-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dapr Overview 3 | parent: Basic Concepts and Prerequisites 4 | has_children: false 5 | nav_order: 1 6 | layout: default 7 | --- 8 | 9 | # Dapr Overview 10 | 11 | {% include 00-intro/1-dapr-overview.md relativeAssetsPath="../../assets/" %} 12 | 13 | 14 | 15 | 16 | [< Introduction]({{ site.baseurl }}{% link index.markdown %}){: .btn .mt-7 } 17 | 18 | 19 | [Prerequisites >]({{ site.baseurl }}{% link modules/00-intro/2-prerequisites.md %}){: .btn .float-right .mt-7 } 20 | -------------------------------------------------------------------------------- /docs/modules/00-intro/2-prerequisites.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prerequisites 3 | parent: Basic Concepts and Prerequisites 4 | has_children: false 5 | nav_order: 2 6 | layout: default 7 | --- 8 | 9 | # Prerequisites 10 | 11 | {% include 00-intro/2-prerequisites.md %} 12 | 13 | 14 | 15 | 16 | [< Dapr Overview]({{ site.baseurl }}{% link modules/00-intro/1-dapr-overview.md %}){: .btn .mt-7 } 17 | 18 | 19 | [Assignment 1 - Run without Dapr >]({{ site.baseurl }}{% link modules/01-assignment-1-lab/1-spring-for-apache-kafka.md %}){: .btn .float-right .mt-7 } 20 | 21 | -------------------------------------------------------------------------------- /docs/modules/00-intro/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic Concepts and Prerequisites 3 | has_children: true 4 | nav_order: 2 5 | layout: default 6 | --- 7 | 8 | # Basic Concepts and Prerequisites 9 | 10 | Details on Dapr and Workshop Prerequisites. 11 | -------------------------------------------------------------------------------- /docs/modules/01-assignment-1-lab/1-spring-for-apache-kafka.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spring for Apache Kafka Usage 3 | parent: Assignment 1 - Running Applications with Kafka without using Dapr 4 | has_children: false 5 | nav_order: 1 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Spring for Apache Kafka Usage 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | {% include 01-assignment-1-lab/1-spring-for-apache-kafka.md %} 24 | 25 | 26 | 27 | 28 | [< Prerequisites]({{ site.baseurl }}{% link modules/00-intro/2-prerequisites.md %}){: .btn .mt-7 } 29 | 30 | 31 | [Running Applications without using Dapr >]({{ site.baseurl }}{% link modules/01-assignment-1-lab/2-lab-instructions.md %}){: .btn .float-right .mt-7 } 32 | -------------------------------------------------------------------------------- /docs/modules/01-assignment-1-lab/2-lab-instructions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Running Applications without using Dapr 3 | parent: Assignment 1 - Running Applications with Kafka without using Dapr 4 | has_children: false 5 | nav_order: 2 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Running Applications without using Dapr 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | {% include 01-assignment-1-lab/2-lab-instructions.md %} 24 | 25 | 26 | 27 | 28 | [< Spring for Apache Kafka Usage]({{ site.baseurl }}{% link modules/01-assignment-1-lab/1-spring-for-apache-kafka.md %}){: .btn .mt-7 } 29 | 30 | 31 | [Assignment 2 - Run with Dapr >]({{ site.baseurl }}{% link modules/02-assignment-2-dapr-pub-sub/index.md %}){: .btn .float-right .mt-7 } 32 | 33 | -------------------------------------------------------------------------------- /docs/modules/01-assignment-1-lab/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 1 - Running Applications with Kafka without using Dapr 3 | has_children: true 4 | nav_order: 3 5 | layout: default 6 | --- 7 | 8 | # Assignment 1 - Running Applications with Kafka without using Dapr 9 | 10 | Details on how to run the application to make sure everything works correctly. -------------------------------------------------------------------------------- /docs/modules/02-assignment-2-dapr-pub-sub/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 2 - Using Dapr for pub/sub with Kafka 3 | has_children: false 4 | nav_order: 4 5 | layout: default 6 | has_toc: true 7 | --- 8 | 9 | # Assignment 2 - Using Dapr for pub/sub with Kafka 10 | 11 | {: .no_toc } 12 | 13 |
14 | 15 | Table of contents 16 | 17 | {: .text-delta } 18 | - TOC 19 | {:toc} 20 |
21 | 22 | {% include 02-assignment-2-dapr-pub-sub/1-dapr-pub-sub.md relativeAssetsPath="../../assets/" %} 23 | 24 | 25 | 26 | 27 | [< Assignment 1 - Run without Dapr]({{ site.baseurl }}{% link modules/01-assignment-1-lab/2-lab-instructions.md %}){: .btn .mt-7 } 28 | 29 | 30 | [Assignment 3 - Pub/sub with Azure Services >]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/index.md %}){: .btn .float-right .mt-7 } 31 | 32 | -------------------------------------------------------------------------------- /docs/modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Dapr for pub/sub with Azure Service Bus 3 | parent: Assignment 3 - Using Dapr for pub/sub with Azure Services 4 | has_children: false 5 | nav_order: 1 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Using Dapr for pub/sub with Azure Service Bus 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | {% include 03-assignment-3-azure-pub-sub/1-azure-service-bus.md %} 24 | 25 | 26 | 27 | 28 | [< Assignment 2 - Run with Dapr]({{ site.baseurl }}{% link modules/02-assignment-2-dapr-pub-sub/index.md %}){: .btn .mt-7 } 29 | 30 | 31 | [Assignment 4 - Observability >]({{ site.baseurl }}{% link modules/04-assignment-4-observability-zipkin/index.md %}){: .btn .float-right .mt-7 } 32 | 33 | -------------------------------------------------------------------------------- /docs/modules/03-assignment-3-azure-pub-sub/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 3 - Using Dapr for pub/sub with Azure Services 3 | has_children: true 4 | nav_order: 5 5 | layout: default 6 | --- 7 | 8 | # Assignment 3 - Using Dapr for pub/sub with Azure Services 9 | 10 | With Dapr you can easily without code changes switch between different [pub/sub brokers](https://docs.dapr.io/reference/components-reference/supported-pubsub/). In this assignment you will learn how to use Dapr with Azure Service Bus and Azure Cache for Redis. 11 | 12 | All the assignments of this module can be done independently from each other. You can choose to do one or all of them. 13 | 14 | 15 | 16 | 17 | [Azure Service Bus]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}){: .btn } 18 | 19 | 20 | [Azure Cache for Redis]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/2-azure-cache-redis.md %}){: .btn } 21 | 22 | 23 | 24 | 25 | {: .new-title } 26 | > Challenge 27 | > 28 | > Azure Event Hubs is another messaging solution in Azure and it is supported by Dapr, see [here](https://docs.dapr.io/reference/components-reference/supported-pubsub/setup-azure-eventhubs/). Can you find a way to use Azure Event Hubs as a pub-sub Dapr component? 29 | > 30 | -------------------------------------------------------------------------------- /docs/modules/04-assignment-4-observability-zipkin/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 4 - Observability with Dapr using Zipkin 3 | has_children: false 4 | nav_order: 6 5 | layout: default 6 | --- 7 | 8 | # Assignment 4 - Observability with Dapr using Zipkin 9 | 10 | In this assignment you will look at how to access and view telemetry data being collected through Dapr within a distributed tracing system called Zipkin. 11 | 12 | ## Step 1: Ensure Zipkin container is installed and running 13 | 14 | When Dapr is initialized (`dapr init`) in self-hosted mode, several containers are deployed to your local Docker runtime. Run the following command to view all containers running locally on your machine. Ensure the Zipkin container is up and running and note the port it's running on (Default is 9411) 15 | 16 | ```bash 17 | docker ps 18 | ``` 19 | 20 | ```bash 21 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 22 | a29918435d42 redis "docker-entrypoint.s…" 2 months ago Up 2 hours 0.0.0.0:6379->6379/tcp dapr_redis 23 | 3ba8c5264af1 openzipkin/zipkin "start-zipkin" 2 months ago Up 2 hours (healthy) 9410/tcp, 0.0.0.0:9411->9411/tcp dapr_zipkin 24 | f414fa5d89e6 daprio/dapr:1.6.1 "./placement" 2 months ago Up 2 hours 0.0.0.0:6050->50005/tcp dapr_placement 25 | ``` 26 | 27 | ## Step 2: Use Zipkin to inspect telemetry within a browser 28 | 29 | In your browser of choice, open a new tab and navigate to the following url. 30 | 31 | ```html 32 | http://localhost:9411 33 | ``` 34 | 35 | The Zipkin web application should render where you can begin to search and view telemetry that has been logged through the Dapr observability building block. 36 | 37 | Click on the `Run Query` button to initiate a search. 38 | 39 | Depending on when you completed Assignment 3 and stopped the services included in that assignment, you'll need to make sure the search filters are set correctly in order to have telemetry returned for inspection. 40 | 41 | > The default search criteria is set to all telemetry collected within the last 15 mins. If no telemetry is returned, increase the time filter within the settings section. 42 | 43 | From the list of telemetry items, click the `Show` button to view an individual item and inspect the details of the trace. 44 | 45 | ![Zipkin UI](../../assets/images/zipkin-screenshot.png) 46 | 47 | 48 | 49 | 50 | [< Assignment 3 - Pub/sub with Azure Services]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/index.md %}){: .btn .mt-7 } 51 | 52 | 53 | [Assignment 5 - Deploy to Azure >]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/index.md %}){: .btn .float-right .mt-7 } 54 | 55 | -------------------------------------------------------------------------------- /docs/modules/05-assignment-5-aks-aca/01-aks/1-dapr-sidecar-in-k8s.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dapr Sidecar in Kubernetes 3 | parent: Deploying to Azure Kubernetes Service 4 | grand_parent: Assignment 5 - Deploying to Azure with Dapr 5 | has_children: false 6 | nav_order: 1 7 | layout: default 8 | --- 9 | 10 | # Dapr Sidecar architecture 11 | 12 | * Dapr exposes its HTTP and gRPC APIs as a sidecar architecture, either as a container or as a process, not requiring the application code to include any Dapr runtime code. 13 | ![Dapr Side Car](../../assets/images/overview_kubernetes.png) 14 | * Deploying and running a Dapr-enabled application into your Kubernetes cluster is as simple as adding a few annotations to the deployment schemes. 15 | * Let's inspect deployment file of TrafficControlService. 16 | 17 | ```yml 18 | apiVersion: apps/v1 19 | kind: Deployment 20 | metadata: 21 | creationTimestamp: null 22 | labels: 23 | app: trafficcontrolservice 24 | name: trafficcontrolservice 25 | spec: 26 | replicas: 1 27 | selector: 28 | matchLabels: 29 | app: trafficcontrolservice 30 | strategy: {} 31 | template: 32 | metadata: 33 | creationTimestamp: null 34 | labels: 35 | app: trafficcontrolservice 36 | annotations: 37 | dapr.io/enabled: "true" 38 | dapr.io/app-id: "trafficcontrolservice" 39 | dapr.io/app-port: "6000" 40 | spec: 41 | containers: 42 | - image: .azurecr.io/traffic-control-service:latest 43 | name: traffic-control-service 44 | resources: {} 45 | status: {} 46 | ``` 47 | 48 | * As you can see, the below annotation inserts Dapr sidecar to the deployment. 49 | 50 | ```yml 51 | annotations: 52 | dapr.io/enabled: "true" 53 | ``` 54 | 55 | 56 | 57 | 58 | [< Deploy to AKS]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/index.md %}){: .btn .mt-7 } 59 | 60 | 61 | [Deploy to AKS with Dapr Extension >]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/2-aks-instructions.md %}){: .btn .float-right .mt-7 } 62 | 63 | -------------------------------------------------------------------------------- /docs/modules/05-assignment-5-aks-aca/01-aks/4-gitops.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: (Optional) GitOps 3 | parent: Deploying to Azure Kubernetes Service 4 | grand_parent: Assignment 5 - Deploying to Azure with Dapr 5 | has_children: false 6 | nav_order: 4 7 | layout: default 8 | --- 9 | 10 | # (Optional) Enable GitOps addon and use it to deploy applications 11 | 12 | 1. Fork this repository on your personal GitHub account. 13 | 14 | 2. Create a [personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) that has write permission to repositories (select `repo` under permissions). 15 | 16 | 3. Export your GitHub access token, username, and your forked repository: 17 | 18 | ```bash 19 | export GITHUB_TOKEN= 20 | export GITHUB_USER= 21 | export GITHUB_REPO= 22 | ``` 23 | 24 | 4. Run the following commands: 25 | 26 | ```bash 27 | az feature register --namespace Microsoft.ContainerService --name AKS-ExtensionManager 28 | az provider register --namespace Microsoft.Kubernetes 29 | az provider register --namespace Microsoft.ContainerService 30 | az provider register --namespace Microsoft.KubernetesConfiguration 31 | az extension add -n k8s-configuration 32 | az extension add -n k8s-extension 33 | ``` 34 | 35 | 5. Enable GitOps extension: 36 | 37 | ```bash 38 | az k8s-extension create --cluster-type managedClusters \ 39 | --cluster-name aks-dapr-workshop-java \ 40 | --name myGitopsExtension \ 41 | --extension-type Microsoft.Gitops 42 | ``` 43 | 44 | 6. Apply Flux configuration: 45 | 46 | ```bash 47 | az k8s-configuration flux create -c aks-dapr-workshop-java -n dapr-workshop-java-flux --namespace cluster-config -t managedClusters --scope cluster -u $GITHUB_REPO --branch main --kustomization name=test path=./deploy prune=true --https-user $GITHUB_USER --https-key $GITHUB_TOKEN 48 | ``` 49 | 50 | 7. verify all application pods are running by executing the following command: `kubectl get pods`. 51 | 52 | 53 | 54 | 55 | [< (Optional) Observability]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/3-observability-with-open-telemetry.md %}){: .btn .mt-7 } 56 | 57 | -------------------------------------------------------------------------------- /docs/modules/05-assignment-5-aks-aca/01-aks/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploying to Azure Kubernetes Service 3 | parent: Assignment 5 - Deploying to Azure with Dapr 4 | has_children: true 5 | nav_order: 1 6 | layout: default 7 | --- 8 | 9 | # Deploying to Azure Kubernetes Service 10 | 11 | In this assignment, you will deploy the 3 services and the simulation to Azure Kubernetes Service (AKS). First there is a [introduction to Dapr sidecar in Kubernetes]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/1-dapr-sidecar-in-k8s.md %}). Then you will [deploy the 3 services and the simulation to AKS]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/2-aks-instructions.md %}). Finally you will test the application. 12 | 13 | There are two more optional exercises in this assignment. The first one is to [setup observability in AKS using OpenTelemetry]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/3-observability-with-open-telemetry.md %}). The second one is to use [GitOps to deploy the application to AKS]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/4-gitops.md %}). 14 | 15 | 16 | 17 | 18 | [< Assignment 4 - Observability]({{ site.baseurl }}{% link modules/04-assignment-4-observability-zipkin/index.md %}){: .btn .mt-7 } 19 | 20 | 21 | [Dapr Sidecar in k8's >]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/1-dapr-sidecar-in-k8s.md %}){: .btn .float-right .mt-7 } 22 | 23 | -------------------------------------------------------------------------------- /docs/modules/05-assignment-5-aks-aca/02-aca/2-observability.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: (Optional) Observability 3 | parent: Deploying to Azure Container Apps 4 | grand_parent: Assignment 5 - Deploying to Azure with Dapr 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | 9 | has_toc: true 10 | --- 11 | 12 | 13 | # (Optional) Observability with Dapr using Application Insights 14 | 15 | 16 | {: .no_toc } 17 | 18 |
19 | 20 | Table of contents 21 | 22 | {: .text-delta } 23 | - TOC 24 | {:toc} 25 |
26 | 27 | In this section, you will deploy Dapr service-to-service telemetry using [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview?tabs=java). When [creating the Azure Container Apps environment](https://learn.microsoft.com/en-us/cli/azure/containerapp/env?view=azure-cli-latest#az-containerapp-env-create), you can set Application Insights instrumentation key that is used by Dapr to export service-to-service telemetry to Application Insights. 28 | 29 | ## Step 1: Create Application Insights resource 30 | 31 | {% include 05-assignment-5-aks-aca/02-aca/0-1-setup-application-insights.md %} 32 | 33 | ## Step 2: Create Azure Container Apps environment 34 | 35 | {% include 05-assignment-5-aks-aca/02-aca/0-2-setup-container-apps-env.md showObservability=true %} 36 | 37 | ## Step 3: Deploy the application 38 | 39 | To deploy the application, follow all the instructions after the creation of the container apps environment in [Deploying Applications to Azure Container Apps (ACA) with Dapr]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/1-aca-instructions.md %}). After the completion of the deployment and the testing, you can see the service-to-service telemetry in the Application Insights as shown below. 40 | 41 | ## Step 4: View the telemetry in Application Insights 42 | 43 | 1. Open the Application Insights resource in the [Azure portal]([https](https://portal.azure.com/)). 44 | 45 | 1. Go to `Application Map`, you should see a diagram like the on below 46 | 47 | ![Dapr Telemetry](../../../assets/image/../images/dapr-telemetry.png) 48 | 49 | 50 | 51 | 52 | [< Deploy to ACA with Dapr]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/1-aca-instructions.md %}){: .btn .mt-7 } 53 | 54 | -------------------------------------------------------------------------------- /docs/modules/05-assignment-5-aks-aca/02-aca/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploying to Azure Container Apps 3 | parent: Assignment 5 - Deploying to Azure with Dapr 4 | has_children: true 5 | nav_order: 2 6 | layout: default 7 | --- 8 | 9 | # Deploying to Azure Container Apps 10 | 11 | In this assignment, you will deploy the 3 services and the simulation to [Azure Container Apps (ACA)]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/1-aca-instructions.md %}). It is followed by an optional exercise to [setup observability in ACA using Application Insights]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/2-observability.md %}). 12 | 13 | {: .important-title } 14 | > Dapr Telemetry 15 | > 16 | > If you want to enable Dapr telemetry, you need to create the container apps environment with Application Insigths. When creating the environment, you can follow the instruction in the optional exercise to [setup Dapr Telemetry in ACA using Application Insights]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/2-observability.md %}). 17 | > 18 | 19 | 20 | 21 | 22 | [< Assignment 4 - Observability]({{ site.baseurl }}{% link modules/04-assignment-4-observability-zipkin/index.md %}){: .btn .mt-7 } 23 | 24 | 25 | [Deploy to ACA with Dapr >]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/1-aca-instructions.md %}){: .btn .float-right .mt-7 } 26 | 27 | -------------------------------------------------------------------------------- /docs/modules/05-assignment-5-aks-aca/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 5 - Deploying to Azure with Dapr 3 | has_children: true 4 | nav_order: 7 5 | layout: default 6 | --- 7 | 8 | # Assignment 5 - Deploying Applications to Azure with Dapr 9 | 10 | In this assignment, you will deploy the 3 services and the simulation to [Azure Kubernetes Service (AKS)]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/index.md %}) and [Azure Container Apps (ACA)]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/index.md %}). You can choose to deploy to either AKS or ACA, but not both. 11 | 12 | 13 | 14 | 15 | [Azure Kubernetes Service (AKS)]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/01-aks/index.md %}){: .btn } 16 | 17 | 18 | [Azure Container Apps (ACA)]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/index.md %}){: .btn } 19 | 20 | -------------------------------------------------------------------------------- /docs/modules/08-additional-topics/1-prevent-port-collisions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prevent port collisions 3 | parent: Additional Topics 4 | has_children: false 5 | nav_order: 1 6 | layout: default 7 | --- 8 | 9 | ## Prevent port collisions 10 | 11 | During the workshop you will run the services in the solution on your local machine. To prevent port-collisions, all services listen on a different HTTP port. When running the services with Dapr, you need additional ports for HTTP and gRPC communication with the sidecars. By default these ports are `3500` and `50001`. But to prevent confusion, you'll use totally different port numbers in the assignments. If you follow the instructions, the services will use the following ports for their Dapr sidecars to prevent port collisions: 12 | 13 | | Service | Application Port | Dapr sidecar HTTP port | Dapr sidecar gRPC port | 14 | |----------------------------|------------------|------------------------|------------------------| 15 | | TrafficControlService | 6000 | 3600 | 60000 | 16 | | FineCollectionService | 6001 | 3601 | 60001 | 17 | | VehicleRegistrationService | 6002 | 3602 | 60002 | 18 | 19 | If you're doing the DIY approach, make sure you use the ports specified in the table above. 20 | 21 | The ports can be specified on the command-line when starting a service with the Dapr CLI. The following command-line flags can be used: 22 | 23 | - `--app-port` 24 | - `--dapr-http-port` 25 | - `--dapr-grpc-port` 26 | 27 | If you're on Windows with Hyper-V enabled, you might run into an issue that you're not able to use one (or more) of these ports. This could have something to do with aggressive port reservations by Hyper-V. You can check whether or not this is the case by executing this command: 28 | 29 | ```powershell 30 | netsh int ipv4 show excludedportrange protocol=tcp 31 | ``` 32 | 33 | If you see one (or more) of the ports shown as reserved in the output, fix it by executing the following commands in an administrative terminal: 34 | 35 | ```powershell 36 | dism.exe /Online /Disable-Feature:Microsoft-Hyper-V 37 | netsh int ipv4 add excludedportrange protocol=tcp startport=6000 numberofports=3 38 | netsh int ipv4 add excludedportrange protocol=tcp startport=3600 numberofports=3 39 | netsh int ipv4 add excludedportrange protocol=tcp startport=60000 numberofports=3 40 | dism.exe /Online /Enable-Feature:Microsoft-Hyper-V /All 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/modules/08-additional-topics/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Additional Topics 3 | has_children: true 4 | nav_order: 8 5 | layout: default 6 | --- 7 | 8 | # Additional Topics -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/01-service-invocation/3-deploying-to-aca.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deploying service invocation to Azure Container Apps 3 | parent: Service invocation using Dapr 4 | grand_parent: Bonus Assignments 5 | has_children: false 6 | nav_order: 3 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Deploying service invocation to Azure Container Apps 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | In this assignment, you will deploy the service communication to Azure Container Apps (ACA). You will use the [service invocation building block](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/service-invocation-overview/) provided by Dapr. 25 | 26 | {: .important-title } 27 | > Pre-requisites 28 | > 29 | > * The first part [Invoke Vehicle Registration Service from Fine Collection Service using Dapr]({{ site.baseurl }}{% link modules/09-bonus-assignments/01-service-invocation/1-invoke-service-using-dapr.md %}) is a pre-requisite for this assignment. 30 | > * Assignment 5 - [Deploying to Azure Container Apps]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/index.md %}) is also a pre-requisite for this assignment. 31 | > 32 | 33 | {% assign stepNumber = 1 %} 34 | {% include 09-bonus-assignments/01-service-invocation/3-deploy-to-aca.md %} 35 | 36 | {: .important-title } 37 | > Cleanup 38 | > 39 | > When the workshop is done, please follow the [cleanup instructions]({{ site.baseurl }}{% link modules/10-cleanup/index.md %}) to delete the resources created in this workshop. 40 | > 41 | 42 | 43 | 44 | 45 | [< Invoke Service using Dapr]({{ site.baseurl }}{% link modules/09-bonus-assignments/01-service-invocation/1-invoke-service-using-dapr.md %}){: .btn .mt-7 } 46 | 47 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/01-service-invocation/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Service invocation using Dapr 3 | parent: Bonus Assignments 4 | has_children: true 5 | nav_order: 1 6 | layout: default 7 | --- 8 | 9 | # Service invocation using Dapr 10 | 11 | This bonus assignment is about using Dapr to invoke the `VehicleRegistrationService` from the `FineCollectionService`. You will use the [service invocation building block](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/service-invocation-overview/) provided by Dapr. 12 | 13 | {: .important-title } 14 | > Pre-requisite 15 | > 16 | > The first part is a pre-requisite for the deployment to Azure Kubernetes Service (AKS) and to Azure Container Apps (ACA). 17 | > 18 | 19 | 20 | 21 | 22 | [Let's start!]({{ site.baseurl }}{% link modules/09-bonus-assignments/01-service-invocation/1-invoke-service-using-dapr.md %}){: .btn .mt-7 } 23 | 24 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/02-state-store/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Azure Cosmos DB as a state store 3 | parent: Bonus Assignments 4 | has_children: true 5 | nav_order: 2 6 | layout: default 7 | --- 8 | 9 | # Using Azure Cosmos DB as a state store 10 | 11 | This bonus assignment is about using [Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/) as a [state store](https://docs.dapr.io/operations/components/setup-state-store/) for the `TrafficControlService`. You will use the [Azure Cosmos DB state store component](https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-azure-cosmosdb/) provided by Dapr. 12 | 13 | {: .important-title } 14 | > Pre-requisite 15 | > 16 | > The first part is a pre-requisite for the deployment to Azure Kubernetes Service (AKS) and to Azure Container Apps (ACA). 17 | > 18 | 19 | 20 | 21 | 22 | [Let's start!]({{ site.baseurl }}{% link modules/09-bonus-assignments/02-state-store/1-azure-cosmos-db-state-store.md %}){: .btn .mt-7 } 23 | 24 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/03-secret-store/1-setup-azure-key-vault.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setup Azure Key Vault as a secret store 3 | parent: Using Azure Key Vault as a secret store 4 | grand_parent: Bonus Assignments 5 | has_children: false 6 | nav_order: 1 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Setup Azure Key Vault as a secret store 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | This bonus assignment is about using Azure Key Vault as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/). You will create the [Azure Key Vault secret store component](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/) provided by Dapr. 25 | 26 | 27 | 28 | {% assign stepNumber = 1 %} 29 | {% include 09-bonus-assignments/03-secret-store/1-setup-azure-key-vault.md %} 30 | 31 | {% assign stepNumber = stepNumber | plus: 1 %} 32 | ## Step {{stepNumber}}: Set the Azure Key Vault secret store component 33 | 34 | 1. **Copy or Move** this file `dapr/azure-keyvault-secretstore.yam` to `dapr/components/` folder. 35 | 36 | 1. Open the copied file `dapr/components/azure-keyvault-secretstore.yaml` in your code editor. 37 | 38 | 1. Set the following values in the metadata section of the component: 39 | - `vaultName`: The name of the Azure Key Vault you created in step 3. 40 | - `azureTenantId`: The value for `tenant` you noted down in step 1. 41 | - `azureClientId`: The value for `appId` you noted down in step 1. 42 | - `azureClientSecret`: The value for `password` you noted down in step 1. 43 | 44 | {: .important } 45 | > Certificate can be used instead of client secret, see [Azure Key Vault secret store](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/). 46 | > 47 | > When deployed to Azure Kubernetes Service, the client secret is a kubernetes secret and not set in the component's YAML file. See the *Kubernetes* tab in *Configure the component* of [Azure Key Vault secret store](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/). 48 | > 49 | > When deployed to Azure Kubernetes Service and Azure Container Apps, managed identity can should used instead of client secret for production workloads. See [Using Managed Service Identities](https://docs.dapr.io/developing-applications/integrations/azure/azure-authentication/authenticating-azure/#about-authentication-with-azure-ad). 50 | > 51 | 52 | 53 | 54 | 55 | [Retreive a secret in the application]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/2-use-secret-store-in-code.md %}){: .btn .mt-7 } 56 | 57 | 58 | [Reference a secret in a component]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/3-use-secret-in-dapr-component.md %}){: .btn .ml-3 } 59 | 60 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/03-secret-store/2-use-secret-store-in-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Retrieve a secret in the application 3 | parent: Using Azure Key Vault as a secret store 4 | grand_parent: Bonus Assignments 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Retrieve a secret in the application 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | Previously, you have created an Azure Key Vault and added the Dapr component. Now, you will use the [secret in the application](https://docs.dapr.io/developing-applications/building-blocks/secrets/howto-secrets/). This bonus assignment is about using Azure Key Vault as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/) for the `FineCollectionService` to get the license key of the fine calculator. 25 | 26 | {: .important-title } 27 | > Pre-requisite 28 | > 29 | > If the setup of the Azure Key Vault is not done yet, please follow the instructions in [Setup Azure Key Vault as a secret store]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/1-setup-azure-key-vault.md %}). 30 | > 31 | 32 | 33 | 34 | {% include 09-bonus-assignments/03-secret-store/2-use-secret-store-in-code.md %} 35 | 36 | ## Step 3: Test the application 37 | 38 | You're going to start all the services now. 39 | 40 | 1. Make sure no services from previous tests are running (close the command-shell windows). 41 | 42 | 1. Open the terminal window and make sure the current folder is `VehicleRegistrationService`. 43 | 44 | 1. Enter the following command to run the VehicleRegistrationService: 45 | 46 | ```bash 47 | mvn spring-boot:run 48 | ``` 49 | 50 | 1. Open a **new** terminal window and change the current folder to `FineCollectionService`. 51 | 52 | 1. Enter the following command to run the FineCollectionService with a Dapr sidecar: 53 | 54 | * Ensure you have run `dapr init` command prior to running the below command 55 | 56 | ```bash 57 | dapr run --app-id finecollectionservice --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --resources-path ../dapr/components mvn spring-boot:run 58 | ``` 59 | 60 | 1. Open a **new** terminal window and change the current folder to `TrafficControlService`. 61 | 62 | 1. Enter the following command to run the TrafficControlService: 63 | 64 | ```bash 65 | mvn spring-boot:run 66 | ``` 67 | 68 | 1. Open a **new** terminal window and change the current folder to `Simulation`. 69 | 70 | 1. Start the simulation: 71 | 72 | ```bash 73 | mvn spring-boot:run 74 | ``` 75 | 76 | You should see the same logs as **Assignment 1**. Obviously, the behavior of the application is exactly the same as before. 77 | 78 | 79 | 80 | 81 | [Reference a secret in a component]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/3-use-secret-in-dapr-component.md %}){: .btn .mt-7 } 82 | 83 | 84 | [Deploy to ACA]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/5-deploying-to-aca.md %}){: .btn } 85 | 86 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/03-secret-store/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Azure Key Vault as a secret store 3 | parent: Bonus Assignments 4 | has_children: true 5 | nav_order: 3 6 | layout: default 7 | --- 8 | 9 | # Using Azure Key Vault as a secret store 10 | 11 | This bonus assignment is about using [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/general/) as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/) for the `FineCollectionService`. You will use the [Azure Key Vault secret store component](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/) provided by Dapr. 12 | 13 | There are 3 main parts in this bonus assignment: 14 | 15 | 1. [Setup of the Azure Key Vault as a secret store]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/1-setup-azure-key-vault.md %}) 16 | 2. [Update of `FineCollectionService` to retrieve the license key from the Azure Key Vault using Dapr secret store component]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/2-use-secret-store-in-code.md %}). The license key is used by the fine calculator engine 17 | 3. [Use secrets of Azure Key Vault in the definition of other components]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/3-use-secret-in-dapr-component.md %}). Using Dapr, component manifests can reference secrets in a secret store. This is used to reference the Azure Service Bus connection string and the Azure Cosmos DB master key in the definition of the Azure Service Bus and Azure Cosmos DB components 18 | 19 | {: .important-title } 20 | > Pre-requisite 21 | > 22 | > The first part is a pre-requisite for the second and third part. The second and third part can be done in any order. 23 | > 24 | 25 | 26 | 27 | 28 | [Let's start!]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/1-setup-azure-key-vault.md %}){: .btn .mt-7 } 29 | 30 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/04-managed-identities/2-managed-identities-in-aca.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: managed Identities in Azure Container Apps 3 | parent: Managed Identities 4 | grand_parent: Bonus Assignments 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Managed Identities in Azure Container Apps 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | 25 | 26 | {% include 09-bonus-assignments/04-managed-identities/2-1-intro.md %} 27 | 28 | {: .important-title } 29 | > Pre-requisites 30 | > 31 | > These assignments are pre-requisites for this assignment: 32 | > 33 | > * [Assignment 3 - Setup Azure Service Bus]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}) 34 | > * Bonus Assignment - [Use Azure Cosmos DB as a state store]({{ site.baseurl }}{% link modules/09-bonus-assignments/02-state-store/index.md %}) 35 | > * Bonus Assignment - [Use Azure Key Vault as a secret store]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/index.md %}) 36 | > * Assignment 5 - [Deploying to Azure Container Apps]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/index.md %}) 37 | > 38 | 39 | 40 | 41 | {% include 09-bonus-assignments/04-managed-identities/2-2-deploy-test-and-discussion.md %} 42 | 43 | 44 | 45 | {: .important-title } 46 | > Cleanup 47 | > 48 | > When the workshop is done, please follow the [cleanup instructions]({{ site.baseurl }}{% link modules/10-cleanup/index.md %}) to delete the resources created in this workshop. Do not forget to delete role assignements. 49 | > 50 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/04-managed-identities/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managed Identities 3 | parent: Bonus Assignments 4 | has_children: true 5 | nav_order: 4 6 | layout: default 7 | --- 8 | 9 | # Managed Identities 10 | 11 | This bonus assignment is about using [Managed Identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) to access Azure resources securely without having to store credentials in Dapr Component or in Kubernetes secrets. 12 | 13 | {: .important-title } 14 | > Pre-requisites 15 | > 16 | > These assignments are pre-requisites for this assignment: 17 | > 18 | > * [Assignment 3 - Setup Azure Service Bus]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}) 19 | > * Bonus Assignment - [Use Azure Cosmos DB as a state store]({{ site.baseurl }}{% link modules/09-bonus-assignments/02-state-store/index.md %}) 20 | > * Bonus Assignment - [Use Azure Key Vault as a secret store]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/index.md %}) 21 | > 22 | 23 | 24 | 25 | 28 | 29 | [Azure Container Apps]({{ site.baseurl }}{% link modules/09-bonus-assignments/04-managed-identities/2-managed-identities-in-aca.md %}){: .btn } 30 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/05-scaling/2-scaling-in-aca.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Scaling Fine Collection Service in Azure Container Apps 3 | parent: Scaling Fine Collection Service using KEDA 4 | grand_parent: Bonus Assignments 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Scaling Fine Collection Service in Azure Container Apps 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | 25 | 26 | {% include 09-bonus-assignments/05-scaling/2-1-intro.md relativeAssetsPath="../../../assets/" %} 27 | 28 | {: .important-title } 29 | > Pre-requisites 30 | > 31 | > * The `Assignment 3 - Setup Azure Service Bus` is a pre-requisite for this bonus assignment. If not done yet, please follow the instructions in [Assignment 3 - Setup Azure Service Bus]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}). 32 | > * Assignment 5 - [Deploying to Azure Container Apps]({{ site.baseurl }}{% link modules/05-assignment-5-aks-aca/02-aca/index.md %}) is also a pre-requisite for this assignment. 33 | > 34 | 35 | 36 | 37 | {% include 09-bonus-assignments/05-scaling/2-2-deploy-and-test.md relativeAssetsPath="../../../assets/" showWithoutSecret=true %} 38 | 39 | 40 | 41 | {: .important-title } 42 | > Cleanup 43 | > 44 | > When the workshop is done, please follow the [cleanup instructions]({{ site.baseurl }}{% link modules/10-cleanup/index.md %}) to delete the resources created in this workshop. 45 | > 46 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/05-scaling/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Scaling Fine Collection Service using KEDA 3 | parent: Bonus Assignments 4 | has_children: true 5 | nav_order: 5 6 | layout: default 7 | --- 8 | 9 | # Scaling Fine Collection Service using KEDA 10 | 11 | This bonus assignment is about usig [KEDA](https://keda.sh/) to scale the `FineCollectionService` based on the number of messages in the Azure Service Bus queue. You will use the [Azure Service Bus Scaler](https://keda.sh/docs/2.11/scalers/azure-service-bus/) provided by KEDA. 12 | 13 | {: .important-title } 14 | > Pre-requisite 15 | > 16 | > The `Assignment 3 - Setup Azure Service Bus` is a pre-requisite for this bonus assignment. If not done yet, please follow the instructions in [Assignment 3 - Setup Azure Service Bus]({{ site.baseurl }}{% link modules/03-assignment-3-azure-pub-sub/1-azure-service-bus.md %}). 17 | > 18 | 19 | 20 | 21 | 24 | 25 | [Azure Container Apps]({{ site.baseurl }}{% link modules/09-bonus-assignments/05-scaling/2-scaling-in-aca.md %}){: .btn } 26 | -------------------------------------------------------------------------------- /docs/modules/09-bonus-assignments/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bonus Assignments 3 | has_children: true 4 | nav_order: 9 5 | layout: default 6 | --- 7 | 8 | # Bonus Assignments 9 | 10 | The bonus assignments are optional and are not required to complete the workshop. They are provided as additional learning opportunities. These assigments cover several [building blocks](https://docs.dapr.io/developing-applications/building-blocks/) of Dapr not covered by the workshop: 11 | 12 | - Service invocation: [service invocation using Dapr]({{ site.baseurl }}{% link modules/09-bonus-assignments/01-service-invocation/index.md %}) 13 | - State management: [Use Azure Cosmos DB as a state store]({{ site.baseurl }}{% link modules/09-bonus-assignments/02-state-store/index.md %}) 14 | - Secrets Management: [Use Azure Key Vault as a secret store]({{ site.baseurl }}{% link modules/09-bonus-assignments/03-secret-store/index.md %}) 15 | 16 | 17 | They also cover the use of managed identities to access Azure resources from the microservices: [Managed Identities]({{ site.baseurl }}{% link modules/09-bonus-assignments/04-managed-identities/index.md %}) 18 | 19 | 20 | Finally, they cover the scaling of `FineCollectionService` using [KEDA](https://keda.sh/) based on the number of messages in the Azure Service Bus topic: [Scale Fine Collection Service using KEDA]({{ site.baseurl }}{% link modules/09-bonus-assignments/05-scaling/index.md %}) 21 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/00-intro/1-dapr-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dapr Overview 3 | parent: Basic Concepts and Prerequisites 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 1 7 | layout: default 8 | --- 9 | 10 | # Dapr Overview 11 | 12 | {% include 00-intro/1-dapr-overview.md relativeAssetsPath="../../../assets/" %} 13 | 14 | 15 | 16 | 17 | [< ACA Challenge]({{ site.baseurl }}{% link modules/11-aca-challenge/index.md %}){: .btn .mt-7 } 18 | 19 | 20 | [Prerequisites >]({{ site.baseurl }}{% link modules/11-aca-challenge/00-intro/2-prerequisites.md %}){: .btn .float-right .mt-7 } 21 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/00-intro/2-prerequisites.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prerequisites 3 | parent: Basic Concepts and Prerequisites 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | --- 9 | 10 | # Prerequisites 11 | 12 | {% include 00-intro/2-prerequisites.md %} 13 | 14 | 15 | 16 | 17 | [< Dapr Overview]({{ site.baseurl }}{% link modules/11-aca-challenge/00-intro/1-dapr-overview.md %}){: .btn .mt-7 } 18 | 19 | 20 | [Assignment 1 - Run without Dapr >]({{ site.baseurl }}{% link modules/11-aca-challenge/01-assignment-1-lab/1-spring-for-apache-kafka.md %}){: .btn .float-right .mt-7 } 21 | 22 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/00-intro/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic Concepts and Prerequisites 3 | parent: Azure Container Apps Challenge 4 | has_children: true 5 | nav_order: 1 6 | layout: default 7 | --- 8 | 9 | # Basic Concepts and Prerequisites 10 | 11 | Details on Dapr and Workshop Prerequisites. 12 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/01-assignment-1-lab/1-spring-for-apache-kafka.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spring for Apache Kafka Usage 3 | parent: Assignment 1 - Running Applications with Kafka without Dapr 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 1 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Spring for Apache Kafka Usage 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | {% include 01-assignment-1-lab/1-spring-for-apache-kafka.md %} 25 | 26 | 27 | 28 | 29 | [< Prerequisites]({{ site.baseurl }}{% link modules/11-aca-challenge/00-intro/2-prerequisites.md %}){: .btn .mt-7 } 30 | 31 | 32 | [Running Applications without using Dapr >]({{ site.baseurl }}{% link modules/11-aca-challenge/01-assignment-1-lab/2-lab-instructions.md %}){: .btn .float-right .mt-7 } 33 | 34 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/01-assignment-1-lab/2-lab-instructions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Run without Dapr 3 | parent: Assignment 1 - Running Applications with Kafka without Dapr 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Running Applications without using Dapr 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | {% include 01-assignment-1-lab/2-lab-instructions.md linkType="aca-challenge" %} 25 | 26 | 27 | 28 | 29 | [< Spring for Apache Kafka Usage]({{ site.baseurl }}{% link modules/11-aca-challenge/01-assignment-1-lab/1-spring-for-apache-kafka.md %}){: .btn .mt-7 } 30 | 31 | 32 | [Assignment 2 - Run with Dapr >]({{ site.baseurl }}{% link modules/11-aca-challenge/02-assignment-2-dapr-pub-sub/index.md %}){: .btn .float-right .mt-7 } 33 | 34 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/01-assignment-1-lab/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 1 - Running Applications with Kafka without Dapr 3 | parent: Azure Container Apps Challenge 4 | has_children: true 5 | nav_order: 2 6 | layout: default 7 | --- 8 | 9 | # Assignment 1 - Running Applications with Kafka without using Dapr 10 | 11 | Details on how to run the application to make sure everything works correctly. -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/02-assignment-2-dapr-pub-sub/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 2 - Using Dapr for pub/sub with Kafka 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 3 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 2 - Using Dapr for pub/sub with Kafka 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | {% include 02-assignment-2-dapr-pub-sub/1-dapr-pub-sub.md relativeAssetsPath="../../../assets/" %} 24 | 25 | 26 | 27 | 28 | [< Assignment 1 - Run without Dapr]({{ site.baseurl }}{% link modules/11-aca-challenge/01-assignment-1-lab/2-lab-instructions.md %}){: .btn .mt-7 } 29 | 30 | 31 | [Assignment 3 - Pub/sub with Azure Service Bus >]({{ site.baseurl }}{% link modules/11-aca-challenge/03-assignment-3-azure-pub-sub/index.md %}){: .btn .float-right .mt-7 } 32 | 33 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/03-assignment-3-azure-pub-sub/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 3 - Using Dapr for pub/sub with Azure Service Bus 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 4 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 3 - Using Dapr for pub/sub with Azure Service Bus 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | {% include 03-assignment-3-azure-pub-sub/1-azure-service-bus.md %} 24 | 25 | 26 | 27 | 28 | [< Assignment 2 - Run with Dapr]({{ site.baseurl }}{% link modules/11-aca-challenge/02-assignment-2-dapr-pub-sub/index.md %}){: .btn .mt-7 } 29 | 30 | 31 | [Assignment 4 - Deploy to Azure Container Apps >]({{ site.baseurl }}{% link modules/11-aca-challenge/04-deploy-to-aca/index.md %}){: .btn .float-right .mt-7 } 32 | 33 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/04-deploy-to-aca/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 4 - Deploying to Azure Container Apps 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 5 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 4 - Deploying to Azure Container Apps 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | This assignment is about deploying the 3 microservices to [Azure Container Apps](https://learn.microsoft.com/en-us/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. 24 | 25 | ![Azure Container Apps Challenge - First Deployment](../../../assets/images/aca-deployment-1.png) 26 | 27 | ## Setup 28 | 29 | {% include 05-assignment-5-aks-aca/02-aca/1-setup.md showObservability=true %} 30 | 31 | ## Step 1 - Deploy Dapr Component for pub/sub 32 | 33 | You are going to deploy the `pubsub` Dapr component to use Azure Service Bus as the pub/sub message broker. 34 | 35 | {% include 05-assignment-5-aks-aca/02-aca/2-1-dapr-component-service-bus.md linkType="aca-challenge" %} 36 | 37 | 38 | 39 | {% assign stepNumber = 2 %} 40 | {% include 05-assignment-5-aks-aca/02-aca/3-build-deploy-test.md %} 41 | 42 | 43 | 44 | {% assign stepNumber = stepNumber | plus: 1 %} 45 | {% include 05-assignment-5-aks-aca/02-aca/4-observability.md relativeAssetsPath="../../../assets/" %} 46 | 47 | 48 | 49 | 50 | [< Assignment 3 - Pub/sub with Azure Service Bus]({{ site.baseurl }}{% link modules/11-aca-challenge/03-assignment-3-azure-pub-sub/index.md %}){: .btn .mt-7 } 51 | 52 | 53 | [Assignment 5 - Service invocation >]({{ site.baseurl }}{% link modules/11-aca-challenge/05-service-invocation/index.md %}){: .btn .float-right .mt-7 } 54 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/05-service-invocation/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 5 - Service Invocation using Dapr 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 6 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 5 - Service Invocation using Dapr 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | This assignment is about using Dapr to invoke the `VehicleRegistrationService` from the `FineCollectionService`. You will use the [service invocation building block](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/service-invocation-overview/) provided by Dapr. This is the second step to reach the final state of the application for this challge. It is represented by the diagram below. 24 | 25 | ![Azure Container Apps Challenge - Second Deployment](../../../assets/images/aca-deployment-2.png) 26 | 27 | 28 | 29 | {% assign stepNumber = 1 %} 30 | {% include 09-bonus-assignments/01-service-invocation/1-use-dapr-to-invoke-vehicle-registration-service.md %} 31 | 32 | 33 | 34 | {% assign stepNumber = stepNumber | plus: 1 %} 35 | {% include 09-bonus-assignments/01-service-invocation/3-deploy-to-aca.md %} 36 | 37 | 38 | 39 | 40 | [< Assignment 4 - Deploy to Azure Container Apps]({{ site.baseurl }}{% link modules/11-aca-challenge/04-deploy-to-aca/index.md %}){: .btn .mt-7 } 41 | 42 | 43 | [Assignment 6 - Cosmos DB as a state store >]({{ site.baseurl }}{% link modules/11-aca-challenge/06-state-store/index.md %}){: .btn .float-right .mt-7 } 44 | 45 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/06-state-store/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 6 - Using Azure Cosmos DB as a state store 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 7 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 6 - Using Azure Cosmos DB as a state store 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | This assignment is about using [Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/) as a [state store](https://docs.dapr.io/operations/components/setup-state-store/) for the `TrafficControlService` instead of keeping the sate in memory. You will use the [Azure Cosmos DB state store component](https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-azure-cosmosdb/) provided by Dapr. This is the third step to reach the final state of the application for this challenge. It is represented by the diagram below. 24 | 25 | ![Azure Container Apps Challenge - Third Deployment](../../../assets/images/aca-deployment-3.png) 26 | 27 | ## Step 1: Create an Azure Cosmos DB 28 | 29 | {% include 09-bonus-assignments/02-state-store/1-1-create-cosmos-db.md %} 30 | 31 | ## Step 2: Deploy Azure Cosmos DB state store component to ACA 32 | 33 | 1. Open the file `dapr/aca-azure-cosmosdb-statestore.yaml` in your code editor and look at the content of the file. 34 | 35 | 1. **Copy or Move** this file `dapr/aca-azure-cosmosdb-statestore.yaml` to `dapr/components` folder. 36 | 37 | 1. **Replace** the following placeholders in this file `dapr/components/aca-azure-cosmosdb-statestore.yaml` with the values you noted down in the previous step: 38 | 39 | - `` with the Cosmos DB account URL 40 | - `` with the master key 41 | 42 | 1. Go to the root folder of the repository. 43 | 44 | 1. Enter the following command to deploy the `statestore` Dapr component: 45 | 46 | ```bash 47 | az containerapp env dapr-component set \ 48 | --name cae-dapr-workshop-java \ 49 | --resource-group rg-dapr-workshop-java \ 50 | --dapr-component-name statestore \ 51 | --yaml ./dapr/components/aca-azure-cosmosdb-statestore.yaml 52 | ``` 53 | 54 | ## Step 3: Add the Azure Cosmos DB state store to the `TrafficControlService` 55 | 56 | {% include 09-bonus-assignments/02-state-store/1-3-update-traffic-control-service.md %} 57 | 58 | 59 | 60 | {% assign stepNumber = 4 %} 61 | {% include 09-bonus-assignments/02-state-store/3-deploy-to-aca.md %} 62 | 63 | 64 | 65 | 66 | [< Assignment 5 - Service invocation]({{ site.baseurl }}{% link modules/11-aca-challenge/05-service-invocation/index.md %}){: .btn .mt-7 } 67 | 68 | 69 | [Assignment 7 - Key Vault as a secret store >]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/index.md %}){: .btn .float-right .mt-7 } 70 | 71 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/07-secret-store/1-setup-azure-key-vault.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setup Azure Key Vault as a secret store 3 | parent: Assignment 7 - Using Azure Key Vault as a secret store 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 1 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Setup Azure Key Vault as a secret store 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | The first part of this assignment is about using Azure Key Vault as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/). It consists in the creation of the Azure Key Vault resource and the deployment of [Azure Key Vault secret store component](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/) to Azure Container Apps environment. 25 | 26 | 27 | 28 | {% assign stepNumber = 1 %} 29 | {% include 09-bonus-assignments/03-secret-store/1-setup-azure-key-vault.md %} 30 | 31 | 32 | 33 | {% assign stepNumber = stepNumber | plus: 1 %} 34 | {% include 09-bonus-assignments/03-secret-store/5-1-deploy-secret-store-component-to-aca.md %} 35 | 36 | 37 | 38 | 39 | [< Assignment 7 - Key Vault as a secret store]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/index.md %}){: .btn .mt-7 } 40 | 41 | 42 | [Retreive a secret in the application >]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/2-use-secret-store-in-code.md %}){: .btn .float-right .mt-7 } 43 | 44 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/07-secret-store/2-use-secret-store-in-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Retrieve a secret in the application 3 | parent: Assignment 7 - Using Azure Key Vault as a secret store 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 2 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Retrieve a secret in the application 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | Previously, you have created an Azure Key Vault and added the Dapr component to Azure Container Apps environmnet. Now, you will use the [secret in the application](https://docs.dapr.io/developing-applications/building-blocks/secrets/howto-secrets/). This second part of the assignment is about using Azure Key Vault as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/) for the `FineCollectionService` to get the license key of the fine calculator. 25 | 26 | 27 | 28 | {% include 09-bonus-assignments/03-secret-store/2-use-secret-store-in-code.md %} 29 | 30 | ## Step 3: Build and redeploy fine collection service 31 | 32 | {% include 09-bonus-assignments/03-secret-store/5-2-a-rebuild-fine-collection-service.md %} 33 | 34 | 35 | 36 | {% assign stepNumber = 4 %} 37 | {% include 05-assignment-5-aks-aca/02-aca/0-3-test-application.md %} 38 | 39 | 40 | 41 | 42 | [< Setup Azure Key Vault]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/1-setup-azure-key-vault.md %}){: .btn .mt-7 } 43 | 44 | 45 | [Reference a secret in Dapr components >]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/3-use-secret-in-dapr-component.md %}){: .btn .float-right .mt-7 } 46 | 47 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/07-secret-store/3-use-secret-in-dapr-component.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Reference a secret in Dapr components 3 | parent: Assignment 7 - Using Azure Key Vault as a secret store 4 | grand_parent: Azure Container Apps Challenge 5 | has_children: false 6 | nav_order: 3 7 | layout: default 8 | has_toc: true 9 | --- 10 | 11 | # Reference a secret in Dapr components 12 | 13 | {: .no_toc } 14 | 15 |
16 | 17 | Table of contents 18 | 19 | {: .text-delta } 20 | - TOC 21 | {:toc} 22 |
23 | 24 | Previously, you have use a secret in `FineCollectionService` code using the `secretstore` component (i.e. Azure Key Vault). Now you will [use a secret from a secret store in another Dapr component](https://docs.dapr.io/operations/components/component-secrets/). This third part of the assignment is about using Azure Key Vault as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/) to store the connection string of the Azure Service Bus and use it in the `pubsub` component. 25 | 26 | 27 | 28 | {% include 09-bonus-assignments/03-secret-store/3-1-create-sb-connection-string-secret.md %} 29 | 30 | ## Step 2: Use a secret in `pubsub` component 31 | 32 | {% include 09-bonus-assignments/03-secret-store/5-2-b-1-use-secret-in-pubsub.md %} 33 | 34 | ## Step 3: Restart `FineCollectionService` and `TrafficControlService` 35 | 36 | {% include 09-bonus-assignments/03-secret-store/5-2-b-2-restart-services.md %} 37 | 38 | 39 | 40 | {% assign stepNumber = 4 %} 41 | {% include 05-assignment-5-aks-aca/02-aca/0-3-test-application.md %} 42 | 43 | {: .new-title } 44 | > Challenge 45 | > 46 | > You can use the secret store to store Cosmos DB master key as well. Try it out! More information on Cosmos DB as a state store can be found in [Bonus Assignment: State Store]({{ site.baseurl }}{% link modules/09-bonus-assignments/02-state-store/index.md %}). 47 | > 48 | 49 | 50 | 51 | 52 | [< Retreive a secret in the application]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/2-use-secret-store-in-code.md %}){: .btn .mt-7 } 53 | 54 | 55 | [Assignment 8 - Managed Identities >]({{ site.baseurl }}{% link modules/11-aca-challenge/08-managed-identities/index.md %}){: .btn .float-right .mt-7 } 56 | 57 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/07-secret-store/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 7 - Using Azure Key Vault as a secret store 3 | parent: Azure Container Apps Challenge 4 | has_children: true 5 | nav_order: 8 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | This assignment is about using [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/general/) as a [secret store](https://docs.dapr.io/operations/components/setup-secret-store/) for the `FineCollectionService`. You will use the [Azure Key Vault secret store component](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/) provided by Dapr. This the fourth step to reach the final state of the application for this challenge. It is represented in the diagram below. 11 | 12 | ![Azure Container Apps Challenge - Fourth Deployment](../../../assets/images/aca-deployment-4.png) 13 | 14 | There are 3 main parts in this assignment: 15 | 16 | 1. [Setup of the Azure Key Vault as a secret store]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/1-setup-azure-key-vault.md %}) 17 | 2. [Update of `FineCollectionService` to retrieve the license key from the Azure Key Vault using Dapr secret store component]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/2-use-secret-store-in-code.md %}). The license key is used by the fine calculator engine 18 | 3. [Use secrets of Azure Key Vault in the definition of other components]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/3-use-secret-in-dapr-component.md %}). Using Dapr, component manifests can reference secrets in a secret store. This is used to reference the Azure Service Bus connection string and the Azure Cosmos DB master key in the definition of the Azure Service Bus and Azure Cosmos DB components 19 | 20 | 21 | 22 | 23 | [< Assignment 6 - Cosmos DB as a state store]({{ site.baseurl }}{% link modules/11-aca-challenge/06-state-store/index.md %}){: .btn .mt-7 } 24 | 25 | 26 | [Setup Azure Key Vault >]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/1-setup-azure-key-vault.md %}){: .btn .float-right .mt-7 } 27 | 28 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/08-managed-identities/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 8 - Managed Identities 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 9 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 8 - Managed Identities 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | 24 | 25 | {% include 09-bonus-assignments/04-managed-identities/2-1-intro.md %} 26 | 27 | This is the fifth step to reach the final state of the application for this challenge. It is represented in the diagram below. 28 | 29 | ![Azure Container Apps Challenge - Fifth Deployment](../../../assets/images/aca-deployment-5.png) 30 | 31 | 32 | 33 | {% include 09-bonus-assignments/04-managed-identities/2-2-deploy-test-and-discussion.md %} 34 | 35 | 36 | 37 | 38 | [< Reference a secret in Dapr components]({{ site.baseurl }}{% link modules/11-aca-challenge/07-secret-store/3-use-secret-in-dapr-component.md %}){: .btn .mt-7 } 39 | 40 | 41 | [Assignment 9 - Scaling >]({{ site.baseurl }}{% link modules/11-aca-challenge/09-scaling/index.md %}){: .btn .float-right .mt-7 } 42 | 43 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/09-scaling/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assignment 9 - Scaling Fine Collection Service in Azure Container Apps 3 | parent: Azure Container Apps Challenge 4 | has_children: false 5 | nav_order: 10 6 | layout: default 7 | has_toc: true 8 | --- 9 | 10 | # Assignment 9 - Scaling Fine Collection Service in Azure Container Apps 11 | 12 | {: .no_toc } 13 | 14 |
15 | 16 | Table of contents 17 | 18 | {: .text-delta } 19 | - TOC 20 | {:toc} 21 |
22 | 23 | 24 | 25 | {% include 09-bonus-assignments/05-scaling/2-1-intro.md %} 26 | 27 | This is the last step of the challenge. At the end of this assignment you should have the final state of the architecture as shown in the following diagram: 28 | 29 | ![Final architecture of the challenge](../../../assets/images/workshop-end-state.png) 30 | 31 | 32 | 33 | {% include 09-bonus-assignments/05-scaling/2-2-deploy-and-test.md relativeAssetsPath="../../../assets/" %} 34 | 35 | 36 | 37 | ## Next Steps 38 | 39 | Well done, you have successfully completed the workshop! 40 | 41 | As next steps, you can: 42 | 43 | - Explore [Azure Container Apps documentation](https://docs.microsoft.com/en-us/azure/container-apps/). There are many other features that you can use like jobs, private networks, etc. Some of these features are still in preview. 44 | - Look at the [ACA Landing Zone Accelerator](https://github.com/Azure/ACA-Landing-Zone-Accelerator) and how to deploy a secure baseline with an internal environment. 45 | - The application of this workshop is used by the landing zone accelerator to demonstrate the [deployment of microservices in Azure Container Apps](https://github.com/Azure/aca-landing-zone-accelerator/tree/main/scenarios/aca-internal/bicep/sample-apps/java-fine-collection-service). It uses User Managed Identity to access Azure resources: Service Bus, Cosmos DB and Key Vault. 46 | - The sample app images used are based on the [end-to-end flow branch](https://github.com/Azure/java-aks-aca-dapr-workshop/tree/e2e-flow) that can be used to check your solutions for the workshop. 47 | - Contribute to this workshop by adding new challenges or improving the existing ones. 48 | 49 | 50 | 51 | {: .important-title } 52 | > Cleanup 53 | > 54 | > When the workshop is done, please follow the [cleanup instructions]({{ site.baseurl }}{% link modules/10-cleanup/index.md %}) to delete the resources created in this workshop. Do not forget to delete role assignements. 55 | > 56 | 57 | 58 | 59 | 60 | [< Assignment 8 - Managed Identities]({{ site.baseurl }}{% link modules/11-aca-challenge/08-managed-identities/index.md %}){: .btn .mt-7 } 61 | 62 | -------------------------------------------------------------------------------- /docs/modules/11-aca-challenge/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Azure Container Apps Challenge 3 | has_children: true 4 | nav_order: 11 5 | layout: default 6 | --- 7 | 8 | # Azure Container Apps Challenge 9 | 10 | In this challenge, you will cover most of the topics covered in the workshop and the bonus assignments. You will: 11 | 12 | - Deploy all 3 microservices to Azure Container Apps (ACA); 13 | - Use Azure Service Bus as a pub/sub Dapr component for the communication between Traffic Control Service and Fine Collection Service; 14 | - Use Azure Cosmos DB as a state store Dapr building block for Traffic Control Service; 15 | - Use the service invocation building block of Dapr to invoke the Vehicle Registration Service from the Fine Collection Service; 16 | - Use Azure Key Vault as a secret store Dapr building block for the Fine Collection Service. 17 | - Use managed identities to access Azure resources from the microservices. 18 | - Use scale rule to scale the Fine Collection Service based on the number of messages in the topic. 19 | 20 | The following diagram shows the architecture, that is the final state of this challenge: 21 | 22 | ![Final architecture of the challenge](../../assets/images/workshop-end-state.png) 23 | 24 | 25 | [Let's start!]({{ site.baseurl }}{% link modules/11-aca-challenge/00-intro/1-dapr-overview.md %}){: .btn .mt-7 } 26 | 27 | -------------------------------------------------------------------------------- /img/application-diagram-without-dapr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/application-diagram-without-dapr.png -------------------------------------------------------------------------------- /img/application-with-dapr-telemetry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/application-with-dapr-telemetry.png -------------------------------------------------------------------------------- /img/dapr-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/dapr-setup.png -------------------------------------------------------------------------------- /img/sequence-dapr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/sequence-dapr.png -------------------------------------------------------------------------------- /img/sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/sequence.png -------------------------------------------------------------------------------- /img/speed-trap-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/speed-trap-overview.png -------------------------------------------------------------------------------- /img/zipkin-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/java-aks-aca-dapr-workshop/3a9d645bcd598923ed8b89cb0d087328c666461e/img/zipkin-screenshot.png --------------------------------------------------------------------------------