The following walkthrough will help you set up a demo to showcase:
- Integration between Microsoft Teams and GitHub
- CI/CD with GitHub Actions
- Environment protection with GitHub Environments
- Azure Web App for Containers
- Azure Bicep for resource deployment
Read more about it on my blog
You will need:
- An Azure subscription (free trial is fine)
- A GitHub account
- Command line with az cli installed, or use Azure Cloud Shell
- Microsoft Teams
- Make sure you are logged into GitHub, then navigate to https://github.com/CharleneMcKeown/Tailwind and fork the repo. This will create a copy of the repo in your GitHub account.
- Clone the newly created repo from your account (optional - we will be making small code changes that can be done in the browser)
Create two new connectors for your target Microsoft Teams channel.
- Incoming Webhook - see here for instructions. Make sure you save the webhook uri to your text editor.
- GitHub Connector - see here for instructions.
In order to deploy and access Azure resources, we need an identity that has the right permissions.
-
In your terminal or Cloud Shell, run the following command, replacing with your Azure subscription ID.
az ad sp create for rbac -n tailwindsp --role contributor --scopes /subscriptions/<subId> --sdk-auth
-
Copy and paste the output into a text editor. Note the AppId - you will need it in the next step.
-
Return to your terminal or Cloud Shell, and run the following command to get the object id of your newly created service principal. Copy it and paste it into your text editor for the next step.
az ad sp show --id <putYourAppIdHere>
We now need to do some configuration in GitHub.
- In the repo, navigate to Settings > Secrets.
- Add a new secret called AZURE_CREDENTIALS, and paste in the JSON object you modified earlier in your text editor. Save it.
- Add another secret called TEAMS_WEBHOOK, and paste in the webhook you saved earlier. Save it.
-
In your repo, navigate to Settings > Environments.
-
Create a new environment called Staging.
-
Create another new environment called Production. Make sure you add an approver (it can be yourself).
-
Lastly, you will most likely have to enable actions because this is a forked repo. Navigate to the Actions tab and do that:
-
In your repo, navigate to Deploy/main.bicep and click edit.
-
On line 14, add in your objectId that you saved earlier on and create a new PR at the bottom instead of commiting to main:
-
This should trigger the GitHub workflow 'build.yml' to build the application. Check it out on the Actions tab.
-
Once it is green, go ahead and merge the pull request.
-
This will trigger another pipeline to build the application and deploy it!
So what's happening?
Azure Bicep is used to declare what our resources should look like, including dependencies and configuration. Bicep is deploying the main.bicep file, which defines the following resources:
The application is a sample front end web store - Tailwind Traders. We are utilising a pre-created backend that is managed by Microsoft, and the app itself will be hosted on a Web App for Containers (Linux) app service plan.
The web app has two deployment slots - one for staging, where we can deploy and observe the change, and one for production. When we're happy with the change, we can initiate a swap slot, which is seamless to users of the website.
We need to package the application and build it into a container image using Docker - so we need somewhere to host it - Azure Container Registry! As we will be pushing to the registry the newly created container image, we obviously need somewhere to securely store the password to the registry once it has been created.
Azure Key Vault is the place where we will put the secret - we can securely access it later during deployments.
Okay, after reading all that - your app has probably deployed! Navigate to the Actions tab in your repo. You should see a deployment either in progress or finished. Click on it.
You should see something like this if it's still in progress:
Feel free to click it and have a look at the logs. When it is green, you should have an approval waiting:
Here you can see that the Staging environment actually has a URL - click on that, and you should see the Tailwind Traders website has been deployed. Go ahead and approve Production by clicking on Review Deployments.
Meanwhile, over in Microsoft Teams, you might have noticed some notifcations:
The incoming webhook you created earlier is getting used by a marketplace GitHub Action in the pipeline:
- name: Microsoft Teams Deploy Card
uses: toko-bifrost/[email protected]
if: always()
with:
webhook-uri: ${{ secrets.TEAMS_WEBHOOK }}
github-token: ${{ secrets.GH_TOKEN }}
environment: production
card-layout-start: complete
card-layout-exit: cozy
show-on-exit: true
view-status-action-text: View prod deployment status
custom-actions: |
- text: View Production Website
url: "http://${{ needs.deployInfra.outputs.web }}.azurewebsites.net"
It uses the card feature in teams, and passes some useful information for us, like:
- environment
- status
- website url to check
So it is easy to see the status of a deployment without having to go directly to GitHub.
Lastly, the point of this exercise to make sure that deployments are done safely. To ensure that no changes make it out to production, we need to set up some branch policies to protect main.
That is really all you need. To demo this:
- Create a new branch off main
- Edit: /Source/Tailwind.Traders.Web/ClientApp/src/assets/locales/translation.json to a add a new free shipping price on line 5.
- Open a Pull Request into main
- Observe your Actions tab - you will see that the build.yml pipeline is building and testing the application.
- Once it passes, complete the merge.
- Observe the deployment pipeline and Teams notifications as it moves through the environments.
A few notes..
This is demo code and not recommended for actual production scenarios. One reason is that we're running the Bicep deployment every time we push changes to the website. This is dangerous! We're doing it here to make it easy for you to create the Azure resources with as few steps as possible, and to show you how easy it is to grab outputs from one step, and pass them to steps in downstream jobs - as well as showing off the nifty capabilities of environments and urls.
If this was real life, the website would likely face downtime during the Bicep deployment. The nice thing about using deployment slot swaps to perform the change means that users won't be impacted at all - the site will remain available throughout.
Another reason - you will notice that every time we push a new version of our application to the container registry, we give it the tag:latest. This is not best practice. Ideally you would link the image to the build, and use something like ${{ github.sha }} instead. Unfortunately, as we are running the Bicep step every time we deploy, this won't work.
Side Note: Bicep doesn't yet have the ability to ignore changes to certain fields like Terraform does with lifecycle_ignore.
Hope you found this useful!