Getting Started with Azure Bicep: Deploying a "Hello World" Web Application

Getting Started with Azure Bicep: Deploying a "Hello World" Web Application

A Beginner's Guide to Azure Bicep Files with Step-by-Step Deployment Instructions

Biceps? But I'm Not Into Weightlifting...

Don’t worry, there’s no heavy lifting required – only some clever coding. With Azure Bicep, your computer and a willingness to learn are all you need. Let’s dive in.

What is a Bicep File?

Bicep files are your gateway to deploying resources in Azure, offering a more straightforward approach than ARM Template files. If you're not familiar with ARM Templates, don't worry. It's helpful to focus solely on Bicep files for now. ARM templates can be challenging to understand and develop. Meanwhile, Microsoft's Bicep files provide equivalent functionality and capabilities but are notably easier to understand and work with, simplifying the experience of managing deployments in Azure.

Bicep Deployment Overview:

  1. Writing the Code: Begin by writing the deployment code in a Bicep file.

  2. Deployment to Azure: Use tools like the Azure CLI or the Azure portal to deploy the Bicep file to Azure.

  3. Conversion to ARM Template Code: Azure automatically converts the Bicep file's code into ARM template code upon deployment.

  4. Resource Creation: Finally, the ARM template code is used to create the necessary resources within Azure.

Benefits of Bicep

Wondering about the perks of Bicep files? Let’s look at it this way: Do you prefer automated processes over manual ones? If yes, we’re on the same page.

The primary advantage of using Bicep files is automation in resource deployments. Once you’ve crafted your Bicep file with the desired setup, you can reuse it across various platforms, like the Azure CLI, Azure Releases Pipeline, or even the Azure Portal.

Moreover, Bicep allows for parameter variation in each deployment. This flexibility is invaluable for systems with different environments. You can customize setups for testing and have entirely different configurations for production, ensuring each environment gets precisely what it needs.

What's the plan?

We're going to deploy a "Hello World" Web Application to Azure’s Web App service. It's not just about getting the app up and running; you'll pick up some cool skills along the way, such as:

  • Setting up an Azure Resource Group – think of this as your project’s home base in Azure.

  • Writing a Bicep file – the blueprint of our deployment plan.

  • Discovering Resource Templates for Bicep Deployments – I'll guide you through finding and using resource templates, essential in shaping your Bicep files.

  • Crafting a Bicep parameter file – this is where we get clever with our configuration, making our deployment adaptable.

  • Deploying your Bicep file using the Azure CLI – you’ll learn not only how to execute the deployment but also how to preview it first to ensure everything goes smoothly.

By the end of this, you’ll not only have your "Hello World" Web Application running on Azure but you'll also gain a comprehensive understanding of resource groups, Bicep files, App Service Plans, and Web App Services. Plus, you’ll become adept at deploying with different parameters. Excited to begin? Let's get started!

I'm Assuming

  1. You Have an Azure Subscription: To create resources, an Azure Subscription is required. If you don't have one yet, signing up is straightforward, and you'll immediately receive $200 in credits, which is more than enough for this project.

  2. A Prepared Resource Group: This is where we'll host our resources. If you’re not familiar with setting up a resource group in Azure, you can follow the steps outlined here.

  3. Basic Programming Knowledge: A fundamental understanding of programming will help you follow along more easily.

  4. IDE Installed: Something like VSCode should be on your machine, ready to go.

  5. Azure CLI: It's essential for our work. If it's not already set up, you can follow the download and install instructions in this link.

  6. Azure CLI - Bicep: Let's make sure you've got the Azure CLI's Bicep extension ready to use. Double-check by following the instructions here.

Let's Get Started!

We're kicking off by setting up our environment. Start by creating a new workspace folder, and inside that, create a file named deploy-app.bicep.

To deploy an App Service, we first need to prepare an App Service plan. This plan acts as a hosting environment for the App Service and defines the region, features, cost, and compute resources. Service plans are referred to as Microsoft.Web/serverfarms in Bicep. You can easily find the template from Microsoft with a quick Google search, and then copy it into our Bicep file. For your convenience, here's the link for easy access.

After trimming down the unnecessary configurations, our code snippet looks like this:

resource symbolicname 'Microsoft.Web/serverfarms@2022-09-01' = {
  name: 'string'
  location: 'string'
  properties: {
    reserved: true
  }
  sku: {
    name: 'string'
  }
  kind: 'string'
}

Next, let's focus on the App Service Bicep template itself. This service is where our site will live. In Bicep, App Services are known as Microsoft.Web/sites. Following the same steps as before, we search, find, and refine the template. Don't worry about the plethora of configuration options; here's a streamlined version for our purpose:

