Greetings, in this post, we will be delving into the process of setting up a CI CD pipeline via GitHub workflow actions for a .NET Web API application running on an Azure Virtual Machine remotely using IIS. Some reasons you may want to host a web API on a VM rather than Azure’s default web API option include having full control over the environment, advanced networking and enhanced security controls.
This post will outline the following;
Deployment of the virtual machine and its necessary dependencies will be executed via a windows power shell script to facilitate automation.
Let’s get started!
If you would like to follow this tutorial, you will need to install the Microsoft Azure CLI and login in to your Azure account sign the az login command:
az login
Before we begin, we will generate an SSH key pair on a local machine, this key pair will be used in order to securely transfer files during any CI CD processes when changes are made to the .NET web API code. In order to generate this key pair, use the following command:
ssh-keygen -t rsa -b 2048
After entering this command, you will be prompted to save the key pair to a file. For now, this can be left empty by simply pressing enter. This will save the key pair to the default location which is the .ssh directory. As well as this, you will be requested to enter a password, this can also be left empty.
After the key pair has been generated, we can now create a Windows powershell script that will deploy a virtual machine within Microsoft Azure. Let’s start writing the script.
Create a new Windows powers script with the file extension .ps1 and each of the following code snippets to the script:
New-AzResourceGroup -Name 'RgAzVMWebAPI' -Location 'ukwest'
The above line creates a new Azure Resource Group named 'RgAzVMWebAPI' in the 'UK West' Azure region. Resource groups in Azure are containers that hold related resources for an Azure solution—in this case, the VM and associated resources.
powershell
$securePassword = ConvertTo-SecureString "Password!234" -AsPlainText -Force
Here, we're converting a plain text password into a secure string. This secure string is encrypted, making it safer to use in scripts and processes. The "-Force" parameter is used to bypass the confirmation prompt that would typically appear for this kind of operation.Obviously in an production environment, use a much stronger password!
powershell
$credential = New-Object System.Management.Automation.PSCredential ("azureuser", $securePassword)
Using the secure password, a "PSCredential" object is created with the username 'azureuser'. This credential object is used to authenticate with Azure services securely.
$result1 = New-AzVm
-ResourceGroupName 'RgAzVMWebAPI'
-Name 'AzVMWebAPI'
-Location 'ukwest'
-Image 'MicrosoftWindowsServer:WindowsServer:2022-datacenter-azure-edition:latest'
-Size 'Standard_B2s'
-VirtualNetworkName 'AzVMWebAPIVNet'
-SubnetName 'AzVMWebAPISubnet'
-SecurityGroupName 'AzVMWebAPINSG'
-PublicIpAddressName 'AzVMWebAPIPublicIP'
-OpenPorts 80,3389,22
This multi-line command ("New-AzVm") initiates the creation of a new VM. It specifies various parameters like the resource group name, VM name, location, and the image to use (Windows Server 2022 Datacenter Azure Edition). It also defines the VM size ("Standard_B2s"), networking details (like VNet and subnet names), and security settings, including a network security group and public IP address. The "-OpenPorts" parameter is used to ensure that the VM can receive traffic on specific ports: 80 (HTTP), 3389 (RDP for remote desktop access), and 22 (SSH).
The backtick at the end of each line is the line continuation character in PowerShell, allowing the command to span multiple lines for better readability.
The result of the VM creation command is stored in the variable "$result1", which can be used for further processing or validation checks in subsequent script sections.
The next part of the script will consist of various commands that will install SSH onto the VM along with specifying the file location of the public key of the Ssh key we earlier generated on our local machine. This public key will be used later when verifying known SSH hosts on our remote VM. Please note, in an productuion environment, it is better practice to use port 443 over 80 for a secure connection. Port 80 is used in this article for demonstration purposes.
After the VM is provisioned, the next step is to configure Secure Shell (SSH) access. SSH is a protocol that provides a secure channel over an unsecured network in a client-server architecture, allowing for secure login from one computer to another.
$publicKeyPath = 'C:\Users\kieroncairns\.ssh\id_rsa.pub'
$publicKey = Get-Content $publicKeyPath -Raw | Out-String | ForEach-Object { $_.TrimEnd() }
The script first defines the path to the public SSH key file. It then reads the content of this file and stores it in the "$publicKey" variable. This public key will be used for SSH authentication, enabling secure passwordless access to the VM.
$installSsh = "@
Add-WindowsCapability -Online -Name OpenSSH.Server
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
"@
Here, a multi-line string (a here-string in PowerShell terminology) is assigned to the $installSsh variable. This string contains commands to install the OpenSSH Server feature on the Windows VM, start the SSH service ("sshd"), and set it to start automatically with the system boot.
try {
Write-Output "Installing Open SSH on VM"
Invoke-AzVMRunCommand -ResourceGroupName 'RgAzVMWebAPI' -VMName 'AzVMWebAPI' -CommandId 'RunPowerShellScript' -ScriptString $installSsh
Write-Output "Open SSH Installation Successful"
}
catch {
Write-Output "Error Installing Open SSH"
}
The script then tries to execute the OpenSSH installation commands on the VM using the "Invoke-AzVMRunCommand" cmdlet. This cmdlet allows you to run PowerShell scripts directly on Azure VMs. If the installation succeeds, it prints a success message. If any error occurs during this process, the catch block captures the error and prints an error message.
The use of "try-catch" blocks in PowerShell is an effective way to handle exceptions and errors in scripts. It ensures that the script can gracefully handle any issues that might occur during execution and provides clear output about the success or failure of the operation.
After the VM is provisioned, the next step is to configure Secure Shell (SSH) access. SSH is a protocol that provides a secure channel over an unsecured network in a client-server architecture, allowing for secure login from one computer to another.
$publicKeyPath = 'C:\Users\kieroncairns\.ssh\id_rsa.pub'
$publicKey = Get-Content $publicKeyPath -Raw | Out-String | ForEach-Object { $_.TrimEnd() }
The script first defines the path to the public SSH key file. It then reads the content of this file and stores it in the "$publicKey" variable. This public key will be used for SSH authentication, enabling secure passwordless access to the VM.
$installSsh = "@
Add-WindowsCapability -Online -Name OpenSSH.Server
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
"@
Here, a multi-line string (a here-string in PowerShell terminology) is assigned to the "$installSsh" variable. This string contains commands to install the OpenSSH Server feature on the Windows VM, start the SSH service ("sshd"), and set it to start automatically with the system boot.
try {
Write-Output "Installing Open SSH on VM"
Invoke-AzVMRunCommand -ResourceGroupName 'RgAzVMWebAPI' -VMName 'AzVMWebAPI' -CommandId 'RunPowerShellScript' -ScriptString $installSsh
Write-Output "Open SSH Installation Successful"
}
catch {
Write-Output "Error Installing Open SSH"
}
The script then tries to execute the OpenSSH installation commands on the VM using the "Invoke-AzVMRunCommand" cmdlet. This cmdlet allows you to run PowerShell scripts directly on Azure VMs. If the installation succeeds, it prints a success message. If any error occurs during this process, the catch block captures the error and prints an error message.
The use of "try-catch" blocks in PowerShell is an effective way to handle exceptions and errors in scripts. It ensures that the script can gracefully handle any issues that might occur during execution and provides clear output about the success or failure of the operation.
The next part of the script will log in the admin user of the VM via SSH in order to create the user account upon the VM’s first use. As well as this, the public key that was generated earlier will be added to an authorized_keys SSH file that is present within the admin accounts user directory. This step will allow for key-based authentication via SSH that will be executed in the next segment of the script after this:
$publicIp = Get-AzPublicIpAddress -ResourceGroupName 'RgAzVMWebAPI' -Name 'AzVMWebAPIPublicIP'
$ipAddress = $publicIp.IpAddress
The script uses the "Get-AzPublicIpAddress" cmdlet to fetch the public IP address assigned to the VM. This IP address is crucial for making remote connections.
if (-not $ipAddress) {
throw "Failed to retrieve IP Address."
}
It checks if the IP address was successfully retrieved. If not, it throws an exception, effectively stopping the script and indicating a problem in the process.
Write-Output "VM Public IP Address: $ipAddress"
If the IP address is successfully retrieved, it is displayed to the user.
$sshCommands = "@
echo 'Creating user profile on VM and adding public key to authorized_keys file...'
mkdir C:\Users\azureuser\.ssh
echo $publicKey > C:\Users\azureuser\.ssh\authorized_keys
exit
"@
The script prepares a string of SSH commands to create a ".ssh" directory in the Azure user's home directory and add the previously retrieved public key to the "authorized_keys" file. This setup allows for secure key-based authentication.
$sshCommand = "ssh -o StrictHostKeyChecking=no azureuser@$ipAddress"
$fullCommand = "echo `"$sshCommands`" | $sshCommand"
Invoke-Expression $fullCommand
The script then constructs an SSH command to connect to the VM and pipes the SSH commands to be executed upon login. The use of "StrictHostKeyChecking=no" bypasses the host key verification; this is not recommended for production environments as it could make the connection vulnerable to man-in-the-middle attacks.
} catch {
Write-Error "An error occurred: $_"
}
The script is enclosed in a try-catch block to handle any potential errors during the SSH setup. If an error occurs, it is captured and printed out, and the script can perform any necessary cleanup.
This part of the script is essential for ensuring that the VM can be securely managed via SSH without the need for password authentication, which is an important aspect of automating VM management. The script not only automates the deployment of the VM but also its initial configuration, reducing the manual steps required to get a VM up and running which will be a key aspect in the GitHub actions workflow CI CD yaml file.
$filePath = "C:\ProgramData\ssh\sshd_config"
The script sets the path to the SSH server configuration file, "sshd_config", which contains settings that dictate how the SSH server behaves.
$disablePwdAuthentication = "@
(Get-Content $filePath) -replace '#PasswordAuthentication yes', 'PasswordAuthentication no' | Set-Content $filePath
Restart-Service sshd
"@
This block of code is designed to enhance security by disabling password authentication for SSH, forcing all users to connect using SSH keys instead. It does this by modifying the SSH configuration file to set "PasswordAuthentication" to "no", and then it restarts the SSH service to apply the changes.
$enablePubKeyAuthentication = "@
(Get-Content $filePath) -replace '#PubkeyAuthentication yes', 'PubkeyAuthentication yes' | Set-Content $filePath
Restart-Service sshd
"@
This code ensures that public key authentication is enabled, allowing users to authenticate using their SSH keys. It modifies the corresponding setting in the configuration file and restarts the SSH service.
$disableMatchGroupAdmins = "@
(Get-Content $filePath) -replace 'Match Group administrators', '#Match Group administrators' | Set-Content $filePath
Restart-Service sshd
"@
In this step, the script comments out any specific settings that apply only to users in the "administrators" group. This is a way of ensuring that SSH configurations apply uniformly to all users.
$disableAdminAuthorizedKeysFile = "@
(Get-Content $filePath) -replace 'AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys', '#AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys' | Set-Content $filePath
Restart-Service sshd
"@
This section of the script comments out the line that specifies a separate "authorized_keys" file for administrator users, ensuring that the same "authorized_keys" file is used for all users.
Each block of configuration changes is executed on the VM using the "Invoke-AzVMRunCommand" cmdlet. This cmdlet allows the script to run PowerShell commands on the remote VM. After each command block is run, there is an output to the user indicating the action that has been taken (e.g., "Disabled password authentication in sshd_config").
} catch {
Write-Output "Error Creating SSH Directory: $_"
}
The "try-catch" block encapsulates the commands to handle any errors that occur during the execution of the configuration changes. If an error occurs, it is caught, and a message is displayed to the user.
This segment is critical for securing the SSH server by implementing key-based authentication and disabling less secure password authentication. The script streamlines the process of hardening the SSH configuration, which is an important aspect of deploying a secure and production-ready VM in the cloud.
With the Azure VM now set up and secured, the next step in our deployment process is to install the necessary software for the .NET web API to run. In this case, we're focusing on installing the .NET 8 runtime, which is essential for running the web API project.
Write-Output "Starting .NET 8 Runtime Installation"
This line simply outputs a message to the console indicating that the .NET 8 runtime installation is about to start.
$dotnetRuntimeInstallerUrl = "https://download.visualstudio.microsoft.com/download/pr/ab5e947d-3bfc-4948-94a1-847576d949d4/bb11039b70476a33d2023df6f8201ae2/dotnet-sdk-8.0.201-win-x64.exe"
Here we define the URL where the .NET 8 runtime installer can be downloaded. This URL points to the official Microsoft server hosting the installer package.
{$installerPath = "C:\dotnet-sdk-8.0.201-win-x64.exe"
The script sets a local path on the VM where the .NET 8 runtime installer will be downloaded to.
$installDotNetRuntime = "@
Invoke-WebRequest -Uri $dotnetRuntimeInstallerUrl -OutFile $installerPath
Start-Process -FilePath $installerPath -ArgumentList '/quiet', '/norestart' -Wait
Remove-Item -Path $installerPath -Force
"@
This block of code is a multi-line PowerShell command that handles three tasks: downloading the installer, executing it with silent and no-restart arguments, and cleaning up by deleting the installer file.
Invoke-AzVMRunCommand -ResourceGroupName 'RgAzVMWebAPI' -VMName 'AzVMWebAPI' -CommandId 'RunPowerShellScript' -ScriptString $installDotNetRuntime
This line runs the installation commands on the remote VM using the "Invoke-AzVMRunCommand" cmdlet, which allows us to execute PowerShell scripts on Azure VMs.
Write-Output ".NET 8 Runtime Installation Successful"
Once the installation commands have been successfully executed, the script outputs a confirmation message.
catch
{
Write-Output "Error Installing .NET 8 Runtime: $_"
}
The "try-catch" block is used here to handle any exceptions that might occur during the installation process. If an error occurs, it is captured and an error message is displayed.
This segment ensures that the server environment is prepared with the necessary runtime for the .NET web API application. By scripting this installation, we automate what would otherwise be a manual and potentially error-prone process, resulting in a more efficient and reliable setup.
The script's last task is to install the .NET 8 Hosting Bundle, which is a set of components needed to host .NET applications on Windows servers, particularly in IIS (Internet Information Services). This is a critical step if the VM will serve as a web server for .NET web applications.
Write-Output "Starting .NET 8 Hosting Bundle Installation"
A message is displayed to indicate that the installation process for the .NET 8 Hosting Bundle is beginning.
$dotnetHostingBundleInstallerUrl = "https://download.visualstudio.microsoft.com/download/pr/98ff0a08-a283-428f-8e54-19841d97154c/8c7d5f9600eadf264f04c82c813b7aab/dotnet-hosting-8.0.2-win.exe"
The URL from which the .NET 8 Hosting Bundle installer can be downloaded is specified. This URL is typically obtained from the official Microsoft download page.
$installerPath = "C:\dotnet-hosting-8.0.2-win.exe"
The script sets the path on the VM where the Hosting Bundle installer will be saved.
$installDotNetHostingBundle = "@
Invoke-WebRequest -Uri $dotnetHostingBundleInstallerUrl -OutFile $installerPath
Start-Process -FilePath $installerPath -ArgumentList '/install', '/quiet', '/norestart' -Wait
Remove-Item -Path $installerPath -Force
"@
This block of PowerShell script is responsible for downloading the Hosting Bundle installer to the VM, executing it silently, and cleaning up by removing the installer file after completion.
Invoke-AzVMRunCommand -ResourceGroupName 'RgAzVMWebAPI' -VMName 'AzVMWebAPI' -CommandId 'RunPowerShellScript' -ScriptString $installDotNetHostingBundle
Similar to previous steps, the script runs the Hosting Bundle installation commands on the remote VM.
Write-Output ".NET 8 Hosting Bundle Installation Successful"
If the installation commands execute without errors, a success message is displayed.
catch
{
Write-Output "Error Installing .NET 8 Hosting Bundle: $_"
}
A "try-catch" block encapsulates the installation process to catch any errors. If an error occurs, an error message is outputted.
Completing the installation of the .NET 8 Hosting Bundle is a key step in preparing the Azure VM to host .NET web applications. This automation exemplifies the power of infrastructure as code, leading to more efficient, reproducible, and reliable deployments.
With everything now setup, we can execute the PowerShell script. Open a terminal prompt, navigate to the directory where the PowerShell script is located, and execute it. After a few moments, you will be required to enter the password for the admin user on the machine we earlier configured. Upon successful completion, the public IP address of the VM will be outputted in the terminal. This will be needed for our GitHub actions workflows CI CD yaml file
In this step, we will create a boilerplate .NET 8 web API project. To do this, open a command prompt or PowerShell window, and enter the following:
dotnet new webapi -n AzWebAPI
After creating the boilerplate web API project, create a new GitHub repository for the web API either via command line or via Visual Studio’s GUI interface. After doing so, we need to set some repository variables that will be used throughout the workflows CI/CD pipeline file.
In GitHub, navigate to the repository settings & under the "Secrets and variables" section in the secutiry settings, add the IP address in the actions section
Now do the same for your prviate SSH key, this can be found in ./ssh/id_rsa
In this section of the blog, we delve into the GitHub Actions workflow file that automates the build and deployment phases for a .NET Web API project. Automation of running unit tests can also be facilitated within this YAML file. Once any changes are committed to the .NET web API repository on the master branch, a series of sequenced operations are triggered that run on the latest Windows environments.
From restoring dependencies and compiling code, to optionally running unit tests and publishing artifacts, and finally deploying the application to a previously provisioned Azure VM— the workflow codifies the steps required to ensure that your .NET application is production-ready at every commit. Let's explore the nuances of this workflow file and how it integrates with the Azure VM setup we previously established through PowerShell scripting, creating a seamless pipeline from code commit to live deployment.
name: CI/CD Pipeline
on:
push:
branches:
- master
This setup defines the initiation of our CI/CD process, ready to act on updates to the master branch, ensuring continuous integration with each code push.
We then define a build-and-deploy
job set to run on the latest Windows environment. This job is the orchestrator, guiding the steps required to transform the code into a deployable state.
jobs:
build-and-deploy:
runs-on: windows-latest
The process kicks off with the checkout
action, fetching the repository's code into the GitHub Actions runner, making the latest commits ready for the subsequent steps.
steps:
- uses: actions/checkout@v2
Following this, the setup-dotnet
action prepares the environment with the .NET version (8.0.x
), ensuring the runner has the necessary runtime and SDK for building the .NET application.
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: '8.0.x'
The dotnet restore
command comes next, restoring the project's dependencies to ensure all necessary packages are available for the build process.
- name: Restore dependencies
run: dotnet restore
With dependencies in place, dotnet build
compiles the code into executable artifacts. The --no-restore
flag signifies that dependency restoration is already handled, focusing the process solely on compilation.
- name: Build Application
run: dotnet build --no-restore
To verify the application's integrity, dotnet test
runs the test suite, ensuring the code performs as intended.
- name: Run Tests
run: dotnet test --no-build
As the build and test phases conclude, dotnet publish
packages the application into a deployable format, readying it for deployment.
- name: Publish Application
run: dotnet publish AzWebAPI/AzWebAPI.csproj --configuration Release --output publish/AzWebAPI
Before deployment, an SSH Agent is set up, utilizing the securely stored SSH private key from GitHub Secrets, establishing a secure connection to the Azure VM.
- name: Create SSH Agent
uses: webfactory/ssh-agent@v0.5.3
with:
ssh-private-key: $secrets.SSH_PRIVATE_KEY
A simple command is executed to confirm the SSH connection's readiness for deployment, marking the preparation for the final deployment steps.
- name: Test SSH Connection
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.VM_IP_ADDRESS "echo Connection successful"
shell: bash
Continuing the narrative of our CI/CD journey, we delve into the deployment phase, where the prepared artifacts are seamlessly transitioned to the live environment. This phase is marked by critical steps that ensure the application is not only deployed but also backed up and verified, embodying a holistic approach to continuous delivery.
- name: Backup Current wwwroot
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY 'powershell -Command "& {$timestamp = Get-Date -Format ''yyyyMMddHHmmss''; $destination = "C:/inetpub/wwwroot_backup_$timestamp"; if (!(Test-Path $destination)) {New-Item -ItemType Directory -Path $destination}; Copy-Item -Path C:/inetpub/wwwroot/* -Destination $destination -Recurse -Force}"'
shell: bash
This step ensures that the current state of the "wwwroot" directory is preserved by creating a timestamped backup. This safeguard allows for recovery in unforeseen circumstances, providing a snapshot of the application before the new deployment.
- name: Delete Current wwwroot Content and Ensure Directory Exists
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "Get-ChildItem -Path C:/inetpub/wwwroot -Exclude wwwroot_backup_* | Remove-Item -Recurse -Force; if (-not (Test-Path -Path C:/inetpub/wwwroot)) { New-Item -Path C:/inetpub/wwwroot -ItemType Directory }""
shell: bash
Following the backup, the "wwwroot" directory is cleansed of its contents, ensuring a pristine environment for the new deployment. This step meticulously avoids disrupting the backup directories, maintaining the integrity of the backups.
- name: List Files in Publish Directory
run: ls -l publish/AzWebAPI
shell: bash
Before proceeding with the file transfer, a listing of the files in the publish directory provides visibility into the artifacts ready for deployment, offering a checkpoint for verification.
- name: Transfer Published Files to VM
run: |
scp -o StrictHostKeyChecking=no -r ./publish/AzWebAPI azureuser@$secrets.SSH_PRIVATE_KEY:C:/inetpub/wwwroot/AzWebAPI
shell: bash
The prepared artifacts are then securely transferred to the Azure VM, placing them within the "wwwroot" directory. This step utilizes secure copy protocol (SCP) to ensure the integrity and security of the file transfer.
- name: Copy New WebAPI to wwwroot
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "if (Test-Path -Path C:/inetpub/wwwroot/AzWebAPI) { Get-ChildItem -Path C:/inetpub/wwwroot/AzWebAPI -Recurse | ForEach-Object { Copy-Item -Path $_.FullName -Destination (Join-Path C:/inetpub/wwwroot $_.Name) -Force } } else { Write-Output 'C:/inetpub/wwwroot/AzWebAPI does not exist, skipping copy.' }""
shell: bash
Upon successful transfer, the contents of the "AzWebAPI" directory are meticulously integrated into the "wwwroot" directory, ensuring that the new version of the application is ready for access.
- name: Move AzWebAPI contents to wwwroot
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "Get-ChildItem -Path C:/inetpub/wwwroot/AzWebAPI -Recurse | Move-Item -Destination C:/inetpub/wwwroot""
shell: bash
This step further ensures that the contents of the "AzWebAPI" are not just copied but also moved to the root of the "wwwroot" directory, aligning with the desired structure for the live application.
- name: Restart IIS
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "Restart-Service -Name W3SVC -Force""
shell: bash
The culmination of the deployment phase is marked by restarting the Internet Information Services (IIS), ensuring that all updates are loaded and the application is served with its newest features. This final step breathes life into the deployed application, making it accessible to users in its most updated form.
Through these meticulously crafted steps, the GitHub Actions workflow encapsulates the essence of continuous delivery, ensuring that every aspect of the deployment is handled with care, from backing up the current state to seamlessly integrating the new version into the live environment. This approach not only streamlines the deployment process but also embeds safeguards and verifications, ensuring the highest level of reliability and integrity in delivering updates to the live application.
In a web browser, if you now navigate to your Azure’s Virtual Machine public IP address followed by the default .NET web API weather forecast endpoint (/WeatherForecast), you will see the boilerplate JSON response.
And with that, we draw the curtains on this installment of our journey through the automation landscape. But rest assured, the adventure doesn't end here. In an upcoming post, I'll be diving into the realms of either Azure Virtual Machines or Docker containers to craft a bespoke iteration of GitHub Actions tailored to our unique needs. So, keep your eyes on this space and stay tuned for more insights and explorations in the ever-evolving world of DevOps. Your continued engagement fuels our exploration into these technological frontiers. Until next time, happy coding!
Following the backup, the "wwwroot" directory is cleansed of its contents, ensuring a pristine environment for the new deployment. This step meticulously avoids disrupting the backup directories, maintaining the integrity of the backups.
- name: List Files in Publish Directory
run: ls -l publish/AzWebAPI
shell: bash
Before proceeding with the file transfer, a listing of the files in the publish directory provides visibility into the artifacts ready for deployment, offering a checkpoint for verification.
- name: Transfer Published Files to VM
run: |
scp -o StrictHostKeyChecking=no -r ./publish/AzWebAPI azureuser@$secrets.SSH_PRIVATE_KEY:C:/inetpub/wwwroot/AzWebAPI
shell: bash
The prepared artifacts are then securely transferred to the Azure VM, placing them within the "wwwroot" directory. This step utilizes secure copy protocol (SCP) to ensure the integrity and security of the file transfer.
- name: Copy New WebAPI to wwwroot
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "if (Test-Path -Path C:/inetpub/wwwroot/AzWebAPI) { Get-ChildItem -Path C:/inetpub/wwwroot/AzWebAPI -Recurse | ForEach-Object { Copy-Item -Path $_.FullName -Destination (Join-Path C:/inetpub/wwwroot $_.Name) -Force } } else { Write-Output 'C:/inetpub/wwwroot/AzWebAPI does not exist, skipping copy.' }""
shell: bash
Upon successful transfer, the contents of the "AzWebAPI" directory are meticulously integrated into the "wwwroot" directory, ensuring that the new version of the application is ready for access.
- name: Move AzWebAPI contents to wwwroot
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "Get-ChildItem -Path C:/inetpub/wwwroot/AzWebAPI -Recurse | Move-Item -Destination C:/inetpub/wwwroot""
shell: bash
This step further ensures that the contents of the "AzWebAPI" are not just copied but also moved to the root of the "wwwroot" directory, aligning with the desired structure for the live application.
- name: Restart IIS
run: |
ssh -o StrictHostKeyChecking=no azureuser@$secrets.SSH_PRIVATE_KEY "powershell -Command "Restart-Service -Name W3SVC -Force""
shell: bash
The culmination of the deployment phase is marked by restarting the Internet Information Services (IIS), ensuring that all updates are loaded and the application is served with its newest features. This final step breathes life into the deployed application, making it accessible to users in its most updated form.
Through these meticulously crafted steps, the GitHub Actions workflow encapsulates the essence of continuous delivery, ensuring that every aspect of the deployment is handled with care, from backing up the current state to seamlessly integrating the new version into the live environment. This approach not only streamlines the deployment process but also embeds safeguards and verifications, ensuring the highest level of reliability and integrity in delivering updates to the live application.
In a web browser, if you now navigate to your Azure’s Virtual Machine public IP address followed by the default .NET web API weather forecast endpoint (/WeatherForecast), you will see the boilerplate JSON response.
And with that, we draw the curtains on this installment of our journey through the automation landscape. But rest assured, the adventure doesn't end here. In an upcoming post, I'll be diving into the realms of either Azure Virtual Machines or Docker containers to craft a bespoke iteration of GitHub Actions tailored to our unique needs. So, keep your eyes on this space and stay tuned for more insights and explorations in the ever-evolving world of DevOps. Your continued engagement fuels our exploration into these technological frontiers. Until next time, happy coding!
© Copyright BrightByte Consulting UK 2023