diff --git a/00-setup-your-environment/README.md b/00-setup-your-environment/README.md index 1f782740..5d3b6706 100644 --- a/00-setup-your-environment/README.md +++ b/00-setup-your-environment/README.md @@ -1,6 +1,6 @@ # 00 - Setup your environment -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ In this section, we'll set up everything you need to expeditiously complete the training. @@ -8,12 +8,12 @@ In this section, we'll set up everything you need to expeditiously complete the ## Creating Azure Resources -To save time, we provide an ARM template for creating all the Azure resources you will need for this lab other than the Azure Spring Apps instance itself. Use the Deploy to Azure button below. +To save time, we provide an ARM template for creating all the Azure resources you will need for this lab other than the Azure Container Apps environment itself. Use the Deploy to Azure button below. > πŸ’‘ Use the following settings for deploying the Azure Template: > > * Create a new resource group. -> * In the location field, select the nearest region from [the list of regions where Azure Spring Apps is available](https://azure.microsoft.com/global-infrastructure/services/?products=spring-apps®ions=all). +> * In the location field, select the nearest region from [the list of regions where Azure Container Apps is available](https://azure.microsoft.com/explore/global-infrastructure/products-by-region/?products=container-apps). > * Save the MySQL password you specify in this step. You will need it in section 6. If you don't set one, it will be `super$ecr3t`. [![Deploy to Azure](media/deploybutton.svg)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2Fazure-spring-cloud-training%2Fmaster%2F00-setup-your-environment%2Fazuredeploy.json?WT.mc_id=asa-java-judubois) @@ -37,7 +37,7 @@ This training lab requires the following to be installed on your machine: > πŸ’‘ If you try the command above and you see the error `bash: az: command not found`, run the following command: `alias az='az.cmd'` and try again. -* 🚧 The `spring` extension for Azure CLI. You can install this extension after installing Azure CLI by running `az extension add -n spring -y`. If the extension is already installed, update it to the latest version by running `az extension update -n spring`. +* 🚧 The `containerapp` extension for Azure CLI. You can install this extension after installing Azure CLI by running `az extension add --name containerapp --upgrade`. If the extension is already installed, update it to the latest version by running `az extension update --name containerapp`. > πŸ’‘ In sections 9 and 10, you will access the UI of the Microservice applications in a web browser. Use the [new Edge](https://microsoft.com/edge/?WT.mc_id=java-spring-judubois), Google Chrome, or Firefox for these sections. @@ -47,4 +47,4 @@ You can then use Visual Studio Code or an IDE of your choice. --- -➑️ Next guide: [01 - Create an Azure Spring Apps instance](../01-create-an-azure-spring-cloud-instance/README.md) +➑️ Next guide: [01 - Create an Azure Container Apps environment](../01-create-an-azure-spring-cloud-instance/README.md) diff --git a/01-create-an-azure-spring-cloud-instance/README.md b/01-create-an-azure-spring-cloud-instance/README.md index bfe58537..edbc3c0b 100644 --- a/01-create-an-azure-spring-cloud-instance/README.md +++ b/01-create-an-azure-spring-cloud-instance/README.md @@ -1,8 +1,8 @@ -# 01 - Create an Azure Spring Apps instance +# 01 - Create an Azure Container Apps environment -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -In this section, we'll create an Azure Spring Apps instance using Azure CLI. While there are other ways of creating Azure resources, Azure CLI is the quickest and simplest method. +In this section, we'll create an Azure Container Apps environment using Azure CLI. While there are other ways of creating Azure resources, Azure CLI is the quickest and simplest method. --- @@ -20,38 +20,39 @@ az account show # See the currently signed-in account. Ensure your default subscription is the one you intend to use for this lab, and if not - set the subscription via ```az account set --subscription ``` -## Create an Azure Spring Apps instance +## Create an Azure Container Apps environment -In this section, we will create our Azure Spring Apps instance using Azure CLI. +In this section, we will create our Azure Container Apps environment using Azure CLI. -First, you will need to come up with a name for your Azure Spring Apps instance. +First, you will need to come up with a name for your Azure Container Apps environment. -- __The name must be unique among all Azure Spring Apps instances across all of Azure__. Consider using your username as part of the name. -- The name can contain only lowercase letters, numbers and hyphens. The first character must be a letter. The last character must be a letter or number. The value must be between 4 and 32 characters long. +- __The name must be unique within your resource group__. +- The name can contain only lowercase letters, numbers and hyphens. The first character must be a letter. The last character must be a letter or number. The value must be between 2 and 32 characters long. -To limit typing, set the variable `AZ_RESOURCE_GROUP` to the name of the resource group created in the previous section. Set the variable `AZ_SPRING_APPS_NAME` to the name of the Azure Spring Apps instance to be created: +To limit typing, set the variable `AZ_RESOURCE_GROUP` to the name of the resource group created in the previous section. Set the variable `AZ_CONTAINERAPP_ENV` to the name of the Azure Container Apps environment to be created: ->πŸ›‘ Be sure to substitute your own values for `AZ_RESOURCE_GROUP` and `AZ_SPRING_APPS_NAME` as described above. __`AZ_SPRING_APPS_NAME` must be globally unique, use lowercase letters and should not have special characters.__ +>πŸ›‘ Be sure to substitute your own values for `AZ_RESOURCE_GROUP` and `AZ_CONTAINERAPP_ENV` as described above. ```bash export AZ_RESOURCE_GROUP=spring-apps-lab -export AZ_SPRING_APPS_NAME=azure-spring-apps-lab +export AZ_CONTAINERAPP_ENV=aca-env-lab +export AZ_LOCATION=eastus ``` -With these variables set, we can now create the Azure Spring Apps instance. +With these variables set, we can now create the Azure Container Apps environment. ```bash -az spring create \ - -g "$AZ_RESOURCE_GROUP" \ - -n "$AZ_SPRING_APPS_NAME" \ - --sku standard +az containerapp env create \ + --name "$AZ_CONTAINERAPP_ENV" \ + --resource-group "$AZ_RESOURCE_GROUP" \ + --location "$AZ_LOCATION" ``` -For the remainder of this workshop, we will be running Azure CLI commands referencing the same resource group and Azure Spring Apps instance. So let's set them as defaults, so we don't have to specify them again: +For the remainder of this workshop, we will be running Azure CLI commands referencing the same resource group and Azure Container Apps environment. So let's set them as defaults, so we don't have to specify them again: ```bash az configure --defaults group=$AZ_RESOURCE_GROUP -az configure --defaults spring=$AZ_SPRING_APPS_NAME +az configure --defaults location=$AZ_LOCATION ``` --- diff --git a/02-build-a-simple-spring-boot-microservice/README.md b/02-build-a-simple-spring-boot-microservice/README.md index 4c039fa2..473dec75 100644 --- a/02-build-a-simple-spring-boot-microservice/README.md +++ b/02-build-a-simple-spring-boot-microservice/README.md @@ -1,8 +1,8 @@ # 02 - Build a simple Spring Boot microservice -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -In this section, we'll build a simple Spring boot microservice and deploy it to Azure Spring Apps. This will give us a starting point for adding Spring Cloud technologies in later sections. +In this section, we'll build a simple Spring boot microservice and deploy it to Azure Container Apps. This will give us a starting point for adding Spring Cloud technologies in later sections. --- @@ -39,7 +39,7 @@ public class HelloController { @GetMapping("/hello") public String hello() { - return "Hello from Azure Spring Apps\n"; + return "Hello from Azure Container Apps\n"; } } ``` @@ -56,7 +56,7 @@ cd simple-microservice cd .. ``` -Requesting the `/hello` endpoint should return the "Hello from Azure Spring Apps" message. +Requesting the `/hello` endpoint should return the "Hello from Azure Container Apps" message. ```bash curl http://127.0.0.1:8080/hello @@ -68,68 +68,100 @@ Finally, kill running app: kill %1 ``` -## Create and deploy the application on Azure Spring Apps +## Create and deploy the application on Azure Container Apps -This section shows how to create an app instance and then deploy your code to it. +This section shows how to build a container image and deploy it to Azure Container Apps. -In order to create the app instance graphically, you can use [the Azure portal](https://portal.azure.com/?WT.mc_id=java-asa-judubois): +First, we need to build the application and create a container image. We'll use Docker to build the container image. -- Look for your Azure Spring Apps instance in your resource group -- Click on the "Apps" link under "Settings" on the navigation sidebar. -- Click on "Create App" link at the top of the Apps page. -- Create a new application named "simple-microservice", using the Java 17 environment. - -![Create application](media/00-create-application.png) - -- Click on "Create". - -Alternatively, you can use the command line to create the app instance, which is easier: +Create a `Dockerfile` in the `simple-microservice` directory: ```bash -az spring app create -n simple-microservice --runtime-version Java_17 +cd simple-microservice +cat > Dockerfile << 'EOF' +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] +EOF +cd .. ``` -You can now build your "simple-microservice" project and deploy it to Azure Spring Apps: +Now build your "simple-microservice" project and deploy it to Azure Container Apps: ```bash cd simple-microservice ./mvnw clean package -az spring app deploy -n simple-microservice --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +# Build and deploy directly to Azure Container Apps +az containerapp up \ + --name simple-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --source . \ + --target-port 8080 \ + --ingress external + cd .. ``` -This creates a jar file on your local disk and uploads it to the app instance you created in the preceding step. The `az` command will output a result in JSON. You don't need to pay attention to this output right now, but in the future, you will find it useful for diagnostic and testing purposes. +This command builds your application from source, creates a container image, and deploys it to Azure Container Apps with an external ingress endpoint. ## Test the project in the cloud Go to [the Azure portal](https://portal.azure.com/?WT.mc_id=azurespringcloud-github-judubois): -- Look for your Azure Spring Apps instance in your resource group -- Click "Apps" in the "Settings" section of the navigation pane and select "simple-microservice" -- Find the "Test endpoint" in the "Essentials" section. -![Test endpoint](media/01-test-endpoint.png) -- This will give you something like: - `https://primary:BBQM6nsYnmmdQREXQINityNx63kWUbjsP7SIvqKhOcWDfP6HJTqg27klMLaSfpTB@rwo1106f.test.azuremicroservices.io/simple-microservice/default/` - >πŸ’‘ Note the text between `https://` and `@`. These are the basic authentication credentials, without which you will not be authorized to access the service. -- Append `hello` to the URL. Failure to do this will result in a "404 not found". +- Look for your Azure Container Apps environment in your resource group +- Click on your container app "simple-microservice" +- Find the "Application Url" in the "Essentials" section. + +You can also get the URL using the Azure CLI: -You can now use cURL again to test the `/hello` endpoint, this time served by Azure Spring Apps. For example. +```bash +az containerapp show \ + --name simple-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv +``` + +You can now use cURL to test the `/hello` endpoint: ```bash -curl https://primary:...simple-microservice/default/hello +SIMPLE_MICROSERVICE_URL=$(az containerapp show \ + --name simple-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv) + +curl https://$SIMPLE_MICROSERVICE_URL/hello ``` -If successful, you should see the message: `Hello from Azure Spring Apps`. +If successful, you should see the message: `Hello from Azure Container Apps`. ## Conclusion -Congratulations, you have deployed your first Spring Boot microservice to Azure Spring Apps! +Congratulations, you have deployed your first Spring Boot microservice to Azure Container Apps! If you need to check your code, the final project is available in the ["simple-microservice" folder](simple-microservice/). Here is the final script to build and deploy everything that was done in this guide: -``` +```bash curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=web -d baseDir=simple-microservice -d bootVersion=3.1.3 -d javaVersion=17 | tar -xzvf - cd simple-microservice cat > HelloController.java << EOF @@ -143,19 +175,46 @@ public class HelloController { @GetMapping("/hello") public String hello() { - return "Hello from Azure Spring Apps"; + return "Hello from Azure Container Apps"; } } EOF mv HelloController.java src/main/java/com/example/demo/HelloController.java -az spring app create -n simple-microservice --runtime-version Java_17 + +cat > Dockerfile << 'EOF' +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] +EOF + ./mvnw clean package -az spring app deploy -n simple-microservice --artifact-path target/demo-0.0.1-SNAPSHOT.jar +az containerapp up \ + --name simple-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --source . \ + --target-port 8080 \ + --ingress external cd .. ``` --- -⬅️ Previous guide: [01 - Create an Azure Spring Apps instance](../01-create-an-azure-spring-cloud-instance/README.md) +⬅️ Previous guide: [01 - Create an Azure Container Apps environment](../01-create-an-azure-spring-cloud-instance/README.md) ➑️ Next guide: [03 - Configure monitoring](../03-configure-monitoring/README.md) diff --git a/02-build-a-simple-spring-boot-microservice/simple-microservice/src/main/java/com/example/demo/HelloController.java b/02-build-a-simple-spring-boot-microservice/simple-microservice/src/main/java/com/example/demo/HelloController.java index d3e14671..167bc97e 100644 --- a/02-build-a-simple-spring-boot-microservice/simple-microservice/src/main/java/com/example/demo/HelloController.java +++ b/02-build-a-simple-spring-boot-microservice/simple-microservice/src/main/java/com/example/demo/HelloController.java @@ -14,6 +14,6 @@ public class HelloController { @GetMapping("/hello") public String hello() { - return "Hello from Azure Spring Apps\n"; + return "Hello from Azure Container Apps\n"; } } diff --git a/03-configure-monitoring/README.md b/03-configure-monitoring/README.md index 3685bd18..62186413 100644 --- a/03-configure-monitoring/README.md +++ b/03-configure-monitoring/README.md @@ -1,6 +1,6 @@ # 03 - Configure application logs -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ Now that we have an application deployed, we'll configure Log Analytics, so that we can quickly search the application's logs if something goes wrong. We'll see how to take advantage of Log Analytics in a later section, but because it takes time for log entries to start coming in, we'll do the configuration steps here before moving on with the training. @@ -8,20 +8,34 @@ Now that we have an application deployed, we'll configure Log Analytics, so that ## Configure log aggregation -There are actually three ways to access your application's logs: [Azure Storage](https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction/?WT.mc_id=azurespringcloud-github-judubois), [Azure Events Hub](https://docs.microsoft.com/en-us/azure/event-hubs/?WT.mc_id=azurespringcloud-github-judubois), and [Log Analytics](https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/get-started-portal/?WT.mc_id=azurespringcloud-github-judubois). We will focus here on Log Analytics as it's the most common one, and as it's integrated into Azure Spring Apps. +There are actually three ways to access your application's logs: [Azure Storage](https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction/?WT.mc_id=azurespringcloud-github-judubois), [Azure Events Hub](https://docs.microsoft.com/en-us/azure/event-hubs/?WT.mc_id=azurespringcloud-github-judubois), and [Log Analytics](https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/get-started-portal/?WT.mc_id=azurespringcloud-github-judubois). We will focus here on Log Analytics as it's the most common one, and as it's integrated into Azure Container Apps. -[Log Analytics](https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/get-started-portal/?WT.mc_id=azurespringcloud-github-judubois) is part of [Azure Monitor](https://azure.microsoft.com/en-us/services/monitor/?WT.mc_id=azurespringcloud-github-judubois), which is well-integrated into Azure Spring Apps and which we will also use for metrics monitoring. +[Log Analytics](https://docs.microsoft.com/en-us/azure/azure-monitor/log-query/get-started-portal/?WT.mc_id=azurespringcloud-github-judubois) is part of [Azure Monitor](https://azure.microsoft.com/en-us/services/monitor/?WT.mc_id=azurespringcloud-github-judubois), which is well-integrated into Azure Container Apps and which we will also use for metrics monitoring. -Having completed the setup in [Section 00](../00-setup-your-environment/README.md), you should have a Log Analytics workspace named `sclab-la-` in your resource group for this workshop. We must now configure our Azure Spring Apps instance to send its data to this workspace. +Having completed the setup in [Section 00](../00-setup-your-environment/README.md), you should have a Log Analytics workspace named `sclab-la-` in your resource group for this workshop. -- Navigate to the Azure Spring Apps instance in Azure Portal and select "Diagnostic settings" in the "Monitoring" section of the navigation pane: +Azure Container Apps automatically sends logs to Log Analytics when you create the environment. When you created the Container Apps environment in Section 01, it was automatically configured to use a Log Analytics workspace. -![Diagnostic Settings](media/01-diagnostic-settings.png) +To verify the logs are flowing: -- Click on "Add diagnostic setting" and configure your instance to send all its logs to the Log analytics workspace that we just created. -- Fill in the values as shown here and click "Save". +- Navigate to your Azure Container Apps environment in the Azure Portal +- Select "Logs" in the "Monitoring" section of the navigation pane +- You can now run queries against your container app logs using the Kusto query language -![Send logs to the log analytics workspace](media/02-send-logs-to-log-analytics-workspace.png) +For example, to see recent logs from your simple-microservice: + +```kusto +ContainerAppConsoleLogs_CL +| where ContainerAppName_s == "simple-microservice" +| order by TimeGenerated desc +| take 100 +``` + +You can also view logs for individual container apps: + +- Navigate to your container app (e.g., "simple-microservice") in the Azure Portal +- Select "Log stream" to see real-time logs +- Or select "Logs" for more advanced querying capabilities ⬅️ Previous guide: [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md) diff --git a/04-configure-a-spring-cloud-config-server/AzureReposForConfig.md b/04-configure-a-spring-cloud-config-server/AzureReposForConfig.md index a9c86623..da863b4a 100644 --- a/04-configure-a-spring-cloud-config-server/AzureReposForConfig.md +++ b/04-configure-a-spring-cloud-config-server/AzureReposForConfig.md @@ -1,8 +1,8 @@ -# 04a - Using Azure Repos for Azure Spring Apps Configuration +# 04a - Using Azure Repos for Configuration -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -Configure a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config), that will be entirely managed and supported by Azure Spring Apps, to be used by Spring Boot microservices. +Configure a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config), deployed as a container app, to be used by Spring Boot microservices. --- @@ -18,14 +18,14 @@ Configure a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-co ```yml application: - message: Configured by Azure Spring Apps + message: Configured by Azure Container Apps ``` Commit and push the new file. ## Obtain Repository URL and Credentials -Azure Spring Apps can access Git repositories that are public, secured by SSH, or secured using HTTP basic authentication. We will use that last option, as it is easier to create and manage with Azure Repos. +Spring Cloud Config Server can access Git repositories that are public, secured by SSH, or secured using HTTP basic authentication. We will use that last option, as it is easier to create and manage with Azure Repos. 1. In the Azure Repos portal for your project, click the "Clone" button: @@ -48,23 +48,35 @@ Azure Spring Apps can access Git repositories that are public, secured by SSH, o 1. Click "Generate Git Credentials". A username and password will appear. Save these for use in the next section. -## Configure Azure Spring Apps to access the Git repository - -- Go to [the Azure portal](https://portal.azure.com/?WT.mc_id=azurespringcloud-github-judubois). -- Go to the overview page of your Azure Spring Apps server and select "Config server" in the menu -- Configure the repository we previously created: - - Add the repository URL that you have saved from the previous section. - - - Click on `Authentication` and select `HTTP Basic` - - The __username__ is the username saved from the previous section - - The __password__ is the password saved from the previous section -- Click on "Apply" and wait for the operation to succeed - -![Spring Cloud config server](media/03-config-server-azdo.png) +## Deploy Spring Cloud Config Server to Azure Container Apps + +Now deploy the Spring Cloud Config Server as a container app, configured with your Azure Repos credentials: + +```bash +# Set your Azure DevOps organization, project, and repository details +export AZDO_ORG_URL=https://dev.azure.com///_git/ +export AZDO_USERNAME= +export AZDO_PASSWORD= + +az containerapp create \ + --name config-server \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --image hyness/spring-cloud-config-server:latest \ + --target-port 8888 \ + --ingress internal \ + --env-vars \ + SPRING_CLOUD_CONFIG_SERVER_GIT_URI=$AZDO_ORG_URL \ + SPRING_CLOUD_CONFIG_SERVER_GIT_DEFAULT_LABEL=main \ + SPRING_CLOUD_CONFIG_SERVER_GIT_USERNAME=$AZDO_USERNAME \ + SPRING_CLOUD_CONFIG_SERVER_GIT_PASSWORD=$AZDO_PASSWORD \ + --min-replicas 1 \ + --max-replicas 1 +``` ## Review -We have now created a private configuration repository. We have enabled Azure Spring Apps to create a configuration server with the configuration files from this repository. +We have now created a private configuration repository and deployed a Spring Cloud Config Server as a container app with the configuration files from this repository. In the next section, we will create an application that consumes this configuration, specifically the custom message we defined in `application.yml`. diff --git a/04-configure-a-spring-cloud-config-server/README.md b/04-configure-a-spring-cloud-config-server/README.md index 2303ec6c..5020854a 100644 --- a/04-configure-a-spring-cloud-config-server/README.md +++ b/04-configure-a-spring-cloud-config-server/README.md @@ -1,24 +1,14 @@ # 04 - Configure a Spring Cloud Config server -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -A key feature of cloud-native applications is *externalized configuration* - the ability to store, manage, and version configuration separately from the application code. In this section, we'll configure a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config) to enable this functionality. In the next section, you'll see how Spring Cloud Config can inject configuration from a Git repository into your application. +A key feature of cloud-native applications is *externalized configuration* - the ability to store, manage, and version configuration separately from the application code. In this section, we'll deploy a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config) as a container app to enable this functionality. In the next section, you'll see how Spring Cloud Config can inject configuration from a Git repository into your application. --- -> πŸ’‘ If your organization uses Azure Repos as your source code repository, see [Using Azure Repos for Azure Spring Apps configuration](AzureReposForConfig.md) +> πŸ’‘ If your organization uses Azure Repos as your source code repository, see [Using Azure Repos for configuration](AzureReposForConfig.md) > ⏱ If you want to skip the step of creating a private repository, you can use this public repository instead: [https://github.com/Azure-Samples/spring-cloud-sample-public-config.git](https://github.com/Azure-Samples/spring-cloud-sample-public-config.git). __Storing configuration in a public repository is not recommended in real-world deployments.__ We offer this public repository only as a shortcut for this workshop, for example if you don't have a GitHub account. -> -> To use this shortcut: -> - Go to [the Azure portal](https://portal.azure.com/?WT.mc_id=java-0000-judubois). -> - Go to the overview page of your Azure Spring Apps server and select "Config server" in the menu -> - Set the repository URL: `https://github.com/Azure-Samples/spring-cloud-sample-public-config.git` -> - Click on "Validate" and wait for the operation to succeed -> - Click on "Apply" and wait for the operation to succeed -> -> We have enabled Azure Spring Apps to create a configuration server with the configuration files from this repository. You can now proceed to the next guide: -> ➑ [05 - Build a Spring Boot microservice using Spring Cloud features](../05-build-a-spring-boot-microservice-using-spring-cloud-features/README.md) ## Create a Git repository for storing the application configuration @@ -32,16 +22,16 @@ For the moment, our `application.yml` will just store a message to check if the ```yaml application: - message: Configured by Azure Spring Apps + message: Configured by Azure Container Apps ``` Commit and push the new file. ## Create a GitHub personal token -Azure Spring Apps can access Git repositories that are public, secured by SSH, or secured using HTTP basic authentication. We will use that last option, as it is easier to create and manage with GitHub. +Spring Cloud Config Server can access Git repositories that are public, secured by SSH, or secured using HTTP basic authentication. We will use that last option, as it is easier to create and manage with GitHub. -Let's create a new token by going into the GitHub developer settings and selecting "Personal access tokens" and "Fine-grained tokens" in the menu. Give it a name such as `spring apps training`. +Let's create a new token by going into the GitHub developer settings and selecting "Personal access tokens" and "Fine-grained tokens" in the menu. Give it a name such as `container apps training`. ![GitHub personal access token](media/01-github-personal-access-token.png) @@ -65,26 +55,79 @@ Once the token is generated, leave that tab open until the end of this section. If you need more help here, please follow the [GitHub guide to create a personal token documentation.](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) -## Configure Azure Spring Apps to access the Git repository +## Deploy Spring Cloud Config Server to Azure Container Apps -- Go to [the Azure portal](https://portal.azure.com/?WT.mc_id=java-0000-judubois). -- Go to the overview page of your Azure Spring Apps server and select "Config server" in the menu -- Configure the repository we previously created: - - Add the repository URL, for example `https://github.com/Azure-Samples/spring-cloud-sample-public-config.git` +Now we'll deploy Spring Cloud Config Server as a container app. We'll use the official Spring Cloud Config Server Docker image and configure it with environment variables. - >πŸ’‘ Make sure you include the `.git` ending in the URL. - - For the label, select the branch name, for example the GitHub default `main` - - Click on `Authentication` and select `HTTP Basic` - - The __username__ is your GitHub login name - - The __password__ is the personal token we created in the previous section -- Click on "Validate" and wait for the operation to succeed -- Click on "Apply" and wait for the operation to succeed +First, set environment variables for your Git repository: -![Spring Cloud config server](media/06-config-server.png) +>πŸ›‘ Replace `YOUR_GITHUB_USERNAME` with your GitHub username and `YOUR_GITHUB_TOKEN` with the token you created above. Replace `YOUR_REPO_NAME` with your config repository name (e.g., `spring-cloud-config-repo`). + +```bash +export GIT_REPO_URI=https://github.com/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME.git +export GIT_USERNAME=YOUR_GITHUB_USERNAME +export GIT_PASSWORD=YOUR_GITHUB_TOKEN +``` + +Or, if using the public sample repository: + +```bash +export GIT_REPO_URI=https://github.com/Azure-Samples/spring-cloud-sample-public-config.git +``` + +Now deploy the Spring Cloud Config Server: + +```bash +az containerapp create \ + --name config-server \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --image hyness/spring-cloud-config-server:latest \ + --target-port 8888 \ + --ingress internal \ + --env-vars \ + SPRING_CLOUD_CONFIG_SERVER_GIT_URI=$GIT_REPO_URI \ + SPRING_CLOUD_CONFIG_SERVER_GIT_DEFAULT_LABEL=main \ + SPRING_CLOUD_CONFIG_SERVER_GIT_USERNAME=$GIT_USERNAME \ + SPRING_CLOUD_CONFIG_SERVER_GIT_PASSWORD=$GIT_PASSWORD \ + --min-replicas 1 \ + --max-replicas 1 +``` + +> πŸ’‘ Note: We're using `--ingress internal` so the config server is only accessible from within the Container Apps environment, not from the public internet. This is a security best practice. + +If using the public repository (without authentication): + +```bash +az containerapp create \ + --name config-server \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --image hyness/spring-cloud-config-server:latest \ + --target-port 8888 \ + --ingress internal \ + --env-vars \ + SPRING_CLOUD_CONFIG_SERVER_GIT_URI=https://github.com/Azure-Samples/spring-cloud-sample-public-config.git \ + SPRING_CLOUD_CONFIG_SERVER_GIT_DEFAULT_LABEL=main \ + --min-replicas 1 \ + --max-replicas 1 +``` + +Get the internal URL of the config server: + +```bash +CONFIG_SERVER_URL=$(az containerapp show \ + --name config-server \ + --resource-group $AZ_RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv) + +echo "Config Server URL: http://$CONFIG_SERVER_URL" +``` ## Review -We have now created a private configuration repository. We have enabled Azure Spring Apps to create a configuration server with the configuration files from this repository. +We have now created a private configuration repository and deployed a Spring Cloud Config Server as a container app with the configuration files from this repository. In the next section, we will create an application that consumes this configuration, specifically the custom message we defined in `application.yml`. diff --git a/05-build-a-spring-boot-microservice-using-spring-cloud-features/README.md b/05-build-a-spring-boot-microservice-using-spring-cloud-features/README.md index d63fecc5..b4798d71 100644 --- a/05-build-a-spring-boot-microservice-using-spring-cloud-features/README.md +++ b/05-build-a-spring-boot-microservice-using-spring-cloud-features/README.md @@ -1,20 +1,18 @@ # 05 - Build a Spring Boot microservice using Spring Cloud features -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -In this section, we'll build a similar service to the one from section 2, but with the addition of two important Spring Cloud features. First, we'll add this service to Spring Cloud registry for discovery by other services. Second, we'll use Spring Cloud Config to inject a setting from a Git repository into the application and display it on the screen. +In this section, we'll build a similar service to the one from section 2, but with the addition of Spring Cloud Config client capabilities. We'll use Spring Cloud Config to inject a setting from a Git repository (via our config server) into the application and display it on the screen. --- ## What we are going to build -This guide builds upon the previous guides: we are going to build again a simple Spring Boot microservice like in [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md), but this time it will use two major Spring Cloud features: - -- It will be connected to a Spring Cloud Service Registry so it can discover other microservices, as well as being discovered itself! +This guide builds upon the previous guides: we are going to build again a simple Spring Boot microservice like in [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md), but this time it will use Spring Cloud Config: - It will get its configuration from the Spring Cloud Config server that we configured in the previous guide, [04 - Configure a Spring Cloud Config server](../04-configure-a-spring-cloud-config-server/README.md) -For both features, it will just be a matter of adding an official Spring Boot starter, and Azure Spring Apps will take care of everything else. +It will just be a matter of adding an official Spring Boot starter, and configuring the connection to our config server. ## Create a simple Spring Cloud microservice @@ -23,10 +21,10 @@ The microservice that we create in this guide is [available here](spring-cloud-m To create our microservice, we will invoke the Spring Initalizer service from the command line: ```bash -curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=web,cloud-eureka,cloud-config-client -d baseDir=spring-cloud-microservice -d bootVersion=3.1.3 -d javaVersion=17 | tar -xzvf - +curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=web,cloud-config-client -d baseDir=spring-cloud-microservice -d bootVersion=3.1.3 -d javaVersion=17 | tar -xzvf - ``` -> This time, we add the `Eureka Discovery Client` and the `Config Client` Spring Boot starters, which will respectively automatically trigger the use of Spring Cloud Service Registry and the Spring Cloud Config Server. +> This time, we add the `Config Client` Spring Boot starter, which will automatically trigger the use of the Spring Cloud Config Server. ## Add a new Spring MVC Controller @@ -54,17 +52,20 @@ public class HelloController { ## Configure Spring Boot -Edit the file `src/main/resources/application.properties` and add the following line: +Edit the file `src/main/resources/application.properties` and add the following lines: ```properties -spring.config.import=optional:configserver: +spring.config.import=optional:configserver:http://${CONFIG_SERVER_URL:localhost:8888} +spring.application.name=spring-cloud-microservice ``` -This line makes using the Spring Cloud Config server optional. This will be useful in development mode (when we won't have a Spring Cloud Config server), and can be removed later in production. +The first line makes the Spring Cloud Config server optional for local development. The second line sets the application name, which will be used by the config server to identify which configuration to serve. + +> πŸ’‘ The `CONFIG_SERVER_URL` will be provided as an environment variable when we deploy to Azure Container Apps. ## Test the project locally -Before deploying the microservice to Azure Spring Apps, let's run it locally. +Before deploying the microservice to Azure Container Apps, let's run it locally. >πŸ’‘ Do not be alarmed when you see exception stack traces: > ![Exception stack trace](media/01-exception-stack-trace.png) @@ -90,47 +91,92 @@ Kill the locally running microservice: kill %1 ``` -## Create and deploy the application on Azure Spring Apps +## Create and deploy the application on Azure Container Apps -As in [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md), create a specific `spring-cloud-microservice` application in your Azure Spring Apps instance: +First, create a `Dockerfile` in the `spring-cloud-microservice` directory: ```bash -az spring app create -n spring-cloud-microservice --runtime-version Java_17 +cd spring-cloud-microservice +cat > Dockerfile << 'EOF' +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] +EOF +cd .. ``` -You can now build your "spring-cloud-microservice" project and send it to Azure Spring Apps: +Now get the config server URL and deploy the application: ```bash +# Get the config server internal URL +CONFIG_SERVER_URL=$(az containerapp show \ + --name config-server \ + --resource-group $AZ_RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv) + cd spring-cloud-microservice ./mvnw clean package -DskipTests -az spring app deploy -n spring-cloud-microservice --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +# Deploy to Azure Container Apps +az containerapp up \ + --name spring-cloud-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --source . \ + --target-port 8080 \ + --ingress external \ + --env-vars CONFIG_SERVER_URL=$CONFIG_SERVER_URL + cd .. ``` ## Test the project in the cloud -Go to [the Azure portal](https://portal.azure.com/?WT.mc_id=azurespringcloud-github-judubois): +Get the URL for your microservice: -- Look for your Azure Spring Apps instance in your resource group -- Go to "Apps" - - Verify that `spring-cloud-microservice` has a `Registration status` of `1/1`. This shows that it is correctly registered in Spring Cloud Service Registry. - - Select `spring-cloud-microservice` to have more information on the microservice. -- Copy/paste the "Test endpoint" that is provided. +```bash +MICROSERVICE_URL=$(az containerapp show \ + --name spring-cloud-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv) -You can now use cURL again to test the `/hello` endpoint, this time it is served by Azure Spring Apps and configured using the Spring Config Server from [04 - Configure a Spring Cloud Config server](../04-configure-a-spring-cloud-config-server/README.md). +curl https://$MICROSERVICE_URL/hello +``` + +You can now use cURL to test the `/hello` endpoint, this time it is served by Azure Container Apps and configured using the Spring Config Server from [04 - Configure a Spring Cloud Config server](../04-configure-a-spring-cloud-config-server/README.md). As a result, requesting the `/hello` endpoint should return the message that we configured in the `application.yml` file, coming from the Spring Cloud Config Server: ```bash -Configured by Azure Spring Apps +Configured by Azure Container Apps ``` ## Stream application logs -When you run an application on your machine, you can see its output in the console. When you run a microservice on Azure Spring Apps, you can also see its console output through Azure CLI: +When you run an application on your machine, you can see its output in the console. When you run a microservice on Azure Container Apps, you can also see its console output through Azure CLI: ```bash -az spring app logs -n spring-cloud-microservice -f +az containerapp logs show \ + --name spring-cloud-microservice \ + --resource-group $AZ_RESOURCE_GROUP \ + --follow ``` _Please be aware it might take a couple of minutes for the logs to show up._ @@ -143,21 +189,19 @@ Press CTRL+C to stop following the output and return to the shell. ## Query application logs -Streaming the console output as we just did may be helpful in understanding the immediate state of a microservice. However, sometimes it's necessary to look further into the past or to look for something specific. This is easily done with Log Analytics. In section 3, we enabled log aggregation in Azure Log Analytics. Such settings changes can take 1-2 minutes to apply, so by now, you should be able to query Azure Log Analytics. +Streaming the console output as we just did may be helpful in understanding the immediate state of a microservice. However, sometimes it's necessary to look further into the past or to look for something specific. This is easily done with Log Analytics. In section 3, we configured log aggregation in Azure Log Analytics. -[Open Azure Portal](https://portal.azure.com/?WT.mc_id=java-spring-judubois) and navigate to your Azure Spring Apps instance. Click on "Logs". This is a shortcut to the Log Analytics workspace that was created earlier. If a tutorial appears, feel free to skip it for now. +[Open Azure Portal](https://portal.azure.com/?WT.mc_id=java-spring-judubois) and navigate to your Container Apps environment. Click on "Logs". This is a shortcut to the Log Analytics workspace that was created earlier. If a tutorial appears, feel free to skip it for now. This workspace allows you to run queries on the aggregated logs. The most common query is to get the latest log from a specific application: -__Important:__ Spring Boot applications logs have a dedicated `AppPlatformLogsforSpring` type. - -Here is how to get its 50 most recent logs of the `AppPlatformLogsforSpring` type for the microservice we just deployed: +Here is how to get the 50 most recent logs for the microservice we just deployed: -Insert this text in the text area that states "Type your queries here or click on of the example queries to start". Click the text of the query, then click "Run". +Insert this text in the text area that states "Type your queries here or click on of the example queries to start". Click the text of the query, then click "Run". -```sql -AppPlatformLogsforSpring -| where AppName == "spring-cloud-microservice" +```kusto +ContainerAppConsoleLogs_CL +| where ContainerAppName_s == "spring-cloud-microservice" | project TimeGenerated, Log | order by TimeGenerated desc | limit 50 @@ -165,7 +209,7 @@ AppPlatformLogsforSpring ![Query logs](media/03-logs-query.png) ->πŸ’‘ It can also take 1-2 minutes for the console output of an Azure Spring Apps microservice to be read into Log Analytics. +>πŸ’‘ It can also take 1-2 minutes for the console output of an Azure Container Apps microservice to be read into Log Analytics. ## Conclusion diff --git a/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/README.md b/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/README.md index b07ee29b..2e01d1ea 100644 --- a/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/README.md +++ b/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/README.md @@ -1,6 +1,6 @@ # 06 - Build a reactive Spring Boot microservice using Cosmos DB -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ In this section, we'll build an application that uses a [Cosmos DB database](https://docs.microsoft.com/en-us/azure/cosmos-db/?WT.mc_id=azurespringcloud-github-judubois) in order to access a globally-distributed database with optimum performance. @@ -13,7 +13,7 @@ We'll use the reactive programming paradigm to build our microservice in this se From Section 00, you should already have a Cosmos DB account named `sclabc-`. - Click on the `Data Explorer` menu item - - Expand the container named `azure-spring-apps-cosmosdb`. + - Expand the container named `azure-container-apps-cosmosdb`. - In that container, expand the container named `City`. - Click on `Items` and use the `New Item` button to create some sample items using the contents below: @@ -41,7 +41,7 @@ To create our microservice, we will invoke the Spring Initalizr service from the curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=webflux,cloud-eureka,cloud-config-client -d baseDir=city-service -d bootVersion=3.1.3 -d javaVersion=17 | tar -xzvf - ``` -> We use the `Spring WebFlux`, `Eureka Discovery Client` and the `Config Client` Spring Boot starters. +> We use the `Spring WebFlux`, `Eureka Discovery Client` and the `Config Client` Spring Boot starters. Note: For Azure Container Apps, we won't be using service discovery, but we keep these dependencies for consistency with the original code. ## Add the Azure Cosmos DB API @@ -79,7 +79,7 @@ class City { Then, in the same location, create a new `CityController.java` file that contains the code that will be used to query the database. -> The CityController class will get its Cosmos DB configuration from the Azure Spring Apps Service Connector that we will configure later. +> The CityController class will get its Cosmos DB configuration from environment variables that we will configure later. ```java package com.example.demo; @@ -131,65 +131,81 @@ public class CityController { } ``` -## Create the application on Azure Spring Apps +## Create a Dockerfile -As in [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md), create a specific `city-service` application in your Azure Spring Apps instance: +Create a `Dockerfile` in the `city-service` directory, similar to the one in section 02: ```bash -az spring app create -n city-service --runtime-version Java_17 +cd city-service +cat > Dockerfile << 'EOF' +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] +EOF +cd .. ``` -## Connect the Azure Cosmos DB database to the application - -Azure Spring Apps can automatically connect the Cosmos DB database we created to our microservice. - -- Go to `Apps` in your Azure Spring Apps instance. -- Select the `city-service` application -- Go to `Service Connector` -- Click on `+ Create` -- Choose `Cosmos DB` as the Service type -- Give your Connection a name, for example "cosmos_city" -- Select the `NoSQL` API type -- Select the Cosmos DB account and Database we created in the initial 00 setup step -- Verify that the Client type is `SpringBoot` -- Click the `Next: Authentication` button - -![Connect to Cosmos DB database 1 of 4](media/03-service-connector-cosmos.png) - -- Select `Connection string` for the authentication type -- Expand the `Advanced` tag below to verify the property names injected into the connected app -- Click the `Next: Networking` button - -![Connect to Cosmos DB database 2 of 4](media/04-service-connector-cosmos.png) - -- Leave `Configure firewall rules to enable access to target service` selected -- Click the `Next: Review + Create` button +## Get Cosmos DB connection details -![Connect to Cosmos DB database 3 of 4](media/05-service-connector-cosmos.png) +Get the Cosmos DB connection information that we'll use as environment variables. These commands assume you're using the Cosmos DB account created in section 00: -- Once validation passes, click the `Create` button to create the Service Connector - -![Connect to Cosmos DB database 4 of 4](media/06-service-connector-cosmos.png) +```bash +# Get the Cosmos DB account name (adjust if you have multiple accounts) +export COSMOS_DB_NAME=$(az cosmosdb list --resource-group $AZ_RESOURCE_GROUP --query '[0].name' -o tsv) +export COSMOS_DB_URI=$(az cosmosdb show --name $COSMOS_DB_NAME --resource-group $AZ_RESOURCE_GROUP --query documentEndpoint -o tsv) +export COSMOS_DB_KEY=$(az cosmosdb keys list --name $COSMOS_DB_NAME --resource-group $AZ_RESOURCE_GROUP --query primaryMasterKey -o tsv) +``` ## Deploy the application -You can now build your "city-service" project and send it to Azure Spring Apps: +You can now build your "city-service" project and deploy it to Azure Container Apps: ```bash cd city-service ./mvnw clean package -DskipTests -az spring app deploy -n city-service --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +az containerapp create \ + --name city-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --source . \ + --target-port 8080 \ + --ingress internal \ + --env-vars \ + AZURE_COSMOS_URI=$COSMOS_DB_URI \ + AZURE_COSMOS_KEY=$COSMOS_DB_KEY \ + AZURE_COSMOS_DATABASE=azure-container-apps-cosmosdb + cd .. ``` ## Test the project in the cloud -- Go to `Apps` in your Azure Spring Apps instance. - - Verify that `city-service` has a `Registration status` which says `1/1`. This shows that it is correctly registered in Spring Cloud Service Registry. - - Select `city-service` to have more information on the microservice. -- Copy/paste the "Test Endpoint" that is provided. +Since the city-service has internal ingress, you can test it using the Azure Container Apps exec command: + +```bash +az containerapp exec \ + --name city-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --command "wget -qO- http://localhost:8080/cities" +``` -You can now use cURL to test the `/cities` endpoint, and it should give you the list of cities you created. For example, if you only created `Paris, France` and `London, UK` as is shown in this guide, you should get: +You should get the list of cities you created. For example, if you only created `Paris, France` and `London, UK` as is shown in this guide, you should get: ```json [[{"name":"Paris, France"},{"name":"London, UK"}]] diff --git a/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/city-service/Dockerfile b/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/city-service/Dockerfile new file mode 100644 index 00000000..1dcf2b43 --- /dev/null +++ b/06-build-a-reactive-spring-boot-microservice-using-cosmosdb/city-service/Dockerfile @@ -0,0 +1,18 @@ +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] diff --git a/07-build-a-spring-boot-microservice-using-mysql/README.md b/07-build-a-spring-boot-microservice-using-mysql/README.md index 4fac8fe3..c5c4d3db 100644 --- a/07-build-a-spring-boot-microservice-using-mysql/README.md +++ b/07-build-a-spring-boot-microservice-using-mysql/README.md @@ -1,20 +1,11 @@ # 07 - Build a Spring Boot microservice using MySQL -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ In this section, we'll build another data-driven microservice. This time, we will use a relational database, a [MySQL database managed by Azure](https://docs.microsoft.com/en-us/azure/mysql/?WT.mc_id=azurespringcloud-github-judubois). And we'll use Java Persistence API (JPA) to access the data in a way that is more frequently used in the Java ecosystem. --- -## Create the application on Azure Spring Apps - -As in [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md), create a specific `weather-service` application in your Azure Spring Apps instance: - -```bash -az spring app create -n weather-service --runtime-version Java_17 -``` - - ## Configure the MySQL Server instance After following the steps in Section 00, you should have an Azure Database for MySQL instance named `sclabm-` in your resource group. @@ -22,7 +13,7 @@ After following the steps in Section 00, you should have an Azure Database for M Before we can use it however, we will need to perform several tasks: 1. Create a MySQL firewall rule to allow connections from our local environment. -1. Create a MySQL firewall rule to allow connections from Azure Services. This will enable connections from Azure Spring Apps. +1. Create a MySQL firewall rule to allow connections from Azure Services. This will enable connections from Azure Container Apps. 1. Create a MySQL database. > πŸ’‘When prompted for a password, enter the MySQL password you specified when deploying the ARM template in [Section 00](../00-setup-your-environment/README.md). @@ -50,59 +41,21 @@ az mysql flexible-server firewall-rule create \ # Create a MySQL database az mysql flexible-server db create \ - --database-name "azure-spring-apps-training" \ + --database-name "azure-container-apps-training" \ --server-name $MYSQL_SERVERNAME # Display MySQL username (to be used in the next section) echo "Your MySQL username is: ${MYSQL_USERNAME}" -``` - -## Connect the MySQL database to the application - -As we did for Cosmos DB in the previous section, create a Service Connector for the MySQL database to make it available to the `weather-service` microservice. -In the [Azure Portal](https://portal.azure.com/?WT.mc_id=java-0000-judubois): - -- Navigate to your Azure Spring Apps instance -- Click on `Apps` -- Click on `weather-service`. -- Click on `Service Connector` and then on `+ Create`. -- Populate the Service Connector fields as shown: - - For Service type, select `DB for MySQL flexible server` - - Specify a connection name, e.g. "weatherdb" - - Verify the correct subscription is shown - - Choose the MySQL server created in the preceding steps - - Select the MySQL database created earlier - - Select `SpringBoot` as the Client type - - Click the `Next: Authentication` button - -![MySQL Service Connector, 1 of 5](media/01-create-service-connector-mysql.png) - -- Verify `Connection string` is selected -- Select `Continue with...Database credentials` and fill in Username and Password - - The Username was echoed to the terminal as the last command executed earlier - - The password is the one you specified in section 0. The default value is `super$ecr3t`. -- Expand `Advanced` to visually inspect the injected Spring Data properties (optional) - -![MySQL Service Connector, 2 of 5](media/02-create-service-connector-mysql.png) - -- Review the properties automatically injected by the Service Connector to the `weather-service` -- Click `Next: Networking` - -![MySQL Service Connector, 3 of 5](media/03-create-service-connector-mysql.png) +# Set MySQL password (use the password you specified in section 00) +# Default is super$ecr3t - replace with your actual password +export MYSQL_PASSWORD="super\$ecr3t" -- Verify that `Configure firewall rules to enable access to target service` is selected -- Click on `Next: Review + Create` - -![MySQL Service Connector, 4 of 5](media/04-create-service-connector-mysql.png) - -- After receiving the "Validation passed" message, click the `Create` button to create the Service Connector - -![MySQL Service Connector, 5 of 5](media/05-create-service-connector-mysql.png) +``` ## Create a Spring Boot microservice -Now that we've provisioned the Azure Spring Apps instance and configured the Service Connector, let's get the code for `weather-service` ready. The microservice that we create in this guide is [available here](weather-service/). +Now that we've provisioned the MySQL database and configured the firewall rules, let's get the code for `weather-service` ready. The microservice that we create in this guide is [available here](weather-service/). To create our microservice, we will invoke the Spring Initalizr service from the command line: @@ -110,7 +63,7 @@ To create our microservice, we will invoke the Spring Initalizr service from the curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=web,data-jpa,mysql,cloud-eureka,cloud-config-client -d baseDir=weather-service -d bootVersion=3.1.3 -d javaVersion=17 | tar -xzvf - ``` -> We use the `Spring Web`, `Spring Data JPA`, `MySQL Driver`, `Eureka Discovery Client` and the `Config Client` components. +> We use the `Spring Web`, `Spring Data JPA`, `MySQL Driver`, `Eureka Discovery Client` and the `Config Client` components. Note: For Azure Container Apps, we won't be using service discovery, but we keep these dependencies for consistency with the original code. ## Add Spring code to get the data from the database @@ -206,34 +159,73 @@ spring.jpa.hibernate.ddl-auto=create Then, in order to have Spring Boot add sample data at startup, create a `src/main/resources/import.sql` file and add: ```sql -INSERT INTO `azure-spring-apps-training`.`weather` (`city`, `description`, `icon`) VALUES ('Paris, France', 'Very cloudy!', 'weather-fog'); -INSERT INTO `azure-spring-apps-training`.`weather` (`city`, `description`, `icon`) VALUES ('London, UK', 'Quite cloudy', 'weather-pouring'); +INSERT INTO `azure-container-apps-training`.`weather` (`city`, `description`, `icon`) VALUES ('Paris, France', 'Very cloudy!', 'weather-fog'); +INSERT INTO `azure-container-apps-training`.`weather` (`city`, `description`, `icon`) VALUES ('London, UK', 'Quite cloudy', 'weather-pouring'); ``` > The icons we are using are the ones from [https://materialdesignicons.com/](https://materialdesignicons.com/) - you can pick their other weather icons if you wish. +## Create a Dockerfile + +Create a `Dockerfile` in the `weather-service` directory: + +```bash +cd weather-service +cat > Dockerfile << 'EOF' +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] +EOF +cd .. +``` + ## Deploy the application -You can now build your "weather-service" project and send it to Azure Spring Apps: +You can now build your "weather-service" project and deploy it to Azure Container Apps: ```bash cd weather-service ./mvnw clean package -DskipTests -az spring app deploy -n weather-service --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +az containerapp create \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --source . \ + --target-port 8080 \ + --ingress internal \ + --env-vars \ + SPRING_DATASOURCE_URL="jdbc:mysql://${MYSQL_HOST}:3306/azure-container-apps-training?useSSL=true&requireSSL=false&serverTimezone=UTC" \ + SPRING_DATASOURCE_USERNAME=$MYSQL_USERNAME \ + SPRING_DATASOURCE_PASSWORD=$MYSQL_PASSWORD + cd .. ``` ## Test the project in the cloud -- Go to "Apps" in your Azure Spring Apps instance. - - Verify that `weather-service` has a `Registration status` which says `1/1`. This shows that it is correctly registered in the Spring Cloud Service Registry. - - Select `weather-service` to have more information on the microservice. -- Copy/paste the "Test endpoint" that is provided. - -You can now use cURL to test the `/weather/city` endpoint. For example, to test for `Paris, France` city, append to the end of the test endpoint: `/weather/city?name=Paris%2C%20France`. +Since the weather-service has internal ingress, you can test it using the Azure Container Apps exec command: ```bash -curl "https://primary:31SifNyr649htxU3IEpYaLbxRz6Gy3xAk0aLDFM49hcwx9zcCEXvPEGkHSpzJzKv@judubois-4876.test.azuremicroservices.io/weather-service/default/weather/city?name=Paris%2C%20France" +az containerapp exec \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --command "wget -qO- 'http://localhost:8080/weather/city?name=Paris%2C%20France'" ``` Here is the response you should receive: diff --git a/07-build-a-spring-boot-microservice-using-mysql/weather-service/Dockerfile b/07-build-a-spring-boot-microservice-using-mysql/weather-service/Dockerfile new file mode 100644 index 00000000..1dcf2b43 --- /dev/null +++ b/07-build-a-spring-boot-microservice-using-mysql/weather-service/Dockerfile @@ -0,0 +1,18 @@ +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] diff --git a/08-build-a-spring-cloud-gateway/README.md b/08-build-a-spring-cloud-gateway/README.md index 47e98e93..32678e21 100644 --- a/08-build-a-spring-cloud-gateway/README.md +++ b/08-build-a-spring-cloud-gateway/README.md @@ -1,6 +1,6 @@ # 08 - Build a Spring Cloud Gateway -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ A Spring Cloud gateway allows you to selectively expose your microservices and to route traffic to them and among them. In this section, we will create a Spring Cloud Gateway that will expose the microservices we created in the preceding two sections. @@ -16,7 +16,7 @@ To create our gateway, we will invoke the Spring Initalizr service from the comm curl https://start.spring.io/starter.tgz -d type=maven-project -d dependencies=cloud-gateway,cloud-eureka,cloud-config-client -d baseDir=gateway -d bootVersion=3.1.3 -d javaVersion=17 | tar -xzvf - ``` -> We use the `Cloud Gateway`, `Eureka Discovery Client` and the `Config Client` components. +> We use the `Cloud Gateway`, `Eureka Discovery Client` and the `Config Client` components. Note: For Azure Container Apps, we configure routes directly instead of using service discovery. ## Configure the application @@ -38,46 +38,109 @@ spring: ``` -- The `spring.cloud.gateway.discovery.locator.enabled=true` part is to configure Spring Cloud Gateway to use the Spring Cloud Service Registry to discover the available microservices. -- The `spring.cloud.gateway.globalcors.corsConfiguration` part is to allow Cross-Origin Resource Sharing (CORS) requests to our gateway. This will be helpful in the next guide, when we will add a front-end that is not hosted on Azure Spring Apps. +## Configure the gateway for Azure Container Apps -## Create the application on Azure Spring Apps +For Azure Container Apps, we need to configure the gateway to route to the internal URLs of our microservices. Update `src/main/resources/application.yml`: -As in [02 - Build a simple Spring Boot microservice](../02-build-a-simple-spring-boot-microservice/README.md), create a specific `gateway` application in your Azure Spring Apps instance. As this application is a gateway, we add the `--assign-endpoint true` flag so it is exposed publicly. +```yaml +spring: + cloud: + gateway: + routes: + - id: city-service + uri: http://city-service + predicates: + - Path=/city-service/** + filters: + - StripPrefix=1 + - id: weather-service + uri: http://weather-service + predicates: + - Path=/weather-service/** + filters: + - StripPrefix=1 + globalcors: + corsConfigurations: + '[/**]': + allowedOrigins: "*" + allowedMethods: + - GET + +``` + +Note: In Azure Container Apps, services within the same environment can communicate directly using the service name as the hostname (e.g., `http://city-service`). + +## Create a Dockerfile + +Create a `Dockerfile` in the `gateway` directory: ```bash -az spring app create -n gateway --runtime-version Java_17 --assign-endpoint true +cd gateway +cat > Dockerfile << 'EOF' +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] +EOF +cd .. ``` ## Deploy the application -You can now build your "gateway" project and send it to Azure Spring Apps: +You can now build your "gateway" project and deploy it to Azure Container Apps with external ingress: ```bash cd gateway ./mvnw clean package -DskipTests -az spring app deploy -n gateway --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +az containerapp create \ + --name gateway \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --source . \ + --target-port 8080 \ + --ingress external + cd .. ``` ## Test the project in the cloud -- Go to "Apps" in your Azure Spring Apps instance. - - Verify that `gateway` has a `Registration status` which says `1/1`. This shows that it is correctly registered in the Spring Cloud Service Registry. - - Select `gateway` to have more information on the microservice. -- Copy/paste the public URL that is provided (there is a "Test endpoint" like for microservices, but the gateway is directly exposed on the Internet, so let's use the public URL). Keep this URL handy for subsequent sections. +Get the gateway URL: + +```bash +GATEWAY_URL=$(az containerapp show \ + --name gateway \ + --resource-group $AZ_RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv) -As the gateway is connected to the Spring Cloud Service Registry, it should have automatically opened routes to the available microservices, with URL paths in the form of `/MICROSERVICE-ID/**`. +echo "Gateway URL: https://$GATEWAY_URL" +``` - > πŸ›‘ **The MICROSERVICE-ID must be uppercase, all CAPS**. Replace XXXXXXXX with the name of your Azure Spring Apps instance. +You can now test the gateway routes to access the microservices: - Test the `city-service` microservice endpoint: + ```bash + curl https://$GATEWAY_URL/city-service/cities ``` - curl https://XXXXXXXX-gateway.azuremicroservices.io/CITY-SERVICE/cities - ``` -- Test the `weather-service` microservice endpoint by doing: - ``` - curl 'https://XXXXXXXX-gateway.azuremicroservices.io/WEATHER-SERVICE/weather/city?name=Paris%2C%20France' +- Test the `weather-service` microservice endpoint: + ```bash + curl "https://$GATEWAY_URL/weather-service/weather/city?name=Paris%2C%20France" ``` If you need to check your code, the final project is available in the ["gateway" folder](gateway/). diff --git a/08-build-a-spring-cloud-gateway/gateway/Dockerfile b/08-build-a-spring-cloud-gateway/gateway/Dockerfile new file mode 100644 index 00000000..1dcf2b43 --- /dev/null +++ b/08-build-a-spring-cloud-gateway/gateway/Dockerfile @@ -0,0 +1,18 @@ +FROM eclipse-temurin:17-jdk-alpine as build +WORKDIR /workspace/app + +COPY mvnw . +COPY .mvn .mvn +COPY pom.xml . +COPY src src + +RUN ./mvnw package -DskipTests +RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) + +FROM eclipse-temurin:17-jre-alpine +VOLUME /tmp +ARG DEPENDENCY=/workspace/app/target/dependency +COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app +ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"] diff --git a/08-build-a-spring-cloud-gateway/gateway/src/main/resources/application.yml b/08-build-a-spring-cloud-gateway/gateway/src/main/resources/application.yml index 84650aa5..1d4b7b50 100644 --- a/08-build-a-spring-cloud-gateway/gateway/src/main/resources/application.yml +++ b/08-build-a-spring-cloud-gateway/gateway/src/main/resources/application.yml @@ -1,9 +1,19 @@ spring: cloud: gateway: - discovery: - locator: - enabled: true + routes: + - id: city-service + uri: http://city-service + predicates: + - Path=/city-service/** + filters: + - StripPrefix=1 + - id: weather-service + uri: http://weather-service + predicates: + - Path=/weather-service/** + filters: + - StripPrefix=1 globalcors: corsConfigurations: '[/**]': diff --git a/09-putting-it-all-together-a-complete-microservice-stack/README.md b/09-putting-it-all-together-a-complete-microservice-stack/README.md index 8541a572..65ccfe2c 100644 --- a/09-putting-it-all-together-a-complete-microservice-stack/README.md +++ b/09-putting-it-all-together-a-complete-microservice-stack/README.md @@ -1,6 +1,6 @@ # 09 - Putting it all together, a complete microservice stack -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ Now that we have made two microservices publicly available, we will incorporate a user interface to see them in action. Then, we will use Azure Monitor to monitor the flow of traffic to and among our services and to track metrics. @@ -17,7 +17,7 @@ We now have a complete microservices stack: In order to finish this architecture, we need to add a front-end to it: - We've already built a VueJS application, that is available in the ["weather-app" folder](weather-app/). -- This front-end could be hosted in Azure Spring Apps, using the same domain name (this won't be the case in this guide, and that's why we enabled CORS in our gateway earlier). +- This front-end could be hosted in Azure Container Apps, using the same domain name (this won't be the case in this guide, and that's why we enabled CORS in our gateway earlier). - If you are familiar with NodeJS and Vue CLI, you can run this application locally by typing `npm install && vue ui`. In order to simplify this part, which is not relevant to understanding Spring Cloud, we have already built a running front-end: @@ -32,7 +32,7 @@ Go to [https://spring-training.azureedge.net/](https://spring-training.azureedge ## Review the distributed tracing to better understand the architecture -Distributed tracing is enabled by default on Azure Spring Apps, so your microservices and gateway are already being monitored. +Azure Container Apps integrates with Azure Monitor and Application Insights for distributed tracing. Your microservices and gateway are being monitored through this integration. Now, you can use the VueJS application on [https://spring-training.azureedge.net/](https://spring-training.azureedge.net/) to generate some traffic on the microservices stack. @@ -58,11 +58,21 @@ For even more detailed data, navigate to the `Dependencies` tab in the `Performa Now that distributed tracing is enabled, we can scale applications depending on our needs. -- Go to [the Azure portal](https://portal.azure.com/?WT.mc_id=java-0000-judubois). -- Go to the overview page of your Azure Spring Apps server and select "Apps" in the menu. - - Select one service and click on "Scale Out" in the menu. Select the service that you want to scale out. - - Modify the number of instances to manually scale the service. You can also set custom autoscaling based on metrics. - ![Application scaling](media/04-scale-out.png) +You can scale your Container Apps using the Azure CLI. For example, to scale the `weather-service`: + +```bash +az containerapp update \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --min-replicas 1 \ + --max-replicas 5 +``` + +You can also configure scaling in the Azure Portal: +- Navigate to your Container App in the Azure Portal +- Select "Scale" from the menu +- Configure the minimum and maximum number of replicas +- Set up scale rules based on HTTP traffic, CPU, memory, or custom metrics --- diff --git a/09-putting-it-all-together-a-complete-microservice-stack/weather-app/src/App.vue b/09-putting-it-all-together-a-complete-microservice-stack/weather-app/src/App.vue index f5e93d8f..e5aee9ea 100644 --- a/09-putting-it-all-together-a-complete-microservice-stack/weather-app/src/App.vue +++ b/09-putting-it-all-together-a-complete-microservice-stack/weather-app/src/App.vue @@ -27,7 +27,7 @@ color="indigo" app > - Azure Spring Apps training + Azure Container Apps training diff --git a/10-blue-green-deployment/README.md b/10-blue-green-deployment/README.md index d93a6b25..ace4219d 100644 --- a/10-blue-green-deployment/README.md +++ b/10-blue-green-deployment/README.md @@ -1,10 +1,8 @@ # 10 - Blue/Green deployment -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -The blue-green deployment pattern allows you to test latest application changes on production infrastructure, but without exposing the changes to consumers until your testing is complete. In this section, we'll perform a blue-green deployment with Azure CLI. Although we will go through the deployment steps manually, the Azure CLI commands we'll use can be automated in a CI/CD pipeline. - ->πŸ›‘ This API is currently in transition. It's recommended that for the time being, you skip this guide and proceed directly to the next one: [11 - Configure CI/CD](../11-configure-ci-cd/README.md) +The blue-green deployment pattern allows you to test latest application changes on production infrastructure, but without exposing the changes to consumers until your testing is complete. In this section, we'll perform a blue-green deployment using Azure Container Apps revisions. Although we will go through the deployment steps manually, the Azure CLI commands we'll use can be automated in a CI/CD pipeline. --- @@ -37,7 +35,7 @@ public class WeatherController { @GetMapping("/city") public Optional getWeatherForCity(@RequestParam("name") String cityName) { return weatherRepository.findById(cityName).map(weather -> { - weather.setDescription("It's always sunny on Azure Spring Apps"); + weather.setDescription("It's always sunny on Azure Container Apps"); weather.setIcon("weather-sunny"); return weather; }); @@ -45,61 +43,75 @@ public class WeatherController { } ``` -## Deploy the new application to a new "green" deployment +## Deploy the new application to a new "green" revision -Build a new version of the application and deploy it to a new `deployment` called `green`: +Azure Container Apps uses revisions for managing different versions of your application. Build a new version of the application and deploy it as a new revision with the suffix `green`: ```bash cd weather-service ./mvnw clean package -DskipTests -az spring app deployment create --name green --app weather-service --runtime-version Java_17 --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +# Create a new revision with the suffix 'green' but don't send traffic to it yet +az containerapp update \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --image /weather-service:green \ + --revision-suffix green \ + --set-env-vars + cd .. ``` -Once the application is deployed, if you go to [https://spring-training.azureedge.net/](https://spring-training.azureedge.net/) you will still have the same data, as the new version of the microservice is now in a staging area and not in production yet. - -Navigate to the Azure Spring Apps instance in [the Azure portal](https://portal.azure.com/?WT.mc_id=azurespringcloud-github-judubois): +Once the application is deployed, if you go to [https://spring-training.azureedge.net/](https://spring-training.azureedge.net/) you will still have the same data, as the new revision is deployed but not receiving traffic yet. -- Look for your Azure Spring Apps instance in your resource group -- Go to "Apps" - - Select the `weather-service` microservice - - Click on "Deployments" in the menu. You should now see the "green" deployment, under the "default" deployment: +Navigate to the Azure Container Apps instance in [the Azure portal](https://portal.azure.com): -![Deployment Pane](media/02-deployment-pane.png) +- Look for your Container Apps environment in your resource group +- Select the `weather-service` container app +- Click on "Revision management" in the menu. You should now see the "green" revision alongside your previous revision -You can test the `green` deployment by invoking the same URL as in section 7, but replacing the deployment name `default` with `green`: +You can view all revisions using the CLI: ```bash -curl "https://***.test.azuremicroservices.io/weather-service/green/weather/city?name=Paris%2C%20France" +az containerapp revision list \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + -o table ``` And you should see the result of the recent modification: ```json -{"city":"Paris, France","description":"It's always sunny on Azure Spring Apps","icon":"weather-sunny"} +{"city":"Paris, France","description":"It's always sunny on Azure Container Apps","icon":"weather-sunny"} ``` -Note: we're not testing the green deployment through the `gateway` application. The purpose of a green deployment is to test changes to a microservice before routing production traffic to it. Therefore, if you access `weather-service` through the public Gateway URL, as you did in section 8, you will be routed to the original version of the service. +Note: we're not testing the green revision through the `gateway` application yet. The purpose of a green deployment is to test changes to a microservice before routing production traffic to it. -To put this `green` deployment into production, you can use the command line: +To shift traffic to the `green` revision, you can use the command line: ```bash -az spring app set-deployment -n weather-service -d green +az containerapp ingress traffic set \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --revision-weight =100 ``` -Another solution is to use [the Azure portal](https://portal.azure.com/?WT.mc_id=azurespringcloud-github-judubois): +Another solution is to use [the Azure portal](https://portal.azure.com): -- Find your Azure Spring Apps instance -- Click on the "Apps" menu -- Select the `weather-service` application and click on "Deployments" +- Find your Container App +- Click on the "Revision management" menu +- Select traffic splitting to route traffic between revisions -> If you want to reuse a deployment name, you need first to delete the previous deployment under that name: -> -> ```bash -> az spring app deployment delete --name green --app weather-service -> ``` +You can also perform a gradual rollout by splitting traffic between revisions: + +```bash +az containerapp ingress traffic set \ + --name weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --revision-weight =50 =50 +``` -Once you have swapped deployments and see that `green` is active, you need to wait a few seconds for the Spring Cloud Service Registry to synchronize and use this new version from the `gateway` application. You will then be able to see the new modified data: +Once you have shifted traffic to the green revision, you will be able to see the new modified data: ![Green deployment](media/01-green-deployment.png) diff --git a/10-blue-green-deployment/weather-service/src/main/java/com/example/demo/WeatherController.java b/10-blue-green-deployment/weather-service/src/main/java/com/example/demo/WeatherController.java index 294f1106..628995cf 100644 --- a/10-blue-green-deployment/weather-service/src/main/java/com/example/demo/WeatherController.java +++ b/10-blue-green-deployment/weather-service/src/main/java/com/example/demo/WeatherController.java @@ -26,7 +26,7 @@ public WeatherController(WeatherRepository weatherRepository) { @GetMapping("/city") public Optional getWeatherForCity(@RequestParam("name") String cityName) { return weatherRepository.findById(cityName).map(weather -> { - weather.setDescription("It's always sunny on Azure Spring Apps"); + weather.setDescription("It's always sunny on Azure Container Apps"); weather.setIcon("weather-sunny"); return weather; }); diff --git a/11-configure-ci-cd/README.md b/11-configure-ci-cd/README.md index 92e8a6b5..ddce1c3d 100644 --- a/11-configure-ci-cd/README.md +++ b/11-configure-ci-cd/README.md @@ -1,8 +1,8 @@ # 11 - Configure CI/CD -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ -In this section, we will use GitHub Actions to implement continuous deployment to Azure Spring Apps. For simplicity, we will not implement blue-green deployments in this section, but don't hesitate to come back and add blue-green deployments after completing the remainder of the tutorial. +In this section, we will use GitHub Actions to implement continuous deployment to Azure Container Apps. For simplicity, we will not implement blue-green deployments in this section, but don't hesitate to come back and add blue-green deployments after completing the remainder of the tutorial. --- @@ -26,7 +26,7 @@ git push origin main cd .. ``` -You now need to allow access from your GitHub workflow to your Azure Spring Apps instance. Open up a terminal and type the following command, replacing `$AZ_RESOURCE_GROUP` with the name of your resource group. +You now need to allow access from your GitHub workflow to your Azure Container Apps environment. Open up a terminal and type the following command, replacing `$AZ_RESOURCE_GROUP` with the name of your resource group. πŸ›‘ Make sure you assign the name of your resource group to the variable `AZ_RESOURCE_GROUP` or substitute the value for it in the commands below. @@ -38,7 +38,7 @@ export MSYS_NO_PATHCONV=1 export RESOURCE_ID=$(az group show --name $AZ_RESOURCE_GROUP --query id -o tsv) # Create a service principal with a Contributor role to the resource group. -export SPNAME=sp-$AZ_SPRING_APPS_NAME +export SPNAME=sp-containerapp-$AZ_RESOURCE_GROUP az ad sp create-for-rbac --name $SPNAME --role contributor --scopes $RESOURCE_ID --sdk-auth ``` @@ -48,17 +48,24 @@ Then, in your GitHub project, select `Settings > Secrets` and add a new secret c ## Create a GitHub Action -Inside the `weather-service` directory, create a new directory called `.github/workflows` and add a file called `azure-spring-apps.yml` in it. This file is a GitHub workflow and will use the secret we just configured above to deploy the application to your Azure Spring Apps instance. +Inside the `weather-service` directory, create a new directory called `.github/workflows` and add a file called `azure-container-apps.yml` in it. This file is a GitHub workflow and will use the secret we just configured above to deploy the application to your Azure Container Apps environment. In that file, copy/paste the following content, performing the indicated substitutions: ->πŸ›‘ You must substitute the name of your Azure Spring Apps instance for `` in the YAML below. +>πŸ›‘ You must substitute the name of your Container Apps environment for ``, resource group for ``, and container registry for `` in the YAML below. ```yaml -name: Build and deploy to Azure Spring Apps +name: Build and deploy to Azure Container Apps on: [push] +env: + REGISTRY_NAME: + IMAGE_NAME: weather-service + RESOURCE_GROUP: + CONTAINERAPP_ENV: + CONTAINERAPP_NAME: weather-service + jobs: build-and-deploy: runs-on: ubuntu-latest @@ -73,23 +80,24 @@ jobs: cache: 'maven' - name: Build with Maven run: mvn package -DskipTests - - name: Login to Azure Spring Apps + - name: Login to Azure uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - name: Get Subscription ID + - name: Build and push container image run: | - echo "SUBSCRIPTION_ID=$(az account show --query id --output tsv --only-show-errors)" >> $GITHUB_ENV - shell: bash - - name: Deploy to Azure Spring Apps - uses: azure/spring-cloud-deploy@v1 - with: - action: deploy - azure-subscription: ${{ env.SUBSCRIPTION_ID }} - service-name: - app-name: weather-service - use-staging-deployment: false - package: target/demo-0.0.1-SNAPSHOT.jar + az acr build \ + --registry ${{ env.REGISTRY_NAME }} \ + --image ${{ env.IMAGE_NAME }}:${{ github.sha }} \ + --image ${{ env.IMAGE_NAME }}:latest \ + --file Dockerfile \ + . + - name: Deploy to Container Apps + run: | + az containerapp update \ + --name ${{ env.CONTAINERAPP_NAME }} \ + --resource-group ${{ env.RESOURCE_GROUP }} \ + --image ${{ env.REGISTRY_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }} ``` @@ -97,18 +105,18 @@ This workflow does the following: - It sets up the JDK - It compiles and packages the application using Maven -- It authenticates to Azure Spring Apps using the credentials we just configured -- It fetches your current subscription ID -- It deploys the application to your Azure Spring Apps instance, using the Azure Spring Apps GitHub Action. +- It authenticates to Azure using the credentials we just configured +- It builds a container image and pushes it to Azure Container Registry +- It deploys the container image to your Azure Container Apps environment This workflow is configured to be triggered whenever code is pushed to the repository. There are many other [events that trigger GitHub actions](https://help.github.com/en/articles/events-that-trigger-workflows). You could, for example, deploy each time a new tag is created on the project. ## Test the GitHub Action -You can now commit and push the `azure-spring-apps.yml` file we just created. +You can now commit and push the `azure-container-apps.yml` file we just created. -Going to the `Actions` tab of your GitHub project, you should see that your project is automatically built and deployed to your Azure Spring Apps instance: +Going to the `Actions` tab of your GitHub project, you should see that your project is automatically built and deployed to your Azure Container Apps environment: ![GitHub workflow](media/01-github-workflow.png) diff --git a/12-making-microservices-talk-to-each-other/README.md b/12-making-microservices-talk-to-each-other/README.md index 899415a6..45143184 100644 --- a/12-making-microservices-talk-to-each-other/README.md +++ b/12-making-microservices-talk-to-each-other/README.md @@ -1,6 +1,6 @@ # 12 - Making Microservices Talk to Each Other -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ Creating a microservice that talks to other microservices. @@ -10,9 +10,9 @@ In [Section 6](../06-build-a-reactive-spring-boot-microservice-using-cosmos/READ There is a glaring inefficiency in this design: the browser first calls `city-service`, waits for it to respond, and upon getting that response, calls `weather-service` for each of the cities returned. All these remote calls are made over public internet, whose speed is never guaranteed. -To resolve this inefficiency, we will create a single microservice that implements the [Transaction Script](https://www.martinfowler.com/eaaCatalog/transactionScript.html) pattern: it will orchestrate the calls to individual microservices and return the weather for all cities. To do this, we will use [Spring Cloud OpenFeign](https://spring.io/projects/spring-cloud-openfeign). OpenFeign will automatically obtain the URLs of invoked microservices from Spring Cloud Registry, allowing us to build our `all-cities-weather-services` microservice without needing to resolve the locations of the constituent microservices. +To resolve this inefficiency, we will create a single microservice that implements the [Transaction Script](https://www.martinfowler.com/eaaCatalog/transactionScript.html) pattern: it will orchestrate the calls to individual microservices and return the weather for all cities. To do this, we will use [Spring Cloud OpenFeign](https://spring.io/projects/spring-cloud-openfeign). -Note how the code we create in this section is endpoint-agnostic. All we specify is the name of the services we want to invoke in the `@FeignClient` annotation. OpenFeign and the Azure Spring Apps discovery service then work together behind the scenes to connect our new microservice to the services we've created previously. +In Azure Container Apps, services within the same environment can communicate with each other using their internal fully qualified domain names (FQDNs). When using OpenFeign with the `@FeignClient` annotation, you can specify the service name, and configure the actual URL through environment variables or application properties. For internal communication between Container Apps in the same environment, services can use the pattern `http://` or the full internal FQDN `http://.internal..azurecontainerapps.io`. ## Create a Spring Boot Microservice @@ -150,22 +150,43 @@ spring.cloud.openfeign.client.config.default.connectTimeout=160000000 spring.cloud.openfeign.client.config.default.readTimeout=160000000 ``` -## Create the application on Azure Spring Apps +## Create the application on Azure Container Apps -As before, create a specific `all-cities-weather-service` application in your Azure Spring Apps instance: +As before, create a specific `all-cities-weather-service` application in your Azure Container Apps environment: ```bash -az spring app create -n all-cities-weather-service --runtime-version Java_17 +az containerapp create \ + --name all-cities-weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --image /all-cities-weather-service:latest \ + --target-port 8080 \ + --ingress external \ + --min-replicas 1 \ + --max-replicas 3 ``` ## Deploy the application -You can now build your "all-cities-weather-service" project and send it to Azure Spring Apps: +You can now build your "all-cities-weather-service" project and deploy it to Azure Container Apps: ```bash cd all-cities-weather-service ./mvnw clean package -DskipTests -az spring app deploy -n all-cities-weather-service --artifact-path target/demo-0.0.1-SNAPSHOT.jar + +# Build and push the container image +az acr build \ + --registry \ + --image all-cities-weather-service:latest \ + --file Dockerfile \ + . + +# Update the container app +az containerapp update \ + --name all-cities-weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --image .azurecr.io/all-cities-weather-service:latest + cd .. ``` @@ -180,8 +201,8 @@ https:///ALL-CITIES-WEATHER-SERVICE You should get the JSON output with the weather for all the cities: ```json -[{"city":"Paris, France","description":"It's always sunny on Azure Spring Apps","icon":"weather-sunny"}, -{"city":"London, UK","description":"It's always sunny on Azure Spring Apps","icon":"weather-sunny"}] +[{"city":"Paris, France","description":"It's always sunny on Azure Container Apps","icon":"weather-sunny"}, +{"city":"London, UK","description":"It's always sunny on Azure Container Apps","icon":"weather-sunny"}] ``` --- diff --git a/13-build-a-spring-ai-microservice-with-azure-openai/README.md b/13-build-a-spring-ai-microservice-with-azure-openai/README.md index 1d91b952..19bb3110 100644 --- a/13-build-a-spring-ai-microservice-with-azure-openai/README.md +++ b/13-build-a-spring-ai-microservice-with-azure-openai/README.md @@ -66,35 +66,52 @@ Next, start the service by running `./mvnw spring-boot:run`. Finally, open `http://localhost:8080` in a browser to access the application. -## Deploy to Azure Spring Apps +## Deploy to Azure Container Apps -Use the following command to specify the app name on Azure Spring Apps and to allocate the required resources: +Use the following command to create the container app in your Azure Container Apps environment: ```bash -az spring app create \ +az containerapp create \ --name ai-weather-service \ + --resource-group $AZ_RESOURCE_GROUP \ + --environment $AZ_CONTAINERAPP_ENV \ + --image /ai-weather-service:latest \ + --target-port 8080 \ + --ingress external \ --cpu 2 \ --memory 4Gi \ --min-replicas 2 \ --max-replicas 2 \ - --assign-endpoint true + --env-vars \ + SPRING_AI_AZURE_OPENAI_API_KEY=${SPRING_AI_AZURE_OPENAI_API_KEY} \ + SPRING_AI_AZURE_OPENAI_ENDPOINT=${SPRING_AI_AZURE_OPENAI_ENDPOINT} ``` Build the jar package using the command: `./mvnw clean package`. -Use the following command to deploy the *.jar* file for the app: +Build and deploy the container image: ```bash -az spring app deploy \ +# Build and push the container image +az acr build \ + --registry \ + --image ai-weather-service:latest \ + --file Dockerfile \ + . + +# Update the container app +az containerapp update \ --name ai-weather-service \ - --artifact-path target/demo-0.0.1-SNAPSHOT.jar \ - --env SPRING_AI_AZURE_OPENAI_API_KEY=${SPRING_AI_AZURE_OPENAI_API_KEY} SPRING_AI_AZURE_OPENAI_ENDPOINT=${SPRING_AI_AZURE_OPENAI_ENDPOINT} \ - --runtime-version Java_17 + --resource-group $AZ_RESOURCE_GROUP \ + --image .azurecr.io/ai-weather-service:latest \ + --set-env-vars \ + SPRING_AI_AZURE_OPENAI_API_KEY=${SPRING_AI_AZURE_OPENAI_API_KEY} \ + SPRING_AI_AZURE_OPENAI_ENDPOINT=${SPRING_AI_AZURE_OPENAI_ENDPOINT} ``` ## Test the project in the cloud -- Go to "Apps" in your Azure Spring Apps instance. - - Verify that `ai-weather-service` has a `Registration status` which says `1/1`. This shows that it is correctly registered in Spring Cloud Service Registry. - - Select `ai-weather-service` to see more information about the microservice. -- Click the "URL" that is provided to open it in another browser tab, then type `Basel` into the `Question` prompt box. Click the `Ask AI` button to see the results! +- Go to your Azure Container Apps environment in the Azure Portal. + - Select the `ai-weather-service` container app to see more information about the microservice. + - Navigate to the "Ingress" section to find the application URL. +- Click the URL to open it in another browser tab, then type `Basel` into the `Question` prompt box. Click the `Ask AI` button to see the results! diff --git a/99-conclusion/README.md b/99-conclusion/README.md index f32a021d..d244fa06 100644 --- a/99-conclusion/README.md +++ b/99-conclusion/README.md @@ -1,6 +1,6 @@ # Conclusion -__This guide is part of the [Azure Spring Apps training](../README.md)__ +__This guide is part of the [Azure Container Apps training](../README.md)__ --- @@ -18,13 +18,13 @@ az group delete -g "$AZ_RESOURCE_GROUP" --yes --no-wait ## Additional Resources -As an addendum to this workshop, consider taking the [tutorial on using alerts and action groups with Azure Spring Apps](https://docs.microsoft.com/azure/spring-cloud/spring-cloud-tutorial-alerts-action-groups/?WT.mc_id=azurespringcloud-github-judubois) to detect and respond to abnormal conditions. +As an addendum to this workshop, consider learning more about [Azure Container Apps monitoring and observability](https://learn.microsoft.com/azure/container-apps/observability) to detect and respond to abnormal conditions. -Also, check out our tutorial to [Deploy Azure Spring Apps in a virtual network](https://docs.microsoft.com/azure/spring-cloud/spring-cloud-tutorial-deploy-in-azure-virtual-network). +Also, check out the tutorial to [deploy Azure Container Apps in a virtual network](https://learn.microsoft.com/azure/container-apps/vnet-custom). -Have a look through the [Azure Spring Apps documentation](https://docs.microsoft.com/azure/spring-cloud/?WT.mc_id=azurespringcloud-github-judubois) for more quickstarts, tutorials, and reference materials. +Have a look through the [Azure Container Apps documentation](https://learn.microsoft.com/azure/container-apps/) for more quickstarts, tutorials, and reference materials. -Find more about the monitoring power for [Spring Cloud with Application Insights](https://docs.microsoft.com/en-us/azure/spring-cloud/spring-cloud-howto-application-insights?WT.mc_id=java-13165-sakriema). +Find more about [monitoring Container Apps with Application Insights](https://learn.microsoft.com/azure/container-apps/application-insights) for distributed tracing and performance monitoring. --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2a939248..5b20572b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to the Azure Spring Apps training +# Contributing to the Azure Container Apps training As this training is [Open Source](LICENSE.txt), contributions are highly welcome! diff --git a/README.md b/README.md index 670056a0..1a22c37f 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ languages: - java --- -# Azure Spring Apps training +# Azure Container Apps training (Spring Boot microservices) -You will find here a full workshop on Azure Spring Apps, including guides and demos. -You can run this workshop with the monthly free grant from Azure Spring Apps. [Learn More](https://aka.ms/costs-less) +You will find here a full workshop on deploying Spring Boot microservices to Azure Container Apps, including guides and demos. +Azure Container Apps provides a serverless container platform for deploying microservices applications. This lab is open-source, and under the [MIT license](LICENSE.txt). All Contributions are more then welcome! [Learn more at contribution guidelines.](CONTRIBUTING.md) @@ -22,13 +22,13 @@ This is not the official documentation but an opinionated training. It is a hands-on training, and it will use the command line extensively. The idea is to get coding very quickly and play with the platform, from a simple demo to far more complex examples. -After completing all the guides, you should have a fairly good understanding of everything that Azure Spring Apps offers. +After completing all the guides, you should have a fairly good understanding of deploying Spring Boot microservices to Azure Container Apps. ## Symbols >πŸ›‘ - __Manual Modification Required__. When this symbol appears in front of one or more commands, you will need to modify the commands as indicated prior to running them. ->🚧 - __Preview-specific__. This symbol indicates steps that are only necessary while Azure Spring Apps is in preview. +>🚧 - __Preview-specific__. This symbol indicates steps that are only necessary while certain features are in preview. >πŸ’‘ - __Frustration Avoidance Tip__. These will help you avoid potential pitfalls. @@ -36,9 +36,9 @@ After completing all the guides, you should have a fairly good understanding of Prerequisites and environment setup. -## [01 - Create an Azure Spring Apps cluster](01-create-an-azure-spring-cloud-instance/README.md) +## [01 - Create an Azure Container Apps environment](01-create-an-azure-spring-cloud-instance/README.md) -Basics on creating a cluster and configuring the CLI to work efficiently. +Basics on creating a Container Apps environment and configuring the CLI to work efficiently. ## [02 - Build a simple Spring Boot microservice](02-build-a-simple-spring-boot-microservice/README.md) @@ -50,11 +50,11 @@ Access Spring Boot applications logs to understand common issues. ## [04 - Configure a Spring Cloud Config server](04-configure-a-spring-cloud-config-server/README.md) -Configure a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config), that will be entirely managed and supported by Azure Spring Apps, to be used by Spring Boot microservices. +Configure a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config), deployed as a container app, to be used by Spring Boot microservices. ## [05 - Build a Spring Boot microservice using Spring Cloud features](05-build-a-spring-boot-microservice-using-spring-cloud-features/README.md) -Build a Spring Boot microservice that is cloud-enabled: it uses a Spring Cloud Service Registry and a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config) which are both managed and supported by Azure Spring Apps. +Build a Spring Boot microservice that is cloud-enabled: it uses a Spring Cloud Service Registry and a [Spring Cloud Config Server](https://cloud.spring.io/spring-cloud-config) deployed on Azure Container Apps. ## [06 - Build a reactive Spring Boot microservice using Cosmos DB](06-build-a-reactive-spring-boot-microservice-using-cosmosdb/README.md) @@ -70,11 +70,11 @@ Build a [Spring Cloud Gateway](https://spring.io/projects/spring-cloud-gateway) ## [09 - Putting it all together, a complete microservice stack](09-putting-it-all-together-a-complete-microservice-stack/README.md) -Use a front-end to access graphically our complete microservice stack. Monitor our services with Azure Spring Apps's distributed tracing mechanism and scale our services depending on our needs. +Use a front-end to access graphically our complete microservice stack. Monitor our services with Azure Container Apps monitoring and scale our services depending on our needs. ## [10 - Blue/Green deployment](10-blue-green-deployment/README.md) -Deploy new versions of applications in a staging environment and switch between staging and production with Azure Spring Apps. +Deploy new versions of applications using Azure Container Apps revisions to achieve blue/green deployments. ## [11 - Configure CI/CD](11-configure-ci-cd/README.md)