resource appService 'Microsoft.Web/sites@2020-12-01' = {
  name: 'string'
  location: 'string'
  kind: 'string'
  properties: {
    serverFarmId: 'string'
    httpsOnly: bool
    siteConfig: {
      appSettings: [
        {
          name: 'string'
          value: 'string'
        }
      ]
      publicNetworkAccess: bool
    }
  }
}

Now, let's tackle the code deployment to our new App Service. For this, we use a template called Microsoft.Web/sites/sourcecontrols. This template allows us to deploy our code directly from a public GitHub repository. In our case, we'll use it to deploy a simple "Hello World" application. For newcomers, this means that our App Service will automatically pull the code from the specified repository and branch, making the deployment process smooth and automated.

Here's how that part of the Bicep file should look:

resource srcControls 'Microsoft.Web/sites/sourcecontrols@2021-01-01' = {
  parent: 'string'
  name: 'string'
  properties: {
    repoUrl: 'string'
    branch: 'string'
    isManualIntegration: bool
  }
}

By the end of this setup, your deploy-app.bicep file will be a robust blueprint for your Azure deployment. It should look something like this: deploy-app.bicep.

Preparing Your Bicep File: Structuring for Success

A quick note before we continue: If you're eager to get straight to the action, you're welcome to skip ahead to the Creating Parameter Files for Different Environments (Testing vs. Production) section. But if you're here for some handy tips on structuring your Bicep file for success, let's dive in!

Tips on Structuring Your Code

  1. Logical Grouping: Organize related resources together. For instance, if you're creating a web app, group all resources related to the web app (like App Service, App Service Plan, and Storage Account) in one section.

  2. Use Comments Wisely: Comments are crucial for explaining why something is done a certain way, especially for complex logic. However, avoid over-commenting obvious things as it can clutter your code.

  3. Consistent Naming Conventions: Adopt a clear and consistent naming strategy for resources and variables. This not only makes your code more readable but also eases collaboration with others.

  4. Modular Approach: Break down your code into modules for reusability and simplicity. Each module should ideally represent a logical unit of deployment, like a network module, a storage module, etc.

Best Practices for Scalability and Maintenance

  1. Parameterization: Make use of parameters to avoid hard-coding values, especially those that might change (like environment names, sizes, and SKUs). This practice makes your Bicep files adaptable and easier to scale.

  2. Leverage Resource Dependencies: Bicep automatically handles resource dependencies, but understanding and defining these properly ensures that resources are deployed in the correct order.

  3. Version Control: Use version control systems like Git to track changes, collaborate with others, and maintain a history of your deployments. This is crucial for any scalable project.

  4. Testing: Regularly test your Bicep files in different environments. Testing helps to identify issues early and ensures that your deployments are reliable.

  5. Stay Updated: Make sure to keep up with the latest Azure Bicep updates. Regular releases bring new features, improvements, and bug fixes, all of which can greatly enhance your deployment experience.

By following these guidelines, you’ll set a strong foundation for your Azure Bicep files, ensuring they are not only effective and efficient but also scalable and easy to maintain.

Bicep Refinement

To enhance readability, maintainability, and overall deployment efficiency, let's fine-tune the base template by:

  1. Extracting Change-Expected Values into Parameters: We're moving values that are likely to change into parameters for easy adjustments.

     param location string = resourceGroup().location // Bicep function returning the resource group location
     param textToReplaceSubtitleWith string
     param repositoryBranch string
    
  2. Adding Clear and Concise Comments: Brief yet informative comments are key to understanding our parameters.

     @description('Azure resource deployment location.')
     param location string
    
     @description('The text to replace the default subtitle with.')
     param textToReplaceSubtitleWith string
    
     @description('Branch of the repository for deployment.')
     param repositoryBranch string
    
  3. Setting Defaults for Some Parameters: We'll assign default values to parameters that might not get values during deployment.

     @description('Azure resource deployment location.')
     param location string = resourceGroup().location
    
     @description('The text to replace the default subtitle with.')
     param textToReplaceSubtitleWith string = 'This is my default subtitle text. Boring, right?'
    
     @description('Branch of the repository for deployment.')
     param repositoryBranch string = 'main'
    
  4. Finalizing the Bicep File: We'll now incorporate our variables and set the remaining values and configurations.

     // App Service Plan Creation
     resource appServicePlan 'Microsoft.Web/serverfarms@2020-12-01' = {
       name: 'myAppServicePlan'
       location: location
       sku: {
         name: 'F1'
       }
       kind: 'app'
       properties: {
         reserved: false
       }
     }
    
     // Web App Creation
     resource appService 'Microsoft.Web/sites@2020-12-01' = {
       name: 'this-is-a-unique-name-for-the-web-app'
       location: location
       properties: {
         serverFarmId: appServicePlan.id
         httpsOnly: true
         siteConfig: {
           appSettings: [
             {
               name: 'TEXT_TO_REPLACE_SUBTITLE_WITH' // This value needs to match the name of the environment variable in the application code
               value: textToReplaceSubtitleWith
             }
             {
               name: 'SCM_DO_BUILD_DURING_DEPLOYMENT' // Build the application during deployment
               value: 'true'
             }
             {
               name: 'WEBSITE_NODE_DEFAULT_VERSION' // Set the default node version
               value: '~20'
             }
           ]
           publicNetworkAccess: 'Enabled'
         }
       }
     }
    
     // Source Control Integration
     resource srcControls 'Microsoft.Web/sites/sourcecontrols@2021-01-01' = {
       parent: appService
       name: 'web'
       properties: {
         repoUrl: 'https://github.com/FarzamMohammadi/hello-world'
         branch: repositoryBranch
         isManualIntegration: true
       }
     }
    

