Implement build-and-test Github Actions CI using AWS spot instances #1
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build And Test | ||
# Based on | ||
# https://blog.devgenius.io/create-register-and-terminate-ec2-spot-instances-via-github-actions-aef473b8a00f | ||
on: | ||
workflow_call: | ||
inputs: | ||
architecture: | ||
required: true | ||
type: string | ||
instance_type: | ||
required: true | ||
type: string | ||
secrets: | ||
ACTIONS_TOKEN: | ||
required: true | ||
env: | ||
EC2_SECURITY_GROUP_ID: sg-072c6deccd49e89c8 # rr-testing | ||
AWS_ROLE_ARN: arn:aws:iam::019859450731:role/SpotInstanceManager | ||
AWS_REGION: us-east-2 | ||
RUNNER_VERSION: "2.316.1" | ||
jobs: | ||
start-runner: | ||
name: Start Runner | ||
permissions: write-all | ||
runs-on: ubuntu-latest | ||
outputs: | ||
EC2_HOST: ${{ env.EC2_HOST }} | ||
EC2_INSTANCE_ID: ${{ env.EC2_INSTANCE_ID }} | ||
steps: | ||
- name: "Run :: Configure AWS credentials" | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
role-to-assume: ${{ env.AWS_ROLE_ARN }} | ||
role-session-name: pipeline-assume-role-session | ||
aws-region: ${{ env.AWS_REGION }} | ||
- name: "Run :: Create and register AWS spot instance" | ||
run: |2- | ||
# Get GitHub Actions runner registration token | ||
response=$(curl -s -X POST -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer ${{ secrets.ACTIONS_TOKEN }}' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/orgs/rr-debugger/actions/runners/registration-token) | ||
echo "response :: $response" | ||
RUNNER_REG_TOKEN=$(echo "$response" | jq -r .token) | ||
echo "RUNNER_REG_TOKEN :: $RUNNER_REG_TOKEN" | ||
if [ $RUNNER_REG_TOKEN == "null" ]; then | ||
exit 1 | ||
fi | ||
USER_DATA="#!/bin/bash | ||
# Make sure the VM doesn't run for more than an hour | ||
shutdown +60 | ||
apt-get update -y | ||
apt-get dist-upgrade -f -y | ||
sudo -u ubuntu --login <<EOF | ||
# Install GitHub Actions runner | ||
mkdir /home/ubuntu/actions-runner && cd /home/ubuntu/actions-runner | ||
curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz | ||
echo \"Github Runner Installed\" | ||
# Extract the installer | ||
tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz | ||
echo \"Github Runner Installer Extracted\" | ||
# Run GitHub Actions runner configuration | ||
yes '' | ./config.sh --url https://github.com/rr-debugger --token $RUNNER_REG_TOKEN --labels ${{ inputs.architecture }}_${{github.sha}} | ||
# Run GitHub Actions runner | ||
yes '' | ./run.sh | ||
EOF | ||
" | ||
IMAGE_ID=$(aws ec2 describe-images --owners 099720109477 --filters 'Name=architecture,Values=${{ inputs.architecture }}' 'Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-*' | jq --raw-output .Images[0].ImageId) | ||
echo "IMAGE_ID :: $IMAGE_ID" | ||
ENCODED_USER_DATA=$(echo -n "$USER_DATA" | sed 's/^[[:space:]]*//' | base64 -w 0) | ||
echo "ENCODED_USER_DATA :: $ENCODED_USER_DATA" | ||
INSTANCE_ID=$(aws ec2 run-instances --image-id $IMAGE_ID --instance-type ${{ inputs.instance_type }} --user-data $ENCODED_USER_DATA --security-group-ids ${{ env.EC2_SECURITY_GROUP_ID }} --instance-market-options MarketType=spot --instance-initiated-shutdown-behavior terminate --query 'Instances[0].InstanceId' --key-name rr-testing --output text) | ||
echo "INSTANCE_ID :: $INSTANCE_ID" | ||
aws ec2 wait instance-running --instance-ids $INSTANCE_ID | ||
HOSTNAME=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].PublicDnsName' --output text) | ||
echo "HOSTNAME :: $HOSTNAME" | ||
echo Runner label :: ${{ inputs.architecture }}_${{github.sha}} | ||
echo "EC2_HOST=$HOSTNAME" >> $GITHUB_ENV | ||
echo "EC2_INSTANCE_ID=$INSTANCE_ID" >> $GITHUB_ENV | ||
build-and-test: | ||
name: Build And Test | ||
permissions: | ||
contents: read | ||
runs-on: [self-hosted, ${{ inputs.architecture }}_${{github.sha}}] | ||
needs: | ||
- start-runner | ||
steps: | ||
- name: Start | ||
run: |2- | ||
echo " Starting GitHub Action!" && | ||
echo "STEPS_CAN_PROCEED=true" >> $GITHUB_ENV | ||
- name: "Run :: Checkout repository" | ||
uses: actions/checkout@v2 | ||
- name: "Run :: Build" | ||
run: ./scripts/github-actions-build.sh | ||
- name: "Run :: Test" | ||
run: ./scripts/github-actions-test.sh | ||
stop-runner: | ||
name: Stop Runner | ||
permissions: write-all | ||
runs-on: ubuntu-latest | ||
needs: | ||
- start-runner | ||
- build-and-test | ||
if: ${{ always() }} | ||
steps: | ||
- name: "Run :: Configure AWS credentials" | ||
uses: aws-actions/configure-aws-credentials@v4 | ||
with: | ||
role-to-assume: ${{ env.AWS_ROLE_ARN }} | ||
role-session-name: pipeline-assume-role-session | ||
aws-region: ${{ env.AWS_REGION }} | ||
- name: "Run :: Terminate and unregister AWS spot instance" | ||
run: |2- | ||
aws ec2 terminate-instances --instance-ids ${{ needs.start-runner.outputs.EC2_INSTANCE_ID }} | ||
gh_runner_label=${{ needs.start-runner.outputs.EC2_RUNNER }} | ||
response=$(curl -X GET https://api.github.com/orgs/rr-debugger/actions/runners -H 'Authorization: Bearer ${{ secrets.ACTIONS_TOKEN }}' | ||
) | ||
offline_runners=$(echo "$response" | jq '.runners | map(select((.labels? | any(.name == "${{ inputs.architecture }}_${{github.sha}}"))))') | ||
echo "Offline Runners :: $offline_runners" | ||
echo "Attempting to remove offline runners..." | ||
for runner in $(echo "$offline_runners" | jq -r '.[].id'); do | ||
echo "Triggering action for runner ID: $runner" | ||
curl -X DELETE https://api.github.com/orgs/rr-debugger/actions/runners/$runner -H 'Authorization: Bearer ${{ secrets.ACTIONS_TOKEN }}' | ||
done |