From 8bb2976d6bd476fdb31e462fb0a0fcd0b628d045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Palom=C3=A4ki?= Date: Sun, 26 Sep 2021 22:26:08 +0300 Subject: [PATCH] Leverage ephemeral runners by default (#8) --- README.md | 88 +++++++++++++++++++++++++++++++++++++++--------- start/action.yml | 17 ++++++++-- stop/action.yml | 15 ++++----- 3 files changed, 93 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index dfc4303..e309fbd 100644 --- a/README.md +++ b/README.md @@ -9,22 +9,32 @@ Inspired by ## Requirements - AWS account and VPC network + - A default VPC works fine, too - AWS credentials with EC2 permissions -- VPC subnet with Internet access (either assigning public IP or via NAT gateway) + - You can use either a plain IAM user, or assume a role +- VPC subnet with Internet access + - Public subnet (public IP) **or** + - Private subnet with NAT gateway - Linux runner AMI (amd64 or arm64), with the following things pre-configured: - - [Actions-runner](https://github.com/actions/runner) and its [dependencies](https://github.com/actions/runner/blob/main/docs/start/envlinux.md) - Non-root user to run actions-runner service as - - `git`, `docker`, `curl` and optionally `at` (if using the auto-shutdown feature) - - See e.g. -- EC2 launch template (AMI, instance type, VPC, security group, spot options etc) + - [Actions-runner](https://github.com/actions/runner) v2.283.1+ and required [dependencies](https://github.com/actions/runner/blob/main/docs/start/envlinux.md) + - `git`, `docker`, `curl` and optionally `at` (if using the `auto-shutdown-at` feature) + - See e.g. for an example AMI build +- EC2 launch template (AMI, instance type, VPC subnet, security groups, spot options etc) - See example [Cloudformation template](https://gist.github.com/jpalomaki/003c4d173a856cf64c6d35f8869a2de8) that sets up a launch template - GitHub personal access token (PAT) with `repo` scope -## Example workflow - See [start/action.yml](start/action.yml) and [stop/action.yml](stop/action.yml) for all available input parameters. -:warning: do not copy this example verbatim, but adjust action version, AWS region, launch template etc to match your config +## Example workflows + +💡 EC2 instance ID is automatically assigned as a unique, self-hosted runner label + +⚠️ Do not simply copy these examples verbatim, but adjust action version, AWS region, launch template name etc to match your config + +### Simple + +Simple default. Leverages ephemeral runners that are automatically deregistered from GitHub after the `main` job has run. ```yaml jobs: @@ -38,27 +48,73 @@ jobs: aws-region: eu-north-1 aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-launch-template: LaunchTemplateName=my-arm64-runner + aws-launch-template: LaunchTemplateName=my-special-runner github-token: ${{ secrets.GH_PAT }} - runner-labels: ubuntu-18.04-arm64 outputs: - runner-id: ${{ steps.runner.outputs.runner-id }} instance-id: ${{ steps.runner.outputs.instance-id }} - complex-build: + main: + needs: start-runner + runs-on: ${{ needs.start-runner.outputs.instance-id }} + steps: + - run: uname -a + + stop-runner: + if: always() + needs: [start-runner, main] + runs-on: ubuntu-20.04 + steps: + - name: Stop runner + uses: superblk/ec2-actions-runner/stop@ + with: + aws-region: eu-north-1 + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + instance-id: ${{ needs.start-runner.outputs.instance-id }} +``` + +### Advanced + +A more fail-safe alternative. Deregisters GitHub runner explicitly (not relying on ephemeral runner auto-deregistration behavior alone). Also leverages EC2 [instance-initiated shutdown](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingInstanceInitiatedShutdownBehavior) **terminate** behavior for ensuring the EC2 instance is terminated, even if the `stop-runner` job fails to run. + +⚠️ For the automatic dead-man's switch termination to work, the AMI must include the `at` tool, and the EC2 launch template must specify instance-initiated shutdown behavior as **terminate**. + +💡 This example also illustrates the use of extra runner labels and a matrix `main` job, that uses both GitHub-hosted and self-hosted runners. + +```yaml +jobs: + start-runner: + runs-on: ubuntu-20.04 + steps: + - id: runner + name: Start runner + uses: superblk/ec2-actions-runner/start@ + with: + aws-region: eu-north-1 + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-launch-template: LaunchTemplateName=my-special-runner + runner-labels: ubuntu-18.04-arm64-${{ github.run_id }} + github-token: ${{ secrets.GH_PAT }} + auto-shutdown-at: 'now + 3 hours' + outputs: + instance-id: ${{ steps.runner.outputs.instance-id }} + runner-id: ${{ steps.runner.outputs.runner-id }} + + main: needs: start-runner runs-on: ${{ matrix.runner }} strategy: matrix: include: - runner: ubuntu-18.04 - - runner: ubuntu-18.04-arm64 + - runner: ubuntu-18.04-arm64-${{ github.run_id }} steps: - run: uname -a stop-runner: if: always() - needs: [start-runner, complex-build] + needs: [start-runner, main] runs-on: ubuntu-20.04 steps: - name: Stop runner @@ -67,7 +123,7 @@ jobs: aws-region: eu-north-1 aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - github-token: ${{ secrets.GH_PAT }} - runner-id: ${{ needs.start-runner.outputs.runner-id }} instance-id: ${{ needs.start-runner.outputs.instance-id }} + runner-id: ${{ needs.start-runner.outputs.runner-id }} + github-token: ${{ secrets.GH_PAT }} ``` diff --git a/start/action.yml b/start/action.yml index 685bd95..271321c 100644 --- a/start/action.yml +++ b/start/action.yml @@ -26,7 +26,7 @@ inputs: default: ${{ github.repository }} required: false runner-labels: - description: Extra runner labels (comma-separated) + description: Extra runner labels (comma-separated). Can be referenced in job 'runs-on' required: false runner-home: description: Directory that contains actions-runner software and scripts @@ -39,6 +39,10 @@ inputs: auto-shutdown-at: description: Automatically shutdown instance at the specified time?. E.g. 'now + 72 hours'. Requires https://linux.die.net/man/1/at required: false + ephemeral: + description: Flag the runner as ephemeral? An ephemeral runner is automatically de-registered after running _one_ workflow job + required: false + default: true outputs: runner-id: @@ -67,11 +71,19 @@ runs: run: | runner_token="$(gh api -X POST -H 'Accept: application/vnd.github.v3+json' "repos/$GITHUB_REPO/actions/runners/registration-token" | jq -r .token)" + if [ "$EPHEMERAL" = "true" ]; then + extra_flags="--ephemeral" + fi + + if [ ! -z "$RUNNER_LABELS" ]; then + extra_labels=",$RUNNER_LABELS" + fi + user_data=$(cat <