In this sample, you'll learn how to define creating Azure Marketplace VM images on HCI and creating VMs using those image in GitHub Action and how to deploy your Bicep code by using the workflow.
Short URL to this page: https://aka.ms/ashci/automate-bicep/github-actions
Video recording - Automate: Azure Marketplace VMs on HCI using Bicep and GitHub Actions! |
- To set up VM images, users manually had to download the operating system images, set up a VM, and create a generalized VM image.
- To keep track of new updates, such as security patches, bug fixes, and feature enhancements, users were manually tracking and deploying updates.
- Custom VM images often leads to compliance scrutiny, causing delays in the assessment, and implementation process.
- To automate at-scale, user couldn’t set up VM images and VMs from Azure. This required switching to on-premises tools.
Suppose you're responsible for deploying and configuring the VMs on Azure Stack HCI cluster to support an internal testing team.
Multiple such internal teams ask for new virtual machines regularly, so the deployment process has become time-consuming. You want to find a way to automate the process so that you can focus on other key tasks.
You also want your colleagues to be able to make changes and deploy the VMs themselves. But you need to make sure your colleagues follow the same process that you use!
You decided to create a deployment workflow that will run automatically every time the Bicep code is updated in your shared repository. The workflow will deploy your Bicep files to Azure.
- Author Azure Bicep file to create Azure Marketplace VM images and VMs
- Set up GitHub Actions to run automatically when Bicep code is updated
- Configure Actions to deploy VM images and VMs from Azure.
To work through the sample, you'll need an Azure account, with the ability to create resource groups, Azure Active Directory applications and access to Azure Stack HCI clusters with Arc VM management configured.
You'll also need the following installed locally:
- Visual Studio Code
- The Bicep extension for VS Code.
- The GitHub Pull Requests and Issues extension for VS Code
- Git
- In a browser, go to GitHub. Sign in by using your GitHub account, or create a new account if you don't have one.
- Create a new repository on your personal account or any organization. Refer Create a new repository.
- In Visual Studio Code, clone your repository. Refer Working with GitHub in VS Code .
NOTE To successfully run the below script to set up you need to appropriate permissions. If not, ask this script to be executed by your administrator.
- Ensure that you've permissions to create Azure AD Application
- Assign the AAD application "Contributor" permissions to the resource group where VMs and VM images will be created. You must have access to the
Microsoft.Authorization/roleAssignments/write
action. Of the built-in roles, only User Access Administrator and Owner and are granted access to this action.
- Download the files
workflow-identity-setup.sh
andaad-fed-cred.json
. In the Visual Studio Code terminal, run thiswget
command to download the file.- To setup identity, download script, ../cli-common/workflow-identity-setup.sh
wget -o workflow-identity-setup.sh https://raw.githubusercontent.com/anoobbacker/ashci-automation-samples/main/cli-common/workflow-identity-setup.sh
- To set up AAD Federation Credentials, download JSON ../json/aad-fed-cred.json.
workflow-identity-setup.sh
script uses this JSON.
wget -o aad-fed-cred.json https://raw.githubusercontent.com/anoobbacker/ashci-automation-samples/main/json/aad-fed-cred.json
- Change the variables in
workflow-identity-setup.sh
# Assigning default values for variable subscription=${1:-"00000000-0000-0000-0000-000000000000"} # Replace with your Subscription ID resourcegroup=${2:-"HCICluster"} # Replace with your resource group where the bicep file will be deployed githubOrganizationName=${3:-"anoobbacker"} # Replace mygithubuser with your GitHub username githubRepositoryName=${4:-"ashci-automation-samples"} # Replace with your GitHub repository aadFedCredFile=${5:-"./aad-fed-cred.json"} # Replace with the path to your AAD Fed Cred JSON file
- Launch Cloud Shell from the the top navigation of the Azure Portal. Refer Quickstart for Azure Cloud Shell
- Upload files
workflow-identity-setup.sh
andaad-fed-cred.json
into Cloud Shell. Refer Upload files - In Azure Cloud Shell, change the permission to execute the file.
chmod +x workflow-identity-setup.sh
- Execute the script
workflow-identity-setup.sh
to show you the value you need to create as GitHub secrets.... AZURE_CLIENT_ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx AZURE_SUBSCRIPTION_ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx AZURE_TENANT_ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- In your browser, navigate to your GitHub repository.
- Select Settings > Secrets and variables > Actions.
- Select New repository secret.
- Name the secret AZURE_CLIENT_ID.
- In the Value field, paste the GUID from the first line of the terminal output. Don't include AZURE_CLIENT_ID, the colon, or any spaces in the value.
- Click Add secret.
- Repeat the process to create the secrets for AZURE_TENANT_ID and AZURE_SUBSCRIPTION_ID, copying the values from the corresponding fields in the terminal output.
- Repeat the process to create the secret for VMADMIN_DEFAULT_PASSWORD. The value here would be the default password for your virtual machines.
- Verify that all four secrets AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID and VMADMIN_DEFAULT_PASSWORD shows in your list of secrets now.
- To download the Azure Marketplace VM images, create
bicep/vmimage-create.bicep
. - Save your changes to the file. Your file should look like this example:
@description('The Azure region into which the resources should be deployed.') param region string = resourceGroup().location var imagesList = [ { imageName: 'anoob-bicep-vmimage01' //Replace with your image name osType: 'Windows' //Replace with your image OS type publisherId: 'microsoftwindowsserver' //Replace with your image publisher ID offerId: 'windowsserver' // Replace with your image offer ID planId: '2022-datacenter-azure-edition-core' //Replace with your image plan ID skuVersion: '20348.1129.221104' //Replace with your image SKU version generation: 'V2' //Replace with your image generation customLocation: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/RESOURCE-GROUP-PLACEHOLDER/providers/microsoft.extendedlocation/customlocations/CUSTOMLOCATION-NAME-PLACEHOLDER' //Replace with your custom location ID region: region } { imageName: 'anoob-bicep-vmimage02' //Replace with your image name osType: 'Windows'//Replace with your image OS type publisherId: 'microsoftwindowsserver' //Replace with your image publisher ID offerId: 'windowsserver' // Replace with your image offer ID planId: '2022-datacenter-azure-edition' //Replace with your image plan ID skuVersion: '20348.768.220609' //Replace with your image SKU version generation: 'V2' //Replace with your image generation customLocation: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/RESOURCE-GROUP-PLACEHOLDER/providers/microsoft.extendedlocation/customlocations/CUSTOMLOCATION-NAME-PLACEHOLDER' //Replace with your custom location ID region: region } ] resource vmimages 'microsoft.azurestackhci/marketplacegalleryimages@2021-09-01-preview' = [ for image in imagesList: { name: image.imageName location: image.region extendedLocation: { name: image.customLocation type: 'CustomLocation' } tags: { } properties: { osType: image.osType resourceName: image.imageName hyperVGeneration: image.generation identifier: { publisher: image.publisherId offer: image.offerId sku: image.planId } version: { name: image.skuVersion } } }]
- To create Arc VMs on Azure Stack HCI using Azure Marketplace VM images, create
bicep/vm-create.bicep
. - Save your changes to the file. Your file should look like this example:
@description('The Azure region into which the resources should be deployed.') param region string = resourceGroup().location @description('The virtual machine admin username.') @minLength(5) param adminUsername string = 'anoobbacker' //Replace with your admin user name @description('The virtual machine admin password.') @minLength(9) @secure() param adminPassword string @description('Array of VM configuration objects. This array is looped to create VMs') var vmList = [ { name: 'anoob-bicep-vm01' //Replace with your VM name location: region customLocation: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/RESOURCE-GROUP-PLACEHOLDER/providers/microsoft.extendedlocation/customlocations/CUSTOMLOCATION-NAME-PLACEHOLDER' //Replace with your custom location ID hardwareProfile: {processors: 4, memoryGB: 8 } //Replace with your hardware profile osType: 'Windows' //Replace with your OS type adminUserName: adminUsername adminPasswd: adminPassword image: '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RESOURCE-GROUP-PLACEHOLDER/providers/Microsoft.AzureStackHCI/marketplaceGalleryImages/VMIMAGE-NAME-PLACEHOLDER' //Replace with your VM image } ] resource vms 'Microsoft.AzureStackHCI/virtualmachines@2021-09-01-preview' = [ for vm in vmList: { name: vm.name location: vm.location properties: { resourceName: vm.name hardwareProfile: vm.hardwareProfile osProfile: { adminUsername: vm.adminUserName adminPassword: vm.adminPasswd osType: vm.osType computerName: take(uniqueString(vm.name),15) //Refer https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-computername } storageProfile: { imageReference: { name: vm.image } } } extendedLocation: { type: 'CustomLocation' name: vm.customLocation } }]
- Create
.github/workflows/vmimage-workflow.yml
- Save your changes to the file. Your file should look like this example:
name: deploy-vmimages
on: [workflow_dispatch]
permissions:
id-token: write
contents: read
env:
AZURE_RESOURCEGROUP_NAME: demo-rg #Replace with your resource group name
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: azure/arm-deploy@v1
with:
deploymentName: ${{ github.run_number }}
resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
template: ./bicep/vmimage-create.bicep
- Create
.github/workflows/vm-workflow.yml
- Save your changes to the file. Your file should look like this example:
name: deploy-vms
on: [workflow_dispatch]
permissions:
id-token: write
contents: read
env:
AZURE_RESOURCEGROUP_NAME: demo-rg #Replace with your resource group name
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: azure/arm-deploy@v1
with:
deploymentName: ${{ github.run_number }}
resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
template: ./bicep/vm-create.bicep
parameters: adminPassword=${{ secrets.VMADMIN_DEFAULT_PASSWORD }}
- In the Visual Studio Code terminal, stage your changes, commit them to your repository, and push them to GitHub repo:
git add . git commit -m 'Add Azure Bicep and GitHub Action Workflows' git push
- In your browser, open the workflow by selecting Actions > deploy-vmimages.
- Select Run workflow > Run workflow.
- A new run of your workflow will appear in the runs list. If it doesn't appear, refresh your browser page.
- Select the running workflow to view the details of the run.
- Inspect the rest of your workflow output.
The workflow shows a successful deployment.
- In your browser, open the workflow by selecting Actions > deploy-vms.
- Select Run workflow > Run workflow.
- A new run of your workflow will appear in the runs list. If it doesn't appear, refresh your browser page.
- Select the running workflow to view the details of the run.
- Inspect the rest of your workflow output.
The workflow shows a successful deployment.
- Go to the Azure portal
- Search for the resource group where the bicep template was deployed.
- Click Deployments menu to see the details of the deployment.
- To see which resources were deployed, select the deployment. To expand the deployment and see more details, select Deployment details.
- To see if the VMs and VM images are created, select the Azure Stack HCI cluster and navigate to Virtual machines and VM Images menue
In this case, there's two VM images and a VM created using that VM image.
A collegue asks you to enable creation of the VMs so that they can follow the same steps whenever similar VM creation requests come. You'll update the VM creation workflow to run automatically whenever a the Bicep file changes on your main branch.
- In Visual Studio Code, open the .github/workflows/vm-workflow.yml file.
- At the top of the file, after the line
name: deploy-vms
, remove the manual trigger, which is the line that currently readson: [workflow_dispatch]
- on: [workflow_dispatch]
- Between
name:
andpermissions:
add the following code to prevent multiple simultaneous workflows runs and trigger definition of Bicep file change:
concurrency: create-vms
on:
push:
branches:
- main
paths:
- 'bicep/vm-create.bicep'
- In the Visual Studio Code terminal, commit your changes and push them:
git add . git commit -m 'Enable automatically trigerring Bicep deployment on file change merge in main branch' git push