8. Use Github Actions to Deploy your App
Introduction
In this tutorial, we will automate the deployment process of an application, to an Azure Linux VM, using Github Actions.
The integration of Github Actions into the deployment workflow offers a streamlined and efficient approach to automate the build and deployment processes. This guide will introduce you to the foundational concepts and step-by-step instructions required to set up a Continuous Integration and Continuous Deployment (CI/CD) pipeline using Github Actions.
We’ll start by preparing a Github repository and adding a workflow, followed by implementing a sample ASP.NET web application. The tutorial will guide you through developing a CI/CD pipeline as a Github workflow, utilizing a Github-hosted runner for the CI (build) part, and a self-hosted Github runner for the CD (deploy) part. This process ensures that every push to the repository triggers the automated deployment of your application.
This tutorial is designed for developers with a basic understanding of web development, git, and cloud services.
Method
- Setup Github Repository: Initialize a Github repository and configure a workflow for automation.
- Create ASP.NET Web Application: Develop a simple ASP.NET web application to serve as the deployment target.
- Build CI/CD Pipeline: Design a continuous integration and continuous deployment (CI/CD) pipeline using Github Actions.
- Continuous Integration: Utilize Github-hosted runners to build and test your application upon each push or pull request.
- Continuous Deployment: Set up a virtual machine (VM) with a self-hosted Github runner to automate the deployment process.
- Automated Deployment Trigger: Ensure the entire deployment process is automated and triggered by any push to the designated repository branch.
Prerequisites
- An Azure account. If you don’t have one, sign up at Azure’s official site.
- Basic familiarity with Azure services and ASP.NET web development.
- A Github account
- Basic familiarity with git and Github
- VSCode connected to Github
Step 1: Create a Github Repository with an ASP.NET Web Application
Creating a git repository marks both the end of a development phase and the beginning of the CI/CD pipeline. Let’s first setup a git repo and “develop” a webapp, which we check-in to the repo.
Create Project Directory: Create a new directory named
GithubActionsDemo
to house your project.Generate ASP.NET Web Application: Within VSCode, navigate to your newly created directory and execute the following commands to create a new ASP.NET web application and a
.gitignore
file tailored for .NET projects:dotnet new webapp dotnet new gitignore
Initialize Git Repository: Enable version control by initializing a git repository, adding your project files to it, and committing them with an initial message:
git init git add . git commit -m "Initial Commit"
Push to Github: Use VSCode’s integrated git functionality to connect your local repository to Github and push your initial commit. Follow the prompts in VSCode to authenticate and specify your repository details on Github.
This step will set up your project for development and prepare it for an automated CI/CD pipeline, making it ready for continuous integration and deployment with Github Actions.
Step 2: Automate Continuous Integration with a Github-Hosted Runner
With our web application now stored in the repository, the next step is to automate the Continuous Integration (CI) part of our CI/CD pipeline. This involves building and publishing the web application to an artifact repository. For this tutorial, we’ll utilize Github’s own artifact storage.
Setting Up the CI Workflow
Access Your Github Repository: Log in to Github, navigate to your
GithubActionsDemo
repository, and switch to the Actions tab.Initialize the Workflow: Use the search bar within the Actions tab to find a predefined .NET workflow, then click Configure to use it as a starting point for your CI process.
Configure the Workflow File: You’ll be prompted to edit the workflow file. Here’s a template for a basic CI workflow designed for an ASP.NET application:
cicd.yaml
# This workflow will build the GithubActionsDemo project name: GithubActionsDemo on: push: branches: - "main" workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - name: Install .NET SDK uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - name: Check out this repo uses: actions/checkout@v4 - name: Restore dependencies (install Nuget packages) run: dotnet restore - name: Build and publish the app run: | dotnet build --no-restore dotnet publish -c Release -o ./publish - name: Upload app artifacts to Github uses: actions/upload-artifact@v4 with: name: app-artifacts path: ./publish
Name the file
cicd.yaml
and commit the change into the repo by pressing the button Commit changes…. Click Commit changes again in the popup window. This will initiate the CI workflow.
Verify the Workflow’s Success
- Check Workflow Execution: After committing your workflow file, go to the Actions tab again to observe the running workflow.
- Verify Artifact Upload: Navigate to the Summary page of your workflow run. Under the Artifacts section, you should see your application artifacts listed. Download and inspect them to ensure they are as expected.
- Green Checkmark: A successful build will be indicated by a green checkmark.
Important Reminder
- Sync Your Local Repository: Ensure to pull the latest changes from your Github repository into your local VSCode workspace to avoid any synchronization issues as you continue to develop your application.
This setup creates the foundation for continuous integration, automatically handling the build and artifact storage steps every time you push changes to your main branch.
Step 3: Provision a VM with a self-hosted runner
Transitioning your app to a live environment requires deploying it to an Azure Linux VM, installing necessary runtimes, and configuring the VM to handle deployments. This process includes setting up a self-hosted runner on the VM to interact with Github Actions, enabling automated deployment directly from your repository.
Provision the Linux VM
To provision and configure your Azure Linux VM, follow these steps:
Prepare Script Files: Create two files:
provision_vm.sh
for provisioning the VM andcloud-init_dotnet.yaml
for initializing it with necessary configurations.provision_vm.sh
#!/bin/bash resource_group=GithubActionsDemoRG vm_name=GithubActionsDemoVM vm_port=5000 az group create --location northeurope --name $resource_group az vm create --name $vm_name --resource-group $resource_group \ --image Ubuntu2204 --size Standard_B1s \ --generate-ssh-keys --admin-username azureuser \ --custom-data @cloud-init_dotnet.yaml az vm open-port --port $vm_port --resource-group $resource_group --name $vm_name
cloud-init_dotnet.yaml
#cloud-config # Install .Net Runtime 8.0 runcmd: # Register Microsoft repository (which includes .Net Runtime 8.0 package) - wget -q https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb - dpkg -i packages-microsoft-prod.deb # Install .Net Runtime 8.0 - apt-get update - apt-get install -y aspnetcore-runtime-8.0 # Create a service for the application write_files: - path: /etc/systemd/system/GithubActionsDemo.service content: | [Unit] Description=ASP.NET Web App running on Ubuntu [Service] WorkingDirectory=/opt/GithubActionsDemo ExecStart=/usr/bin/dotnet /opt/GithubActionsDemo/GithubActionsDemo.dll Restart=always RestartSec=10 KillSignal=SIGINT SyslogIdentifier=GithubActionsDemo User=www-data Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false Environment="ASPNETCORE_URLS=http://*:5000" [Install] WantedBy=multi-user.target owner: root:root permissions: '0644' systemd: units: - name: GithubActionsDemo.service enabled: true
Execute Provisioning Script: Change the script’s permission with
chmod +x provision_vm.sh
and run it to set up your VM.chmod +x provision_vm.sh ./provision_vm.sh
Verify the provisioning
Go into the Azure portal and verify that a VM has been provisioned.
Login to the VM
ssh azureuser@<public_ip>
Output
azureuser@GithubActionsDemoVM:~$
Configure the Deployment Workflow
Update the Workflow: Integrate a deployment job that downloads build artifacts and deploys them to the VM. Use the self-hosted runner for deployment tasks. Use the code snippet below.
cicd.yaml
... deploy: runs-on: self-hosted needs: build steps: - name: Download the artifacts from Github (from the build job) uses: actions/download-artifact@v4 with: name: app-artifacts - name: Stop the application service run: | sudo systemctl stop GithubActionsDemo.service - name: Deploy the the application run: | sudo rm -Rf /opt/GithubActionsDemo || true sudo cp -r /home/azureuser/actions-runner/_work/GithubActionsDemo/GithubActionsDemo/ /opt/GithubActionsDemo - name: Start the application service run: | sudo systemctl start GithubActionsDemo.service
Don’t push the new workflow just yet. First we should install the runner.
Setting Up a Self-Hosted Runner on the VM
Configure Runner on GitHub: Navigate to your repository’s settings, find the Actions tab, and set up a new self-hosted runner following GitHub’s instructions:
- select the Settings tab
- Select Actions -> Runners in the side menu
- Click New self-hosted runner
- Select Linux (Architecture: x64)
Install Runner on VM: SSH into your VM, execute the provided script to install and start the GitHub runner.
- Run the code from Github
- Press
<Enter>
to accept all default values in the configuration wizard
# The code from Github ... ./run.sh
- Run the code from Github
- Press
Verify the runner installation process
If the installation process went well you should see the following output in the terminal
Output
azureuser@GithubActionsDemoVM:~/actions-runner$ ./run.sh
√ Connected to GitHub
Current runner version: '2.314.1'
2024-03-11 13:39:55Z: Listening for Jobs
In the Github portal, you should also see the runner as Idle.
Verify that the deployment went well
Now it’s time to push your new Github workflow (the cicd.yaml
file) and see how the runner picks up the job and carries it out. Best PracticeAfter pushing the new code to Github you should see how the runner picks up the job.
azureuser@GithubActionsDemoVM:~/actions-runner$ ./run.sh
√ Connected to GitHub
Current runner version: '2.314.1'
2024-03-11 13:39:55Z: Listening for Jobs
2024-03-11 13:52:45Z: Running job: deploy
2024-03-11 13:52:57Z: Job deploy completed with result: Succeeded
Open up a browser and navigate to
http://<public_ip>:5000
You should now see your app running on the VM.
Best Practice: Run the runner as a service instead
In a real scenario you should run the runner as a service in the background. You can do this by running the following commands:
# Run the Github runner as a service sudo ./svc.sh install azureuser sudo ./svc.sh start
You can follow the logs with
journalctl
(use autocomplete with<tab>
to find your service)sudo journalctl -u actions.runner.<user>-GithubActionsDemo.GithubActionsDemoVM.service -f
Step 4: Use the new CI/CD Pipeline for Continuous Deployment
Putting your newly established CI/CD pipeline into action. Here’s how it works:
Implement Changes: Start by opening your project in Visual Studio Code (VSCode). Make any desired modifications to your codebase.
Commit and Push: Once you’re satisfied with the changes, commit them to your local repository and push the updates to your GitHub repository.
Observe Deployment: Navigate to your application’s URL in a web browser. The deployment might take a moment, so refresh the page after a minute or two to see your changes go live.
By following these steps, you go through the full cycle of your CI/CD pipeline, automating the build and deployment processes, and significantly streamlining your workflow.
Conclusion
In this tutorial, we’ve set up and used a CI/CD pipeline with GitHub Actions for deploying an ASP.NET web application to an Azure VM. This pipeline enhances your productivity and ensures that your application is always up to date with the latest changes in your codebase.
This automated deployment strategy offers several benefits, including reduced manual errors, faster release cycles, and a more robust and reliable deployment process. It enables you to focus more on development and less on the deployment process.
Don’t Forget
Azure services incur costs. Delete resources you no longer need.