Exercise - Publish a module to a registry
In your toy company, you've been publishing your Bicep modules into a registry. You've been running the publishing process manually from your own computer. Now, you want to create a workflow to handle the publishing process.
In this exercise, you'll:
- Create a container registry for your Bicep modules.
- Add a lint job to the workflow.
- Add a workflow job to publish the module to your registry.
- Verify that your workflow runs successfully.
- Check the published module in your registry.
Create a container registry
Before you can publish modules, you need to create a registry for your organization to use. Here, you use the Azure portal to create a registry.
In your browser, create a new container registry within the Azure portal.
On the Basics tab, select your target subscription and the ToyReusable resource group that you created earlier.
Enter a name for your registry and a location that's close to you.
Important
The registry name must be unique within Azure and contain 5-50 alphanumeric characters. A check mark next to the registry name indicates that the name you chose is available.
For Pricing plan, select Basic.
Leave the default values for the other configuration settings.
Select Review + create.
When the Validation passed message appears, select Create.
Wait for the deployment to finish, which usually takes 1-2 minutes.
When the Deployment succeeded message appears, select Go to resource to open the container registry.
In the container registry's Overview area, note the value of the Login server setting. The name resembles
yourregistryname.azurecr.io
.You'll need this value shortly.
Add a module metadata file
In the preceding unit, you learned about the importance of having a versioning strategy for your modules. You also learned how to use module metadata files to specify the major and minor version number of your module within a workflow. Here, you add a metadata file for your storage account module.
In Visual Studio Code, expand the modules/storage-account folder in the root of your repository.
Create a new file named metadata.json.
Add the following content to the file:
{ "version": { "major": 1, "minor": 2 } }
In the metadata file, you separately define the major and minor version numbers. Whenever your workflow runs, the workflow combines these numbers together with the workflow's run number to form a complete version number.
Save your changes to the file.
Update your workflow definition and add a lint job
Your repository contains a draft of a workflow that you can use as a starting point.
In Visual Studio Code, expand the .github/workflows folder in the root of the repository.
Open the module-storage-account.yml file.
Update the value of the
MODULE_REGISTRY_SERVER
environment variable to your container registry's server name. You copied that name earlier in this exercise.For example, if your registry's login server is yourregistryname.azurecr.io, your code is like this example:
env: MODULE_NAME: storage-account MODULE_REGISTRY_SERVER: yourregistryname.azurecr.io MODULE_FILE_PATH: modules/storage-account/main.bicep MODULE_METADATA_FILE_PATH: modules/storage-account/metadata.json
At the bottom of the file, for the
# To be added
comment, add the following lint job definition:jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run Bicep linter run: az bicep build --file ${{ env.MODULE_FILE_PATH }}
Add a publish job to your workflow
Now, you can add a second job to publish the module to your container registry.
At the bottom of the module-storage-account.yml file, add the first part of the publish job's definition.
publish: runs-on: ubuntu-latest needs: [ lint ] steps: - uses: actions/checkout@v3 - uses: azure/login@v1 name: Sign in to Azure with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
The initial two steps in this definition are to check out the code from your repository and sign in to Azure.
Below the code that you just added, add another step that reads the version number from your module's metadata.json file and sets it as an environment variable.
- name: Get module version number run: | majorMinorVersionNumber=$(jq '(.version.major | tostring) + "." + (.version.minor | tostring)' ${{ env.MODULE_METADATA_FILE_PATH }} -r ) versionNumber="$majorMinorVersionNumber.${{ github.run_number }}" echo "MODULE_VERSION=$versionNumber" >> $GITHUB_ENV
The step runs a script that uses the
jq
command-line application to parse the JSON file.After the step that you created, add a final step to publish the module to the registry.
- uses: azure/cli@v1 name: Publish module with: inlineScript: | az bicep publish \ --target 'br:${{ env.MODULE_REGISTRY_SERVER }}/${{ env.MODULE_NAME }}:${{ env.MODULE_VERSION }}' \ --file ${{ env.MODULE_FILE_PATH }}
This step constructs the value of the
--target
argument dynamically. It combines the value of the registry server, the module name, and the version number.Save your changes to the file.
Verify and commit your workflow definition
Verify that your module-storage-account.yml file looks like the following example:
name: module-storage-account concurrency: module-storage-account on: workflow_dispatch: push: branches: - main paths: - 'modules/storage-account/**' permissions: id-token: write contents: read env: MODULE_NAME: storage-account MODULE_REGISTRY_SERVER: yourregistryname.azurecr.io MODULE_FILE_PATH: modules/storage-account/main.bicep MODULE_METADATA_FILE_PATH: modules/storage-account/metadata.json jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run Bicep linter run: az bicep build --file ${{ env.MODULE_FILE_PATH }} publish: runs-on: ubuntu-latest needs: [ lint ] steps: - uses: actions/checkout@v3 - uses: azure/login@v1 name: Sign in to Azure with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Get module version number run: | majorMinorVersionNumber=$(jq '(.version.major | tostring) + "." + (.version.minor | tostring)' ${{ env.MODULE_METADATA_FILE_PATH }} -r ) versionNumber="$majorMinorVersionNumber.${{ github.run_number }}" echo "MODULE_VERSION=$versionNumber" >> $GITHUB_ENV - uses: azure/cli@v1 name: Publish module with: inlineScript: | az bicep publish \ --target 'br:${{ env.MODULE_REGISTRY_SERVER }}/${{ env.MODULE_NAME }}:${{ env.MODULE_VERSION }}' \ --file ${{ env.MODULE_FILE_PATH }}
If the file contents are different, update it to match this example, and then save the file.
Commit and push your changes to your Git repository by running the following commands in the Visual Studio Code terminal:
git add . git commit -m "Add lint and publish jobs to storage account module workflow" git push
Trigger the workflow
In your browser, go to your GitHub repository and select the Actions tab.
Select the module-storage-account workflow.
Notice that a workflow run is already in progress. The push trigger fired because you modified the metadata.json file within the module's folder.
Select the latest run in the list.
Wait for the workflow run to finish. The Bicep module is published to your container registry.
Note the workflow's run number, which is probably 3.
Review the module in the registry
You can also view the published module in the Azure portal.
In your browser, go to the Azure portal.
Go to the ToyReusable resource group.
In Resources, select the container registry that you created previously.
Select Services > Repositories from the menu. Then, select the modules\storage-account repository, which represents the module that your workflow published.
Notice that there's a single tag, which matches the version number of the module that your workflow published. The major version (1) and minor version (2) match the version numbers that you defined in the metadata.json file. The revision number (3) matches the workflow's run number.
Clean up the resources
Now that you've completed the exercise, you can remove the resources so you aren't billed for them.
In the Visual Studio Code terminal, run the following command:
az group delete --resource-group ToyReusable --yes --no-wait
The resource group is deleted in the background.
Remove-AzResourceGroup -Name ToyReusable -Force
You can also remove the GitHub secrets and repository, and the Azure workload identities.
GitHub secrets
- From the GitHub repository, go to Settings > Secrets and variables > Actions.
- For each saved GitHub secret, select the Delete <secret-name> icon and follow the prompts.
GitHub repository
- Go to Settings > General.
- Select Delete this repository and follow the prompts.
Azure App registration's federated credentials and service principal.
- From the portal home page, search for Microsoft Entra ID and select it from the list of Services.
- Go to Manage > App registrations.
- In the Owned applications tab, select toy-reusable.
- Select Delete and follow the prompts.
- Select the Deleted applications tab.
- Select toy-reusable, select Delete permanently, and then select Yes to permanently delete the app registration.
Important
It's possible to have duplicate app registration and service principal names. We recommend that you verify the application ID to make sure you're deleting the correct resource.