This sample demonstrates how to create an Azure Managed Application with a link to a publisher's backend to be able to receive commands to update the managed application using docker containers with IaC code running in the context of the Managed Resource Group.
Azure Managed Applications allow Independent Software Vendors (ISVs) to distribute Azure-based solutions as a single package, via a Service Catalog (internally) and via the Azure Marketplace (externally). Application developers must implement a mechanism to update Azure Managed Applications once they have been deployed. One thing to be conscious of is that once a version of the solution is deployed, the only way to get an updated version is to remove it from the subscription and re-adding the updated version.
A possible way to tackle both the application and infrastructure upgrading issue is to split the application deployment into two phases:
- The initial deployment of the baseline resources to establish a communication channel between the deployed solution and the publisher.
- The deployment of the application itself, which will be updated independently from the baseline resources.
This approach allows the publisher to update the application without affecting the baseline resources. Those resources are the ones that are required to establish a communication channel between the deployed solution and the publisher. This communication channel can be used to monitor the deployed solution and to provide the publisher with the means to apply updates to the application without requiring user intervention.
The following diagram shows a high-level flow of the solution:
graph TD
AMA --> | Triggers | ID[Initial deployment]
Customer --> | Deploys | AMA[Azure Managed App]
ID --> | Creates | MRG[Managed Resource Group]
ID --> | Creates | BR[Baseline resources]
BR --> | Comm. channel | Publisher
Publisher --> | App deployment/update | BR
BR --> | App resources | MRG
MRG --> | Makes available | App
A relatively simple way to establish a communication channel between the deployed solution and the publisher is to use an HTTP endpoint. This endpoint could be an HTTP-triggered Azure Function that is deployed as part of the baseline resources and that is responsible for receiving and processing the application and infrastructure update requests, using an identity that has the necessary permissions to perform the required operations.
In a similar manner, the publisher could also use an HTTP-triggered Azure Function listening for requests coming from the deployed solution. This could be used to notify the publisher of any issues or to provide the publisher with any telemetry data.
The solution is composed of the following components:
- Publisher's backend:
-
A
deploymentfunction, used to trigger the deployment of a new version of the application for an already deployed Azure Managed Application. -
A
webhookfunction that is triggered when a new Azure Managed Application instance is deployed. This function will create an entry in a Cosmos DB database containing theapplicationIdof the deployed Azure Managed Application instance. -
setcommandurlfunction that is triggered when a new Azure Managed Application instance is deployed. This function will update thecommandUrlproperty of the Cosmos DB record with the URL and key of thecommandsfunction deployed in the Managed Resource Group. -
eventsfunction used to receive events from the deployed Azure Managed Applications. -
Azure Managed Application deployment:
- A
commandsfunction that is deployed in the Managed Resource Group. This function will be invoked by the publisher's backend to update the deployed Azure Managed Application instance.
- A
-
- Azure Subscription
- Azure CLI
- Docker
- Appliance Resource Provider Object Id (it can be retrieve searching for "Appliance Resource Provider in the Azure Portal, in the Active Directory section)
If you are using WSL on Windows, make sure the zip command is available. You can install it by issuing this command-line sudo apt install zip.
ama-update-sample
├── .devcontainer # devcontainer configuration
├── .vscode # vscode configuration
├── ama # Azure Managed Application components
│ └── commands # "commands" function to be deployed in the Managed Resource Group
│ ├── definition # Azure Managed Application definition (bicep + json templates)
│ └── resources # Docker image with IaC code to be deployed in the Managed Resource Group
├── publisher # Publisher's backend components
│ ├── deployment # "deployment" function to be deployed in the publisher's backend
│ ├── events # "events" function to be deployed in the publisher's backend
│ ├── setcomandurl # "setcommandurl" function to be deployed in the publisher's backend
│ ├── webhook # "webhook" function to be deployed in the publisher's backend
│ └── iac # IaC code to deploy the publisher's backend
└── utils # Utility classes used by all the functionsTo deploy the publisher's backend and the Azure Managed Application definition, you need to run the following commands in the root folder of the repository:
export RESOURCE_GROUP_NAME=<resource group name>
export LOCATION=<location>
export APPLIANCE_RESOURCE_PROVIDER_OBJECT_ID=<object id>
./deploy.shThis will create a resource group with the name specified in the RESOURCE_GROUP_NAME environment variable, and deploy all the resources in that resource group. It will also create an Azure Managed Application definition called ama-update-sample in the service catalog.
Instances of the Azure Managed Application can be created using the az CLI or the Azure Portal.
During the deployment, the publisher's backend will be notified of the deployment, and the webhook function will be triggered. This function will create an entry in the deployed Cosmos DB database containing the deployment applicationId.
The last phase of the deployment will invoke the setcommandurl function, which will update the commandUrl property of the Cosmos DB record with the URL and key of the commands function deployed in the Managed Resource Group.
To update an Azure Managed Application instance, you can send a POST request to the deployment function deployed in the publisher's backend. The body of the request should be a json with the applicationId of the Azure Managed Application instance to be updated, and the full name of the docker image to deploy in the image field. During the backend deployment phase, a sample image was deployed in the publisher's backend, so you can use that image for the update. The image is <prefix>acr.azurecr.io/ama-update-sample-resources:<tag> and can be found in the publisher's Container Registry.
Here is an example of the JSON message for the POST request:
{
"applicationId":"subscriptionsaf4cbd2f-24f1-408a-9945-c7594b98c964resourcegroupspabloprovidersmicrosoft.solutionsapplicationsmyupdatableapp",
"image": "abecaxkqnyv7qh6acr.azurecr.io/ama-update-sample-resources:1673630025"
}
When a new deployment is triggered in the Managed Resource Group, the events function will be triggered. This function will add a new entry in the Cosmos DB database with the applicationId and the image of the deployment.
This step is invoked manually via a Postman tool in this tutorial, but in an actual deployment system, it would be automatically called from the Publisher's backend, called when a new version of the container image is available.
To delete all the deployed resources, you can run the following command:
# by default, it will pick up the resource group name used in the deployment
# To override it, you can export the RESOURCE_GROUP_NAME environment variable
./cleanup.sh