The final result should align with this deploy-webapp.bicep file. Wondering how I know which configurations to use? Well, it's a mix of scouring documentation and good old Google searches. Often, someone else's shared solution is the key to unlocking your deployment puzzles.

Creating Parameter Files for Different Environments (Testing vs. Production)

When deploying applications in Azure, it's common to have separate settings for different environments, such as testing and production. This is where parameter files come into play. They allow you to define environment-specific values without altering the core Bicep file. This approach not only simplifies management but also reduces the risk of errors when moving from testing to production.

For our "Hello World" web app, we've prepared two parameter files: parameters.test.json for testing and parameters.json for production. The primary distinction between these files is the source code branch they target.

parameters.json (Production Environment)

This file, used for the production environment, adheres to the default branch specified in the Bicep file. It doesn't require an explicit repositoryBranch parameter.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "textToReplaceSubtitleWith": {
      "value": "This site was released to Azure using a Bicep file. Biceps are better than ARM templates!"
    }
  }
}

parameters.test.json (Testing Environment)

In this file, we've included the repositoryBranch parameter. This simple yet effective change specifies that Azure should use code from the "test" branch for deployment. It's a practical way to ensure that during the testing phase, we are deploying exactly what's intended for testing, separate from our production environment.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "textToReplaceSubtitleWith": {
      "value": "This site is being tested and was released to Azure using a Bicep file. Let's see if Biceps are better than ARM templates."
    },
    "repositoryBranch": {
      "value": "test"
    }
  }
}

The repositoryBranch parameter in the test file is a key example of how changing one parameter can shift the deployment from production to testing. This helps demonstrate the real-world effects of such variations.

Time to Deploy

Azure CLI Preparation

First things first, we need to authenticate ourselves with the Azure CLI before deploying our Bicep file. It's simple: just run az login. You'll be taken to the Azure portal for a quick sign-in.

Once authenticated, a confirmation message will appear, indicating we're ready to proceed.

Now, let's set the Azure account subscription. Just run az account set --subscription <SUBSCRIPTION_ID>, replacing <SUBSCRIPTION_ID> with your actual subscription ID. And with that, we're set for deployment.

Deploying Bicep With Test Parameters

We'll start by deploying our Bicep file using the parameters.test.json file. Before deploying, it's wise to preview our changes. Using the --confirm-with-what-if option in Azure CLI, we can get a sneak peek of what our deployment will entail.

Run this command in the same directory as your Bicep file:

az deployment group create --resource-group my-rg --template-file deploy-webapp.bicep --parameters parameters.test.json --confirm-with-what-if

Understanding the Command:

  • Resource Group: Use the --resource-group tag to specify the Resource Group where your resources will be deployed.

  • Bicep File: The --template-file tag is followed by the name of your Bicep file.

  • Parameter File: Use the --parameters tag to specify the Parameter JSON file that will override your Bicep parameters.

  • Confirm Before Deployment: The --confirm-with-what-if tag gives you a preview of all the changes about to be made. It's your chance to review everything and confirm whether to proceed or not.

This preview helps identify any potential issues. Once confident, proceed with deployment by pressing y and enter.

Note: You can skip the preview and deploy directly using the same command without --confirm-with-what-if.

Monitoring the Deployment Progress

During deployment, check out "Deployments" in your resource group. This area lets you monitor the progress, review the status, and troubleshoot if needed.

After deployment, delve into the details by selecting your deployment, then your uniquely named App Service under "Resources".

Clicking the "Default domain" URL in the overview will take you to your newly deployed site.

