-
Notifications
You must be signed in to change notification settings - Fork 13
Add CI pipeline for creating self-hosted runners #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6cfc1d0
c683f89
d706073
cf522f2
b09684a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
name: create-azure-self-hosted-runners | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
amount_of_runners: | ||
description: 'Amount of runners to set up' | ||
required: true | ||
default: 1 | ||
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) | ||
|
||
env: | ||
AMOUNT_OF_RUNNERS: ${{ github.event.inputs.amount_of_runners }} | ||
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 }}" | ||
# 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_name }}/azure-self-hosted-runners/post-deployment-script.ps1 | ||
|
||
# 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-matrix: | ||
runs-on: ubuntu-latest | ||
outputs: | ||
matrix: ${{ steps.create-matrix.outputs.matrix }} | ||
steps: | ||
- name: Create matrix for setting up runners in parallel | ||
id: create-matrix | ||
run: | | ||
echo "Going to create $AMOUNT_OF_RUNNERS runners" | ||
MATRIX="matrix={\"runner_index\":[$(seq -s "," 1 $AMOUNT_OF_RUNNERS)]}" | ||
echo "Going to use this matrix: $MATRIX" | ||
echo $MATRIX >> $GITHUB_OUTPUT | ||
create-runners: | ||
name: create-runner-${{ matrix.runner_index }} | ||
needs: create-matrix | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }} | ||
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@v3 | ||
- name: Obtain installation token | ||
id: setup | ||
uses: actions/github-script@v6 | ||
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 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/${{ env.ACTIONS_RUNNER_ORG }}/actions/runners/registration-token" | ||
echo ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/${{ env.ACTIONS_RUNNER_ORG }}" >> $GITHUB_ENV | ||
;; | ||
"repo-level") | ||
ACTIONS_API_URL="https://api.github.com/repos/${{ env.ACTIONS_RUNNER_ORG }}/${{ env.ACTIONS_RUNNER_REPO }}/actions/runners/registration-token" | ||
echo ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/${{ env.ACTIONS_RUNNER_ORG }}/${{ env.ACTIONS_RUNNER_REPO }}" >> $GITHUB_ENV | ||
;; | ||
*) | ||
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" | ||
echo ACTIONS_RUNNER_TOKEN=$ACTIONS_RUNNER_TOKEN >> $GITHUB_ENV | ||
|
||
- name: Azure Login | ||
uses: azure/login@v1 | ||
with: | ||
creds: ${{ secrets.AZURE_CREDENTIALS }} | ||
|
||
- uses: azure/arm-deploy@v1 | ||
with: | ||
resourceGroupName: ${{ secrets.AZURE_RESOURCE_GROUP }} | ||
template: ./azure-self-hosted-runners/azure-arm-template.json | ||
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 }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's leave it for now, I'll monitor the usage. If I'm running out of money too fast, I'll just scale it down. |
||
|
||
- name: Deallocate the VM for later use | ||
uses: azure/CLI@v1 | ||
with: | ||
azcliversion: 2.43.0 | ||
inlineScript: | | ||
az vm deallocate -n ${{ steps.generate-vm-name.outputs.vm_name }} -g ${{ secrets.AZURE_RESOURCE_GROUP }} --verbose |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
{ | ||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", | ||
"contentVersion": "1.0.0.0", | ||
"parameters": { | ||
"location": { | ||
"value": "westeurope" | ||
}, | ||
"enableAcceleratedNetworking": { | ||
"value": true | ||
}, | ||
"networkSecurityGroupRules": { | ||
"value": [ | ||
{ | ||
"name": "RDP", | ||
"properties": { | ||
"priority": 300, | ||
"protocol": "TCP", | ||
"access": "Allow", | ||
"direction": "Inbound", | ||
"sourceAddressPrefix": "*", | ||
"sourcePortRange": "*", | ||
"destinationAddressPrefix": "*", | ||
"destinationPortRange": "3389" | ||
} | ||
} | ||
] | ||
}, | ||
"subnetName": { | ||
"value": "default" | ||
}, | ||
"addressPrefixes": { | ||
"value": [ | ||
"10.2.0.0/16" | ||
] | ||
}, | ||
"subnets": { | ||
"value": [ | ||
{ | ||
"name": "default", | ||
"properties": { | ||
"addressPrefix": "10.2.0.0/24" | ||
} | ||
} | ||
] | ||
}, | ||
"publicIpAddressType": { | ||
"value": "Static" | ||
}, | ||
"publicIpAddressSku": { | ||
"value": "Standard" | ||
}, | ||
"pipDeleteOption": { | ||
"value": "Detach" | ||
}, | ||
"osDiskType": { | ||
"value": "Premium_LRS" | ||
}, | ||
"osDiskDeleteOption": { | ||
"value": "Delete" | ||
}, | ||
"nicDeleteOption": { | ||
"value": "Detach" | ||
}, | ||
"patchMode": { | ||
"value": "AutomaticByOS" | ||
}, | ||
"enableHotpatching": { | ||
"value": false | ||
}, | ||
"zone": { | ||
"value": "1" | ||
}, | ||
"computerName": { | ||
"value": "actions-runner" | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed that you want to create these VMs in their own, dedicated resource group. This pipeline expects the resource group to be created in Azure prior to running the pipeline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. Then we can delete the resource group which should delete everything contained therein.