-
Notifications
You must be signed in to change notification settings - Fork 12
172 lines (158 loc) · 7.49 KB
/
create-azure-self-hosted-runners.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
name: create-azure-self-hosted-runners
on:
workflow_dispatch:
inputs:
runner_scope:
type: choice
required: true
description: Scope of the runner. On personal accounts, only "repo-level" works
options:
- org-level
- repo-level
default: repo-level
runner_org:
type: string
required: false
description: Organization or personal account to deploy the runner to (defaults to the repository owner)
runner_repo:
type: string
required: false
description: Repo to deploy the runner to. Only needed if runner_scope is set to "repo-level" (defaults to current repository)
deallocate_immediately:
type: string
required: true
description: Deallocate the runner immediately after creating it (useful for spinning up runners preemptively)
default: false
env:
ACTIONS_RUNNER_SCOPE: ${{ github.event.inputs.runner_scope }}
ACTIONS_RUNNER_ORG: "${{ github.event.inputs.runner_org || github.repository_owner }}"
ACTIONS_RUNNER_REPO: "${{ github.event.inputs.runner_repo || github.event.repository.name }}"
DEALLOCATE_IMMEDIATELY: ${{ github.event.inputs.deallocate_immediately }}
# This has to be a public URL that the VM can access after creation
POST_DEPLOYMENT_SCRIPT_URL: https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref }}/azure-self-hosted-runners/post-deployment-script.ps1
# Note that you'll need "p" (arm64 processor) and ideally "d" (local temp disk). The number 4 stands for 4 CPU-cores.
# For a convenient overview of all arm64 VM types, see e.g. https://azureprice.net/?_cpuArchitecture=Arm64
AZURE_VM_TYPE: Standard_D4plds_v5
# At the time of writing, "eastus", "eastus2" and "westus2" were among the cheapest region for the VM type we're using.
# For more information, see https://learn.microsoft.com/en-us/azure/virtual-machines/dplsv5-dpldsv5-series (which
# unfortunately does not have more information about price by region)
AZURE_VM_REGION: westus2
AZURE_VM_IMAGE: win11-23h2-ent
# The following secrets are required for this workflow to run:
# AZURE_CREDENTIALS - Credentials for the Azure CLI. It's recommended to set up a resource
# group specifically for self-hosted Actions Runners.
# az ad sp create-for-rbac --name "{YOUR_DESCRIPTIVE_NAME_HERE}" --role contributor \
# --scopes /subscriptions/{SUBSCRIPTION_ID_HERE}/resourceGroups/{RESOURCE_GROUP_HERE} \
# --sdk-auth
# AZURE_RESOURCE_GROUP - Resource group to create the runner(s) in
# AZURE_VM_USERNAME - Username of the VM so you can RDP into it
# AZURE_VM_PASSWORD - Password of the VM so you can RDP into it
jobs:
create-runner:
runs-on: ubuntu-latest
outputs:
vm_name: ${{ steps.generate-vm-name.outputs.vm_name }}
steps:
- name: Generate VM name
id: generate-vm-name
run: |
VM_NAME="actions-runner-$(date +%Y%m%d%H%M%S%N)"
echo "Will be using $VM_NAME as the VM name"
echo "vm_name=$VM_NAME" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4
- name: Obtain installation token
id: setup
uses: actions/github-script@v7
with:
script: |
const appId = ${{ secrets.GH_APP_ID }}
const privateKey = `${{ secrets.GH_APP_PRIVATE_KEY }}`
const getAppInstallationId = require('./get-app-installation-id')
const installationId = await getAppInstallationId(
console,
appId,
privateKey,
process.env.ACTIONS_RUNNER_ORG,
process.env.ACTIONS_RUNNER_REPO
)
const getInstallationAccessToken = require('./get-installation-access-token')
const { token: accessToken } = await getInstallationAccessToken(
console,
appId,
privateKey,
installationId
)
core.setSecret(accessToken)
core.setOutput('token', accessToken)
# We can't use the octokit/request-action as we can't properly mask the runner token with it
# https://github.com/actions/runner/issues/475
- name: Generate Actions Runner token and registration URL
run: |
case "$ACTIONS_RUNNER_SCOPE" in
"org-level")
ACTIONS_API_URL="https://api.github.com/repos/$ACTIONS_RUNNER_ORG/actions/runners/registration-token"
ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/$ACTIONS_RUNNER_ORG"
;;
"repo-level")
ACTIONS_API_URL="https://api.github.com/repos/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO/actions/runners/registration-token"
ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO"
;;
*)
echo "Unsupported runner scope: $ACTIONS_RUNNER_SCOPE"
exit 1
;;
esac
ACTIONS_RUNNER_TOKEN=$(curl \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ steps.setup.outputs.token }}"\
-H "X-GitHub-Api-Version: 2022-11-28" \
$ACTIONS_API_URL \
| jq --raw-output .token)
echo "::add-mask::$ACTIONS_RUNNER_TOKEN"
# The Azure VM type we use has blazing-fast local, temporary storage available as the D:\ drive.
# The only downside is that, after dellocation, the contents of this disk (including the Actions Runner),
# are destroyed. Let's only use it when we don't immediately deallocate the VM.
if [[ "$DEALLOCATE_IMMEDIATELY" == "true" ]]; then
ACTIONS_RUNNER_PATH="C:\a"
else
ACTIONS_RUNNER_PATH="D:\a"
fi
AZURE_ARM_PARAMETERS=$(tr '\n' ' ' <<-END
githubActionsRunnerRegistrationUrl="$ACTIONS_RUNNER_REGISTRATION_URL"
githubActionsRunnerToken="$ACTIONS_RUNNER_TOKEN"
postDeploymentPsScriptUrl="$POST_DEPLOYMENT_SCRIPT_URL"
virtualMachineImage="$AZURE_VM_IMAGE"
virtualMachineName="${{ steps.generate-vm-name.outputs.vm_name }}"
virtualMachineSize="$AZURE_VM_TYPE"
publicIpAddressName1="${{ steps.generate-vm-name.outputs.vm_name }}-ip"
adminUsername="${{ secrets.AZURE_VM_USERNAME }}"
adminPassword="${{ secrets.AZURE_VM_PASSWORD }}"
stopService="$DEALLOCATE_IMMEDIATELY"
githubActionsRunnerPath="$ACTIONS_RUNNER_PATH"
location="$AZURE_VM_REGION"
END
)
echo "AZURE_ARM_PARAMETERS=$AZURE_ARM_PARAMETERS" >> $GITHUB_ENV
- name: Azure Login
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- uses: azure/arm-deploy@v2
id: deploy-arm-template
with:
resourceGroupName: ${{ secrets.AZURE_RESOURCE_GROUP }}
deploymentName: deploy-${{ steps.generate-vm-name.outputs.vm_name }}
template: ./azure-self-hosted-runners/azure-arm-template.json
parameters: ./azure-self-hosted-runners/azure-arm-template-example-parameters.json ${{ env.AZURE_ARM_PARAMETERS }}
- name: Show post-deployment script output
env:
CUSTOM_SCRIPT_OUTPUT: ${{ steps.deploy-arm-template.outputs.customScriptInstanceView }}
run: echo "$CUSTOM_SCRIPT_OUTPUT" | jq -r '.substatuses[0].message'
- name: Deallocate the VM for later use
if: env.DEALLOCATE_IMMEDIATELY == 'true'
uses: azure/CLI@v2
with:
azcliversion: 2.43.0
inlineScript: |
az vm deallocate -n ${{ steps.generate-vm-name.outputs.vm_name }} -g ${{ secrets.AZURE_RESOURCE_GROUP }} --verbose