Skip to content

Commit fb9dda1

Browse files
authored
Merge pull request #11 from git-for-windows/make-self-hosted-runner-deallocation-optional
Optionally keep self-hosted-runners allocated after creating them
2 parents b21205d + 7d3ef90 commit fb9dda1

File tree

5 files changed

+119
-39
lines changed

5 files changed

+119
-39
lines changed

.github/workflows/create-azure-self-hosted-runners.yml

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ name: create-azure-self-hosted-runners
33
on:
44
workflow_dispatch:
55
inputs:
6-
amount_of_runners:
7-
description: 'Amount of runners to set up'
8-
required: true
9-
default: 1
106
runner_scope:
117
type: choice
128
required: true
@@ -23,14 +19,26 @@ on:
2319
type: string
2420
required: false
2521
description: Repo to deploy the runner to. Only needed if runner_scope is set to "repo-level" (defaults to current repository)
22+
deallocate_immediately:
23+
type: string
24+
required: true
25+
description: Deallocate the runner immediately after creating it (useful for spinning up runners preemptively)
26+
default: false
2627

2728
env:
28-
AMOUNT_OF_RUNNERS: ${{ github.event.inputs.amount_of_runners }}
2929
ACTIONS_RUNNER_SCOPE: ${{ github.event.inputs.runner_scope }}
3030
ACTIONS_RUNNER_ORG: "${{ github.event.inputs.runner_org || github.repository_owner }}"
3131
ACTIONS_RUNNER_REPO: "${{ github.event.inputs.runner_repo || github.event.repository.name }}"
32+
DEALLOCATE_IMMEDIATELY: ${{ github.event.inputs.deallocate_immediately }}
3233
# This has to be a public URL that the VM can access after creation
33-
POST_DEPLOYMENT_SCRIPT_URL: https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref_name }}/azure-self-hosted-runners/post-deployment-script.ps1
34+
POST_DEPLOYMENT_SCRIPT_URL: https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref }}/azure-self-hosted-runners/post-deployment-script.ps1
35+
# Note that you'll need "p" (arm64 processor) and ideally "d" (local temp disk). The number 8 stands for 8 CPU-cores.
36+
# For a convenient overview of all arm64 VM types, see e.g. https://azureprice.net/?_cpuArchitecture=Arm64
37+
AZURE_VM_TYPE: Standard_D8plds_v5
38+
# At the time of writing, "eastus", "eastus2" and "westus2" were among the cheapest region for the VM type we're using.
39+
# For more information, see https://learn.microsoft.com/en-us/azure/virtual-machines/dplsv5-dpldsv5-series (which
40+
# unfortunately does not have more information about price by region)
41+
AZURE_VM_REGION: westus2
3442