If things went smoothly, you should see something like this:

Keep this tab open and let's discuss why we're seeing this "From the Test branch" text.

Executing the Steps: Video Demonstration

For a visual guide on deploying with test parameters, watch the first video. It details each step from "Azure CLI Preparation" to "Understanding the Deployment of the Test Branch."

Understanding the Test Branch Deployment

Our deployment targeted the test branch due to the parameters.test.json file. This file specifies the repositoryBranch as 'test', directing Azure to pull code from this branch.

Deploying Bicep With Production Parameters

Next, let’s deploy using the parameters.json file for a production setup.

Important Step: Disconnect Source Control in App Service

After testing your deployment, there's a crucial step to ensure everything works smoothly. I encountered a bug with the "Source Control" feature that prevented it from updating the branch name to "main" during redeployment. To avoid this issue and proceed successfully, manually disconnect the source control settings:

  1. Go to Your App Service: Open the Azure portal and select your App Service created for Bicep deployment.

  2. Find Deployment Center: Inside your App Service, locate and click on "Deployment Center."

  3. Disconnect: In the Deployment Center, simply click the "Disconnect" button to remove the source control link.

This step is vital for the next part of our deployment process to work correctly.

If you're interested in the exact details of this bug, take a look at the issue I created in the Azure Bicep repository. Visit Azure Bicep Issue #12544 for more information.

Deploying the production code is similar to the test deployment. Use this command:

az deployment group create --resource-group my-rg --template-file deploy-webapp.bicep --parameters parameters.json

With parameters.json missing the repositoryBranch property, deployment defaults to the previously set "main" branch in our Bicep file.

@description('Branch of the repository for deployment.')
param repositoryBranch string = 'main'

After the deployment is complete, the view should now reflect the main branch code, as shown here, without any mentions of the Test branch:

And just like that, you’ve completed not one, but two Bicep deployments, and your website is live for the world to see. Congratulations!!

Additional Video: Production Parameter Deployment Walkthrough

For insights into deploying with the "production" parameters, check out this second video. It illustrates the use of parameters.json file, to simulate various deployment scenarios. This video serves as a practical complement to the first, enhancing your understanding of Bicep deployment flexibility.

Troubleshooting Common Issues

Deployment Troubleshooting

If you encounter non-syntax related issues during deployment, a good starting point is the Deployment logs in your Resource Group. These logs can help pinpoint which resources are causing trouble and clarify error messages.

Azure CLI Issues

For Azure CLI-related problems, the official documentation is a reliable resource. It offers detailed solutions and step-by-step guidance for many common issues.

Additional Tips:

  • Check Parameter Mismatches: Ensure your parameter file correctly matches the parameters in your Bicep file. Even small mismatches or typos can lead to unexpected issues.

  • Resource Dependencies: The order of resource deployment can be crucial. Review your Bicep file to ensure dependencies are appropriately managed.

  • API Version Compatibility: Keep your API versions in Bicep templates up-to-date. Older versions may lead to unexpected behaviors.

  • Community Forums and Support: Azure forums and platforms like Stack Overflow are valuable for finding solutions to complex problems.

  • Local Validation and Testing: It's important to validate your Bicep files locally before deploying. You can use the Bicep CLI for this. The --confirm-with-what-if tag in Azure CLI is also useful for previewing changes and catching potential issues early.

Expanding Beyond "Hello World"

Next on the agenda is something a bit more advanced: a guide on deploying containerized applications to Azure using Bicep. This is for those looking to take their Azure skills up a notch, so stay tuned!

Got any Bicep or Azure topics you're itching to learn more about? Send me a message or leave a comment below. I'm always keen to collaborate and explore new ideas!

Conclusion: Wrapping Up and Looking Ahead

That’s it for our Azure Bicep guide! We’ve tackled everything from Bicep basics to getting a "Hello World" Web Application up and running on Azure. The goal was to make things straightforward and practical, and I hope you found it useful.

Along the way, we’ve seen how to write, refine, and deploy with Bicep, not to mention a little bit of Azure CLI in action. Hopefully, the video demo made things even clearer.

Up next, I’m planning to cover the deployment of containerized applications using Bicep, so there’s more useful content on the way. If you have any Bicep or Azure topics you’re curious about, feel free to let me know – your input could guide what comes next.

Thanks for joining me on this journey. Here’s to creating killer software solutions, and successful Azure projects! Keep an eye out for what’s next!

Additional Resources and Further Reading

General Microsoft Bicep Documentation:

Best Practices:

Visual Resources and Tutorials:

Did you find this article valuable?

Support Farzam Mohammadi by becoming a sponsor. Any amount is appreciated!