By: Levi Masonde | Updated: 2024-11-19 | Comments | Related: > Cloud Strategy
Problem
You have used microservice architecture techniques to design a microservice application, but bringing the design to life is a different and difficult task. One issue: difficulty managing the compute infrastructure hosting these microservices and the environment in the cloud.
Solution
You can use infrastructure as code (IaC) to manage and provision computer resources to cloud applications and services. This enables you to define, deploy, and manage infrastructure components (like servers, networks, databases, etc.) using descriptive coding languages or templates. One of the leading descriptive languages used is Bicep.
In this four-part series tutorial, you will learn how to create a microservice application with Azure container apps and Dapr. Since the application relies on Bicep to develop infrastructure code, this part of the series will focus on building infrastructure with Bicep and how to deploy templates.
Prerequisites
Azure Resource Manager (ARM)
ARM is the service that enables you to create, update, audit, delete, and analyze resources in your Azure subscription. You can interact with ARM using tools like Azure web portal and Azure CLI/PowerShell or programmatically using JSON or Bicep. This article leans more towards interacting with ARM using Bicep.
You can read more about ARM: Azure Resource Management Templates to Simplify Cloud Entities. An important concept to understand about ARM operations is the control plane and the data plane. You should use:
- Control Plane: Manages the resources in your subscription. The control plane is like having control to provision resources on a server, like an admin.
- Data Plane: Accesses features or data that your resource exposes. The data plane is like an API exposed by an application on the server.
ARM basically acts as the middleman between your requests and Resource providers, like Azure data stores, container apps, or role assignments to ensure consistent, reliable, and secure deployments. This tutorial will show you how to interact with ARM using Bicep code.
What is Bicep?
Bicep is a domain-specific language (DSL) that uses declarative syntax to deploy Azure resources, i.e., Bicep can only be used to write scripts for ARM to process. This is done by defining the infrastructure you want to deploy to Azure using code that can be used repeatedly during the application's development lifespan to deploy consistent infrastructure multiple times.
When you write a Bicep file and deploy a resource, the Bicep code is first converted into JSON code through the transpilation process, then the JSON code is sent to ARM for processing. You'll define your resources within a Bicep file called a template, then submit the template to ARM. ARM then takes responsibility for deploying each resource within the template on your behalf.
Benefits of Bicep
Here are the advantages for using Bicep to code your infrastructure:
- Modules: You can use macro codes to break down complex template deployments by using decoupled modules to build your final deployments. This is like having a box of differently shaped Lego that you can use to build different structures with. Plus, you can share these modules or Lego pieces with your team.
- Simple Syntax: Bicep was made for deploying Azure resources to ARM, so the language has a simple syntax for interacting with ARM.
- Azure Native: Bicep is native to Azure, which means that it is directly connected to Azure's ecosystem. Therefore, your code will always be up-to-date with the latest Azure new technologies, and you do not have to wait for the technologies to be adapted like you would in the case of third-party IaC languages.
- No State Management: Bicep will keep state for you across its environment and you do not need to create a data storage account to log state.
- Automation: You can automate tasks that manage your Azure resources by writing a template and adding it to a pipeline with custom triggers.
Parameters and Variables
Bicep templates are powerful because of their reusability. You can use Bicep to write templates that deploy multiple environments or deploy multiple applications and services to the same environment.
One way Bicep enables developers to create reusable code is by using parameters. Parameters enable you to get values from outside the template file. If you want to deploy to Azure manually using Azure CLI or Azure PowerShell, you ideally want to create a separate JSON file to contain all the parameter values. If the template will be deployed in an automated pipeline, the pipeline should provide the parameter values.
Using Bicep, this is how you declare a parameter:
param resourceGroupName string = ''
When declaring a parameter, you must specify the type, as shown above. You will use parameters in the next section.
Bicep also uses variables, which are defined and set inside the template file. This is how variables are declared:
var abbrs = loadJsonContent('./abbreviations.json')
When declaring a variable, you do not need to specify the type, as shown above.
Outputs
When developing your Bicep application, you will need to pass parameter values dynamically since the deployments are automated, and there is not a lot of room for user inputs. Some resources depend on other resources. For example, as part of this tutorial, you must create the environment resource for your container apps. But, you need to keep analyzing the environment and you decide to use the logAnalyticsConfiguration property. This property requires you to provide a customer ID. For you to get the customer ID dynamically, you must first create a workspace resource that can output the customer ID. In this case, the environment resource depends on the workspace resource, so you must create the workspace resource using the following Bicep code:
metadata description = 'Creates a Log Analytics workspace.' param name string param location string = resourceGroup().location param tags object = {} resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { name: name location: location tags: tags properties: any({ retentionInDays: 30 features: { searchVersion: 1 } }) } output logAnalyticsWorkspaceId string = logAnalytics.outputs.id output name string = logAnalytics.name
Notice how this file outputs the customer id and name for other resources to use as parameters.
And this is how you can use this customer id output when you define the environment resource:
@description('Name of the Log Analytics workspace') param logAnalyticsWorkspaceName string resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2024-03-01' = { name: name location: location tags: tags properties: { appLogsConfiguration: { destination: 'log-analytics' logAnalyticsConfiguration: { customerId: logAnalyticsWorkspace.properties.customerId sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey } } daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights.properties.InstrumentationKey : '' } } resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { name: logAnalyticsWorkspaceName }
As you can see, this file uses a parameter logAnalyticsWorkspaceName to indicate that this value is expected by the file. The resource is defined using the "existing" keyword to specify that the resource has already been created. Its name in the Bicep application's domain is logAnlayticsWorkspaceName, then you can reference the resource.
Grouping Resources Using Modules
Now that you have created Bicep files to deploy different resources, you have to group all the individual resources and make the code more modularized. You can do this using modules. Bicep modules allow you to organize and reuse your Bicep code by creating smaller units that can be composed into a template.
All the Bicep templates we created in the previous section can now be used as modules by other Bicep templates. This will help to make the code more reusable, plus we can chain related templates and use outputs from one template as a parameter for another template. This is how you define a module:
module myModule 'modules/mymodule.bicep' = { name: 'MyModule' params: { location: location } }
Module use a module keyword and instead of including a resource type and API version, you'll use the module's file name with its path.
Activating Sandbox for Azure
Microsoft Learn has a Sandbox which allows you to use Azure resources for development and testing. The Sandbox assigns a Concierge subscription to an account you register the sandbox with for a limited time:
After you register for the sandbox, go to your terminal and use this Azure CLI command to log in to your account:
Az login
Select a Microsoft account. Ensure that you select and confirm the account you used to register for Sandbox:
If issues arise while setting up your subscription to the sandbox account, copy the subscription ID from the output shown above and use the following command:
az account set --subscription <subscription-id>
Deploy Application to Azure
Now, let's use Azure CLI to deploy the workspace template we defined earlier. First, create a file named log-analytics.Bicep and add the following code:
metadata description = 'Creates a Log Analytics workspace.' param name string param location string = resourceGroup().location param tags object = {} resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { name: name location: location tags: tags properties: any({ retentionInDays: 30 features: { searchVersion: 1 } }) } output id string = logAnalytics.id output name string = logAnalytics.name
Azure's sandbox account has a default resource group named learn-84c03279-b255-4b76-b98d-de362668cf5c and we can set this as our default resource group for the Bicep operations when we run the templates using Azure CLI:
az configure --defaults group="learn-84c03279-b255-4b76-b98d-de362668cf5c"
After running the command, ensure you navigate to your log-analytics.Bicep file's directory and run the following command to deploy the resource in the Bicep template:
az deployment group create --template-file log-analytics.bicep
To confirm your deployment, you will get an output with information about the resource on your terminal or you can log into your Azure portal. Click on your avatar after and change the directory to the Sandbox to see if the resource was created:
Great work! You successfully deployed your first resource using Bicep templates.
Conclusion
This tip serves as the foundation for a series of articles aiming to create a microservice application on Azure using container apps. These container apps will be used as a decoupled microservice that will communicate with other container apps/microservices. Being able to deploy container apps and other related resources in a reliable, secure, and dynamic manner are crucial to the application.
This article covers how Bicep templates can be used to create these resources, and breaks down the basic principles for coding in Bicep and how to deploy these templates to ARM. This is a good starting point if you want to understand the application in detail. The next article will add another layer to integrate your container apps with Dapr and, later, to build the application.
Next Steps
- Learn more about Serverless Microservice Computing Concepts and Architecture
- Learn how to create Azure Resource Manager templates.
- Learn how to use Azure CLI to manage your resources.
About the author
This author pledges the content of this article is based on professional experience and not AI generated.
View all my tips
Article Last Updated: 2024-11-19