3543
# The following secrets are required for this workflow to run:
3644
# AZURE_CREDENTIALS - Credentials for the Azure CLI. It's recommended to set up a resource
@@ -42,24 +50,8 @@ env:
4250
# AZURE_VM_USERNAME - Username of the VM so you can RDP into it
4351
# AZURE_VM_PASSWORD - Password of the VM so you can RDP into it
4452
jobs:
45-
create-matrix:
46-
runs-on: ubuntu-latest
47-
outputs:
48-
matrix: ${{ steps.create-matrix.outputs.matrix }}
49-
steps:
50-
- name: Create matrix for setting up runners in parallel
51-
id: create-matrix
52-
run: |
53-
echo "Going to create $AMOUNT_OF_RUNNERS runners"
54-
MATRIX="matrix={\"runner_index\":[$(seq -s "," 1 $AMOUNT_OF_RUNNERS)]}"
55-
echo "Going to use this matrix: $MATRIX"
56-
echo $MATRIX >> $GITHUB_OUTPUT
57-
create-runners:
58-
name: create-runner-${{ matrix.runner_index }}
59-
needs: create-matrix
53+
create-runner:
6054
runs-on: ubuntu-latest
61-
strategy:
62-
matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
6355
outputs:
6456
vm_name: ${{ steps.generate-vm-name.outputs.vm_name }}
6557
steps:
@@ -103,12 +95,12 @@ jobs:
10395
run: |
10496
case "$ACTIONS_RUNNER_SCOPE" in
10597
"org-level")
106-
ACTIONS_API_URL="https://api.github.com/repos/${{ env.ACTIONS_RUNNER_ORG }}/actions/runners/registration-token"
107-
echo ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/${{ env.ACTIONS_RUNNER_ORG }}" >> $GITHUB_ENV
98+
ACTIONS_API_URL="https://api.github.com/repos/$ACTIONS_RUNNER_ORG/actions/runners/registration-token"
99+
ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/$ACTIONS_RUNNER_ORG"
108100
;;
109101
"repo-level")
110-
ACTIONS_API_URL="https://api.github.com/repos/${{ env.ACTIONS_RUNNER_ORG }}/${{ env.ACTIONS_RUNNER_REPO }}/actions/runners/registration-token"
111-
echo ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/${{ env.ACTIONS_RUNNER_ORG }}/${{ env.ACTIONS_RUNNER_REPO }}" >> $GITHUB_ENV
102+
ACTIONS_API_URL="https://api.github.com/repos/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO/actions/runners/registration-token"
103+
ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO"
112104
;;
113105
*)
114106
echo "Unsupported runner scope: $ACTIONS_RUNNER_SCOPE"
@@ -124,7 +116,32 @@ jobs:
124116
$ACTIONS_API_URL \
125117
| jq --raw-output .token)
126118
echo "::add-mask::$ACTIONS_RUNNER_TOKEN"
127-
echo ACTIONS_RUNNER_TOKEN=$ACTIONS_RUNNER_TOKEN >> $GITHUB_ENV
119+
120+
# The Azure VM type we use has blazing-fast local, temporary storage available as the D:\ drive.
121+
# The only downside is that, after dellocation, the contents of this disk (including the Actions Runner),
122+
# are destroyed. Let's only use it when we don't immediately deallocate the VM.
123+
if [[ "$DEALLOCATE_IMMEDIATELY" == "true" ]]; then
124+
ACTIONS_RUNNER_PATH="C:\a"
125+
else
126+
ACTIONS_RUNNER_PATH="D:\a"
127+
fi
128+
129+
AZURE_ARM_PARAMETERS=$(tr '\n' ' ' <<-END
130+
githubActionsRunnerRegistrationUrl="$ACTIONS_RUNNER_REGISTRATION_URL"
131+
githubActionsRunnerToken="$ACTIONS_RUNNER_TOKEN"
132+
postDeploymentPsScriptUrl="$POST_DEPLOYMENT_SCRIPT_URL"
133+
virtualMachineName="${{ steps.generate-vm-name.outputs.vm_name }}"
134+
virtualMachineSize="$AZURE_VM_TYPE"
135+
publicIpAddressName1="${{ steps.generate-vm-name.outputs.vm_name }}-ip"
136+
adminUsername="${{ secrets.AZURE_VM_USERNAME }}"
137+
adminPassword="${{ secrets.AZURE_VM_PASSWORD }}"
138+
stopService="$DEALLOCATE_IMMEDIATELY"
139+
githubActionsRunnerPath="$ACTIONS_RUNNER_PATH"
140+
location="$AZURE_VM_REGION"
141+
END
142+
)
143+
144+
echo "AZURE_ARM_PARAMETERS=$AZURE_ARM_PARAMETERS" >> $GITHUB_ENV
128145
129146
- name: Azure Login
130147
uses: azure/login@v1
@@ -135,9 +152,10 @@ jobs:
135152
with:
136153
resourceGroupName: ${{ secrets.AZURE_RESOURCE_GROUP }}
137154
template: ./azure-self-hosted-runners/azure-arm-template.json
138-
parameters: ./azure-self-hosted-runners/azure-arm-template-example-parameters.json githubActionsRunnerRegistrationUrl="${{ env.ACTIONS_RUNNER_REGISTRATION_URL }}" githubActionsRunnerToken="${{ env.ACTIONS_RUNNER_TOKEN }}" postDeploymentPsScriptUrl="${{ env.POST_DEPLOYMENT_SCRIPT_URL }}" virtualMachineName=${{ steps.generate-vm-name.outputs.vm_name }} virtualMachineSize=Standard_D8pls_v5 publicIpAddressName1=${{ steps.generate-vm-name.outputs.vm_name }}-ip adminUsername=${{ secrets.AZURE_VM_USERNAME }} adminPassword=${{ secrets.AZURE_VM_PASSWORD }}
155+
parameters: ./azure-self-hosted-runners/azure-arm-template-example-parameters.json ${{ env.AZURE_ARM_PARAMETERS }}
139156

