Skip to content

Commit

Permalink
Add Spring Boot PetClinic Microservices sample application (#160)
Browse files Browse the repository at this point in the history
* Add contribution proposal

* add configuration

* Update README.md

* Update README.md

* Add PetClinic Source

* docker image build with tag

* Add README.md

* temp

* Add service connector

* Update README.md

* Delete scenarios/aca-internal/bicep/sample-apps/spring-petclinic-microservices/README_PROPOSAL.md

* fix comments

* Add random mysql name

* Add Prerequisities

* Add delegate agent pool

* Rename

* Update config server

* Update to official repo

* Add description
  • Loading branch information
yuwzho authored Sep 30, 2024
1 parent 2f1620e commit 6a3cf6a
Show file tree
Hide file tree
Showing 155 changed files with 16,621 additions and 3 deletions.
10 changes: 9 additions & 1 deletion scenarios/aca-internal/bicep/modules/02-spoke/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ export MSYS_NO_PATHCONV=1

:warning: You will need to get the IP address of your Azure firewall or whatever network appliance you are using and replace the `[IP OF THE NETWORK APPLIANCE] placeholder in the deploy.spoke.paramters.jsonc file with it.

1. Get the private IP address of your Azure firewall

```bash
NETWORK_APPLIANCE_IP_ADDRESS=$(az deployment sub show -n acalza01-hub --query properties.outputs.networkApplianceIpAddress.value -o tsv)
echo NETWORK_APPLIANCE_IP_ADDRESS: $NETWORK_APPLIANCE_IP_ADDRESS
```

1. Create the regional spoke network.

```bash
Expand All @@ -40,7 +47,8 @@ export MSYS_NO_PATHCONV=1
-n acalza01-spokenetwork \
-l $LOCATION \
-f 02-spoke/deploy.spoke.bicep -p 02-spoke/deploy.spoke.parameters.jsonc \
-p hubVNetId=${RESOURCEID_VNET_HUB}
-p hubVNetId=${RESOURCEID_VNET_HUB} \
-p networkApplianceIpAddress=${NETWORK_APPLIANCE_IP_ADDRESS}
```

1. Explore your networking resources. *Optional.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ By default, they are deployed to the spoke resource group.
```

```bash
# [This takes about four minutes to run (if you add deployRedis=false).]
# [This takes about four minutes to run (if you add deployRedisCache=false).]
az deployment group create \
-n acalza01-dependencies \
-g $RESOURCENAME_RESOURCEGROUP_SPOKE \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ output containerRegistryLoginServer string = containerRegistry.outputs.container
@description('The resource ID of the user-assigned managed identity for the Azure Container Registry to be able to pull images from it.')
output containerRegistryUserAssignedIdentityId string = containerRegistry.outputs.containerRegistryUserAssignedIdentityId

@description('The name of the contianer registry agent pool name to build images')
output containerRegistryAgentPoolName string = containerRegistry.outputs.containerRegistryAgentPoolName

@description('The resource ID of the Azure Key Vault.')
output keyVaultId string = keyVault.outputs.keyVaultId

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ module containerRegistry '../../../../../shared/bicep/container-registry.bicep'
publicNetworkAccess: 'Disabled'
networkRuleBypassOptions: 'AzureServices'
diagnosticWorkspaceId: diagnosticWorkspaceId
agentPoolSubnetId: spokePrivateEndpointSubnet.id
}
}

Expand Down Expand Up @@ -147,4 +148,7 @@ output containerRegistryLoginServer string = containerRegistry.outputs.loginServ
@description('The resource ID of the user assigned managed identity for the container registry to be able to pull images from it.')
output containerRegistryUserAssignedIdentityId string = containerRegistryUserAssignedIdentity.id

@description('The name of Azure container registry agent pool name to build images')
output containerRegistryAgentPoolName string = containerRegistry.outputs.agentPoolName


Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# # Sample App: Spring Petclinic Microservices

Spring Petclinic Microservices is a Java microservice application that simulates a pet clinic management system.

![Spring Petclinic Microservices](docs/media/spring-petclinic-overview.png)

The application allows users to manage information about pets, their owners, and visits to the clinic. It is built using Spring Boot and follows a microservices architecture.

The sample app is available [here](https://github.com/azure-samples/spring-petclinic-microservices). The branch used for this scenario is [main](https://github.com/azure-samples/spring-petclinic-microservices/tree/main).

## Overview

The Spring Petclinic Microservices sample app consists of several microservices:

* `customers-service`
* `vets-service`
* `visits-service`
* `api-gateway`

Interaction/communication between these microservices is described below:

![Services](docs/media/spring-petclinic-sequence-diagram.png)

## Deployment

The deployment of the sample app is done in 2 steps:

1. :arrow_forward: [Deploy the landing zone](./docs/01-landing-zone.md)
2. :arrow_forward: [Create the container apps](./docs/02-container-apps.md)
2. :arrow_forward: [Connect the container apps with MySql DB](./docs/03-connect-to-db.md)
2. :arrow_forward: [Deploy the PetClinic microservices](./docs/04-deploy-apps.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mysqlSubnetPrefix": {
"value": "10.1.2.64/28"
},
"spokeVnetId": {
"value": "[SPOKE-VENT-RESOURCE-ID]"
},
"hubVnetId": {
"value": "[HUB-VNET-RESOURCE-ID]"
},
"subnetName": {
"value": "snet-mysql"
},
"workloadName": {
"value": "lzaaca"
},
//The name of the environment (e.g. "dev", "test", "prod", "preprod", "staging", "uat", "dr", "qa"). Up to 8 characters long.
"environment": {
"value": "dev"
},
"databaseName": {
"value": "petclinic"
},
"administratorLogin": {
"value": "azureuser"
},
"administratorLoginPassword": {
"value": "Password123"
},
"version": {
"value": "8.0.21"
},
"managedEnvironmentsName": {
"value": "[ACA-ENVIRONMENT-NAME]"
},
"configServerGitRepo": {
"value": "https://github.com/Azure-Samples/spring-petclinic-microservices-config"
},
"configServerGitBranch": {
"value": "master"
},
"acrIdentityId": {
"value": "[ACR-IDENTITY-RESOURCE-ID]"
},
"acrRegistry": {
"value": "[ACR-REGISTRY-SERVER]"
},
"simpleHelloImage": {
"value": "azuredocs/containerapps-helloworld"
},
"simpleHelloTag": {
"value": "latest"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Deploy the Landing Zone

To deploy the Landing Zone, you can follow the complete guide in [Enterprise Scale for ACA - Private](../../../../bicep/README.md).

The deployment of the sample app deploys also an application gateway with the same name as the one of the landing zone. It is recommended to deploy only the first four building blocks of the landing zone and then deploy the sample app, i.e. do not deploy hello world sample app and application gateway. To do so, you can set the attribute `deployHelloWorldSampleApp` to `false` in the parameters file of the landing zone.

:arrow_forward: [Deploy Container Apps](./02-container-apps.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Create the Container Apps with supporting services

Once the landing zone is deployed, the container apps environment and their dependencies are already set up in the private networking environment.

## Expected results
This documentation guides how to deploy the container apps and connect them with the created supporting services.

## Resources

- Azure Database for MySQL flexible server.
- Azure Container Apps Java components
- [Eureka Server](https://learn.microsoft.com/en-us/azure/container-apps/java-eureka-server?tabs=azure-cli)
- [Config Server](https://learn.microsoft.com/en-us/azure/container-apps/java-config-server?tabs=azure-cli)
- Azure Container Apps
- Connect Azure Container Apps to the Eureka Server and Config Server.
- Connect Azure Container Apps to MySQL flexible server and Azure Container Registry with User Assigned Identity.

## Steps

1. Go to the sample application folder as work directory

```bash
cd ../sample-apps/cloud-foundry-spring-boot-application
```

1. Retrieve the Networking and Azure Container Registry information from previous deployment.

```bash
RESOURCENAME_RESOURCEGROUP_SPOKE=$(az deployment sub show -n acalza01-spokenetwork --query properties.outputs.spokeResourceGroupName.value -o tsv)
ENVIRONMENT_NAME=$(az deployment group show -n acalza01-appplat -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.containerAppsEnvironmentName.value -o tsv)
RESOURCEID_IDENTITY_ACR=$(az deployment group show -n acalza01-dependencies -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.containerRegistryUserAssignedIdentityId.value -o tsv)
REGISTRYNAME_ACR=$(az deployment group show -n acalza01-dependencies -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.containerRegistryName.value -o tsv)
LOGINSERVER_ACR=$(az deployment group show -n acalza01-dependencies -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.containerRegistryLoginServer.value -o tsv)
RESOURCEID_VNET_HUB=$(az deployment sub show -n acalza01-hub --query properties.outputs.hubVNetId.value -o tsv)
RESOURCEID_VNET_SPOKE=$(az deployment sub show -n acalza01-spokenetwork --query properties.outputs.spokeVNetId.value -o tsv)

echo RESOURCENAME_RESOURCEGROUP_SPOKE: $RESOURCENAME_RESOURCEGROUP_SPOKE && \
echo ENVIRONMENT_NAME: $ENVIRONMENT_NAME && \
echo RESOURCEID_IDENTITY_ACR: $RESOURCEID_IDENTITY_ACR && \
echo REGISTRYNAME_ACR: $REGISTRYNAME_ACR && \
echo LOGINSERVER_ACR: $LOGINSERVER_ACR && \
echo RESOURCEID_VNET_HUB: $RESOURCEID_VNET_HUB && \
echo RESOURCEID_VNET_SPOKE: $RESOURCEID_VNET_SPOKE
```

1. Import a wellknown hello world image to the private Azure Container Registry for further deploy. This hello world image will help to verify the resource creation.

```bash
az acr import -n ${REGISTRYNAME_ACR} --source mcr.microsoft.com/azuredocs/containerapps-helloworld:latest
```

1. Create the desired resources

```bash
az deployment group create -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE \
-f main.bicep \
-p deploy.spring-petclinic-microservices.jsonc \
-p spokeVnetId=${RESOURCEID_VNET_SPOKE} \
-p hubVnetId=${RESOURCEID_VNET_HUB} \
-p managedEnvironmentsName=${ENVIRONMENT_NAME} \
-p acrIdentityId=${RESOURCEID_IDENTITY_ACR} \
-p acrRegistry=${LOGINSERVER_ACR}
```

1. Retrieve the FQDN of the microservices

```bash
FQDN=$(az deployment group show -g $RESOURCENAME_RESOURCEGROUP_SPOKE -n acalza01-appplat-java --query properties.outputs.fqdn.value -o tsv)
```

1. Create the Application Gateway that connect to the microservices. Replace the environment variable `FQDN_HELLOWORLD_ACA=$FQDN` when creating the Application Gateway. Tutorial can be viewed at [06-application-gateway](../../../modules/06-application-gateway/README.md). Note to change the working directory when creating the Application Gateway.

```bash
cd ../../modules
```

## Verification

1. Go to the sample application folder as work directory

```bash
cd ../sample-apps/cloud-foundry-spring-boot-application
```

1. Get the public IP of Application Gateway.

```bash
IP_APPGW=$(az deployment group show -g $RESOURCENAME_RESOURCEGROUP_SPOKE -n acalza01-appgw --query properties.outputs.applicationGatewayPublicIp.value -o tsv)
echo $IP_APPGW
```

1. Access the "Hello World" application running in Azure Container Apps.

Using your browser either navigate to **https://\<IP_APPGW from prior step>** from above, or if you added the host file entry, to **<https://acahello.demoapp.com>**. *Because the cert is self-signed for this walkthrough, you will need to accept the security warnings presented by your browser.*

![Welcome to Azure Container Apps!](./hello-world.png)

## Next step

:arrow_forward: [Connect Container Apps with MySql Flexible Server](./03-connect-to-db.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Connect Container Apps with MySql Flexible Server

After create the Azure Container Apps and MySql Flexible Server, they are ready to be connected and work together. Since all these workloads are deployed inside a Virtual Network environment, all the operation to them should be finished inside the Virtual Network. Fortunately, we can use the jumbox we created before to operate these resources.

## Expected results
All the container apps can successfully connect to the MySql Flexible Server.

## Steps
1. Login to the VM using Bastion

The username and password can be retrieved or set in [deploy.spoke.parameters.jsonc](../../../modules/02-spoke/deploy.spoke.parameters.jsonc), view `vmAdminUsername` and `vmAdminPassword`.

![bastion](../../../../../../docs/media/acaInternal/bastion-login.png)

1. Install pre-reqs Azure CLI, Docker client

Unfortunatelly the jump host doesn't have the required tools installed. So, you would have to install them.

- [az cli](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt)
```bash
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
```
- Add necessary extensions
```bash
az extension add --name containerapp
az extension add --name serviceconnector-passwordless --upgrade
```

1. Login the Azure CLI and select current subscription. The subscription id can be retrieved from the Virtual Machine's overview blade.
```bash
az login --use-device-code
az account set -s <your-subscription-id>
```
1. Retrieve the environments
```bash
RESOURCENAME_RESOURCEGROUP_SPOKE=$(az deployment sub show -n acalza01-spokenetwork --query properties.outputs.spokeResourceGroupName.value -o tsv)
RESOURCEID_GATEWAY=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.apiGatewayId.value -o tsv)
RESOURCEID_CUSTOMERSERVICE=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.customerServiceId.value -o tsv)
RESOURCEID_VISITSSERVICE=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.visitsServiceId.value -o tsv)
RESOURCEID_VETSSERVICE=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.vetsServiceId.value -o tsv)
RESOURCEID_MYSQL_DATABASE=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.databaseId.value -o tsv)
RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.userAssignedIdentityClientId.value -o tsv)
RESOURCEID_MYSQL_USERASSIGNEDIDENTITY=$(az deployment group show -n acalza01-appplat-java -g $RESOURCENAME_RESOURCEGROUP_SPOKE --query properties.outputs.userAssignedIdentity.value -o tsv)
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
echo RESOURCENAME_RESOURCEGROUP_SPOKE=$RESOURCENAME_RESOURCEGROUP_SPOKE && \
echo RESOURCEID_GATEWAY=$RESOURCEID_GATEWAY && \
echo RESOURCEID_CUSTOMERSERVICE=$RESOURCEID_CUSTOMERSERVICE && \
echo RESOURCEID_VISITSSERVICE=$RESOURCEID_VISITSSERVICE && \
echo RESOURCEID_VETSSERVICE=$RESOURCEID_VETSSERVICE && \
echo RESOURCEID_MYSQL_DATABASE=$RESOURCEID_MYSQL_DATABASE && \
echo RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID=$RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID && \
echo RESOURCEID_MYSQL_USERASSIGNEDIDENTITY=$RESOURCEID_MYSQL_USERASSIGNEDIDENTITY && \
echo SUBSCRIPTION_ID=$SUBSCRIPTION_ID
```
1. Create Service Connector for Azure Container Apps and MySql Flexible Server. The below commands create users in the database and these user will be used by Azure Container Apps to connect to database.
```bash
az containerapp connection create mysql-flexible --connection mysql_api_gateway \
--source-id ${RESOURCEID_GATEWAY} \
--target-id ${RESOURCEID_MYSQL_DATABASE} \
--client-type springBoot \
--user-identity \
client-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID} \
subs-id=${SUBSCRIPTION_ID} \
mysql-identity-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY} \
-c api-gateway
az containerapp connection create mysql-flexible --connection mysql_customer_service \
--source-id ${RESOURCEID_CUSTOMERSERVICE} \
--target-id ${RESOURCEID_MYSQL_DATABASE} \
--client-type springBoot \
--user-identity \
client-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID} \
subs-id=${SUBSCRIPTION_ID} \
mysql-identity-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY} \
-c customer-service
az containerapp connection create mysql-flexible --connection mysql_visits_service \
--source-id ${RESOURCEID_VISITSSERVICE} \
--target-id ${RESOURCEID_MYSQL_DATABASE} \
--client-type springBoot \
--user-identity \
client-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID} \
subs-id=${SUBSCRIPTION_ID} \
mysql-identity-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY} \
-c visits-service
az containerapp connection create mysql-flexible --connection mysql_vets_service \
--source-id ${RESOURCEID_VETSSERVICE} \
--target-id ${RESOURCEID_MYSQL_DATABASE} \
--client-type springBoot \
--user-identity \
client-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY_CLIENTID} \
subs-id=${SUBSCRIPTION_ID} \
mysql-identity-id=${RESOURCEID_MYSQL_USERASSIGNEDIDENTITY} \
-c vets-service
```
## Next step
:arrow_forward: [Deploy the Container Apps](./04-deploy-apps.md)
Loading

0 comments on commit 6a3cf6a

Please sign in to comment.