140157
- name: Deallocate the VM for later use
158+
if: env.DEALLOCATE_IMMEDIATELY == 'true'
141159
uses: azure/CLI@v1
142160
with:
143161
azcliversion: 2.43.0
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: delete azure-self-hosted-runner
2+
run-name: Delete ${{ inputs.runner_name }}
3+
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
runner_name:
8+
type: string
9+
required: true
10+
description: The name of the runner that needs to be deleted
11+
12+
env:
13+
ACTIONS_RUNNER_NAME: ${{ github.event.inputs.runner_name }}
14+
15+
# The following secrets are required for this workflow to run:
16+
# AZURE_CREDENTIALS - Credentials for the Azure CLI. It's recommended to set up a resource
17+
# group specifically for self-hosted Actions Runners.
18+
# az ad sp create-for-rbac --name "{YOUR_DESCRIPTIVE_NAME_HERE}" --role contributor \
19+
# --scopes /subscriptions/{SUBSCRIPTION_ID_HERE}/resourceGroups/{RESOURCE_GROUP_HERE} \
20+
# --sdk-auth
21+
# AZURE_RESOURCE_GROUP - Resource group to create the runner(s) in
22+
jobs:
23+
delete-runner:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Azure Login
27+
uses: azure/login@v1
28+
with:
29+
creds: ${{ secrets.AZURE_CREDENTIALS }}
30+
- name: Delete VM '${{ env.ACTIONS_RUNNER_NAME }}'
31+
uses: azure/CLI@v1
32+
with:
33+
azcliversion: 2.43.0
34+
inlineScript: |
35+
az vm delete -n "$ACTIONS_RUNNER_NAME" -g ${{ secrets.AZURE_RESOURCE_GROUP }} --yes
36+
az network nsg delete -n "$ACTIONS_RUNNER_NAME"-nsg -g ${{ secrets.AZURE_RESOURCE_GROUP }}
37+
az network vnet delete -n "$ACTIONS_RUNNER_NAME"-vnet -g ${{ secrets.AZURE_RESOURCE_GROUP }}
38+
az network public-ip delete -n "$ACTIONS_RUNNER_NAME"-ip -g ${{ secrets.AZURE_RESOURCE_GROUP }}

azure-self-hosted-runners/azure-arm-template-example-parameters.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
33
"contentVersion": "1.0.0.0",
44
"parameters": {
5-
"location": {
6-
"value": "westeurope"
7-
},
85
"enableAcceleratedNetworking": {
96
"value": true
107
},
@@ -50,7 +47,7 @@
5047
"value": "Standard"
5148
},
5249
"pipDeleteOption": {
53-
"value": "Detach"
50+
"value": "Delete"
5451
},
5552
"osDiskType": {
5653
"value": "Premium_LRS"
@@ -59,7 +56,7 @@
5956
"value": "Delete"
6057
},
6158
"nicDeleteOption": {
62-
"value": "Detach"
59+
"value": "Delete"
6360
},
6461
"patchMode": {
6562
"value": "AutomaticByOS"

azure-self-hosted-runners/azure-arm-template.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
"description": "GitHub Actions Runner registration token for the org/repo. Note that these tokens are only valid for one hour after creation!"
1717
}
1818
},
19+
"githubActionsRunnerPath": {
20+
"type": "string",
21+
"metadata": {
22+
"description": "Path to the Actions Runner. Keep this path short to prevent Long Path issues, e.g. D:\\a"
23+
}
24+
},
1925
"postDeploymentPsScriptUrl": {
2026
"type": "string",
2127
"minLength": 6,
@@ -30,6 +36,12 @@
3036
"description": "Windows Computer Name. Can be maximum 15 characters."
3137
}
3238
},
39+
"stopService": {
40+
"type": "string",
41+
"metadata": {
42+
"description": "(optional) Whether to stop the service immediately. Useful for spinning up runners preemptively."
43+
}
44+
},
3345
"location": {
3446
"type": "string"
3547
},
@@ -250,7 +262,7 @@
250262
"value": "[parameters('location')]"
251263
},
252264
"arguments": {
253-
"value": "[concat('-GitHubActionsRunnerToken ', parameters('githubActionsRunnerToken'), ' -GithubActionsRunnerRegistrationUrl ', parameters('githubActionsRunnerRegistrationUrl'), ' -GithubActionsRunnerName ', parameters('virtualMachineName'))]"
265+
"value": "[concat('-GitHubActionsRunnerToken ', parameters('githubActionsRunnerToken'), ' -GithubActionsRunnerRegistrationUrl ', parameters('githubActionsRunnerRegistrationUrl'), ' -GithubActionsRunnerName ', parameters('virtualMachineName'), ' -StopService ', parameters('stopService'), ' -GitHubActionsRunnerPath ', parameters('githubActionsRunnerPath'))]"
254266
}
255267
}
256268
},

azure-self-hosted-runners/post-deployment-script.ps1

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,16 @@ param (
1111

1212
# Actions Runner name. Needs to be unique in the org/repo
1313
[Parameter(Mandatory=$true)]
14-
[string]$GithubActionsRunnerName
14+
[string]$GithubActionsRunnerName,
15+
16+
# Stop Service immediately (useful for spinning up runners preemptively)
17+
[Parameter(Mandatory=$false)]
18+
[ValidateSet('true', 'false')]
19+
[string]$StopService = 'true',
20+
21+
# Path to the Actions Runner. Keep this path short to prevent Long Path issues, e.g. D:\a
22+
[Parameter(Mandatory=$true)]
23+
[string]$GitHubActionsRunnerPath
1524
)
1625

1726
Write-Output "Starting post-deployment script."
@@ -28,8 +37,6 @@ $GitHubActionsRunnerVersion = "2.300.2"
2837
$GithubActionsRunnerArch = "arm64"
2938
$GithubActionsRunnerHash = "9409e50d9ad33d8031355ed079b8f56cf3699f35cf5d0ca51e54deed432758ef"
3039
$GithubActionsRunnerLabels = "self-hosted,Windows,ARM64"
31-
# Keep this path short to prevent Long Path issues
32-
$GitHubActionsRunnerPath = "C:\a"
3340

3441
# ======================
3542
# WINDOWS DEVELOPER MODE
@@ -106,6 +113,12 @@ if((Get-FileHash -Path ${GitHubActionsRunnerPath}\actions-runner-win-${GithubAct
106113
Write-Output "Installing GitHub Actions runner ${GitHubActionsRunnerVersion} as a Windows service with labels ${GithubActionsRunnerLabels}..."
107114

108115
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("${GitHubActionsRunnerPath}\actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip", $GitHubActionsRunnerPath)
116+
117+
Write-Output "Configuring the runner to shut down automatically after running"
118+
Set-Content -Path "${GitHubActionsRunnerPath}\shut-down.ps1" -Value "shutdown -s -t 60 -d p:4:0 -c `"workflow job is done`""
119+
[System.Environment]::SetEnvironmentVariable("ACTIONS_RUNNER_HOOK_JOB_COMPLETED", "${GitHubActionsRunnerPath}\shut-down.ps1", [System.EnvironmentVariableTarget]::Machine)
120+
121+
Write-Output "Configuring the runner"
109122
cmd.exe /c "${GitHubActionsRunnerPath}\config.cmd" --unattended --ephemeral --name ${GithubActionsRunnerName} --runasservice --labels ${GithubActionsRunnerLabels} --url ${GithubActionsRunnerRegistrationUrl} --token ${GitHubActionsRunnerToken}
110123

111124
# Ensure that the service was created. If not, exit with error code.
@@ -116,6 +129,8 @@ if ($MatchedServices.count -eq 0) {
116129
}
117130

118131
# Immediately stop the service as we want to leave the VM in a deallocated state for later use. The service will automatically be started when Windows starts.
119-
Stop-Service -Name "actions.runner.*" -Verbose
132+
if (${StopService} -eq 'true') {
133+
Stop-Service -Name "actions.runner.*" -Verbose
134+
}
120135

121136
Write-Output "Finished installing GitHub Actions runner."

0 commit comments

Comments
 (0)