CDK constructs for self-hosted GitHub Actions runners

Overview

GitHub Self-Hosted Runners CDK Constructs

NPM PyPI Maven Central Go Nuget Release License

Use this CDK construct to create ephemeral self-hosted GitHub runners on-demand inside your AWS account.

  • Easy to configure GitHub integration
  • Customizable runners with decent defaults
  • Supports multiple runner configurations controlled by labels
  • Everything fully hosted in your account

Self-hosted runners in AWS are useful when:

  • You need easy access to internal resources in your actions
  • You want to pre-install some software for your actions
  • You want to provide some basic AWS API access (aws-actions/configure-aws-credentials has more security controls)

Ephemeral runners are the recommended way by GitHub for auto-scaling, and they make sure all jobs run with a clean image. Runners are started on-demand. You don't pay unless a job is running.

API

Documentation of available constructs and their interface is available on Constructs Hub in all supported programming languages.

Providers

A runner provider creates compute resources on-demand and uses actions/runner to start a runner.

Provider Time limit vCPUs RAM Storage sudo Docker
CodeBuild 8 hours (default 1 hour) 2 (default), 4, 8, or 72 3gb (default), 7gb, 15gb or 145gb 50gb to 824gb (default 64gb)
Fargate Unlimited 0.25 to 4 (default 1) 512mb to 30gb (default 2gb) 20gb to 200gb (default 25gb)
Lambda 15 minutes 1 to 6 (default 2) 128mb to 10gb (default 2gb) Up to 10gb (default 10gb)

The best provider to use mostly depends on your current infrastructure. When in doubt, CodeBuild is always a good choice. Execution history and logs are easy to view, and it has no restrictive limits unless you need to run for more than 8 hours.

You can also create your own provider by implementing IRunnerProvider.

Installation

  1. Confirm you're using CDK v2
  2. Install the appropriate package
    1. Python
      pip install cloudsnorkel.cdk-github-runners
      
    2. TypeScript or JavaScript
      npm i @cloudsnorkel/cdk-github-runners
      
    3. Java
      <dependency>
      <groupId>com.cloudsnorkel</groupId>
      <artifactId>cdk.github.runners</artifactId>
      </dependency>
    4. Go
      go get github.com/CloudSnorkel/cdk-github-runners-go/cloudsnorkelcdkgithubrunners
      
    5. .NET
      dotnet add package CloudSnorkel.Cdk.Github.Runners
      
  3. Use GitHubRunners construct in your code (starting with default arguments is fine)
  4. Deploy your stack
  5. Look for the status command output similar to aws --region us-east-1 lambda invoke --function-name status-XYZ123 status.json
  6. Execute the status command (you may need to specify --profile too) and open the resulting status.json file
  7. Setup GitHub integration as an app or with personal access token
  8. Run status command again to confirm github.auth.status and github.webhook.status are OK
  9. Trigger a GitHub action that has a self-hosted label with runs-on: [self-hosted, linux, codebuild] or similar
  10. If the action is not successful, see troubleshooting

Customizing

The default providers configured by GitHubRunners are useful for testing but probably not too much for actual production work. They run in the default VPC or no VPC and have no added IAM permissions. You would usually want to configure the providers yourself.

For example:

import * as cdk from 'aws-cdk-lib';
import { aws_ec2 as ec2, aws_s3 as s3 } from 'aws-cdk-lib';
import { GitHubRunners, CodeBuildRunner } from '@cloudsnorkel/cdk-github-runners';

const app = new cdk.App();
const stack = new cdk.Stack(
  app,
  'github-runners-test',
  {
     env: {
        account: process.env.CDK_DEFAULT_ACCOUNT,
        region: process.env.CDK_DEFAULT_REGION,
     },
  },
);

const vpc = ec2.Vpc.fromLookup(stack, 'vpc', { vpcId: 'vpc-1234567' });
const runnerSg = new ec2.SecurityGroup(stack, 'runner security group', { vpc: vpc });
const dbSg = ec2.SecurityGroup.fromSecurityGroupId(stack, 'database security group', 'sg-1234567');
const bucket = new s3.Bucket(stack, 'runner bucket');

// create a custom CodeBuild provider
const myProvider = new CodeBuildRunner(
  stack, 'codebuild runner',
  {
     label: 'my-codebuild',
     vpc: vpc,
     securityGroup: runnerSg,
  },
);
// grant some permissions to the provider
bucket.grantReadWrite(myProvider);
dbSg.connections.allowFrom(runnerSg, ec2.Port.tcp(3306), 'allow runners to connect to MySQL database');

// create the runner infrastructure
new GitHubRunners(
  stack,
  'runners',
  {
    providers: [myProvider],
    defaultProviderLabel: 'my-codebuild',
  }
);

app.synth();

Architecture

Architecture diagram

Troubleshooting

  1. Always start with the status function, make sure no errors are reported, and confirm all status codes are OK
  2. Confirm the webhook Lambda was called by visiting the URL in troubleshooting.webhookHandlerUrl from status.json
    1. If it's not called or logs errors, confirm the webhook settings on the GitHub side
    2. If you see too many errors, make sure you're only sending workflow_job events
  3. Check execution details of the orchestrator step function by visiting the URL in troubleshooting.stepFunctionUrl from status.json
    1. Use the details tab to find the specific execution of the provider (Lambda, CodeBuild, Fargate, etc.)
    2. Every step function execution should be successful, even if the runner action inside it failed

Other Options

  1. philips-labs/terraform-aws-github-runner if you're using Terraform
  2. actions-runner-controller/actions-runner-controller if you're using Kubernetes
Comments
  • feature request: self hosted ephemeral enterprise runners

    feature request: self hosted ephemeral enterprise runners

    Currently this solution can be used in conjunction with github apps for organizations and personal repositories.

    Github Enterprise supports "self-hosted enterprise runners" that can be registered on the enterprise level. Would be nice to have the option to created self-hosted enterprise runners.

    opened by pharindoko 9
  • GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.

    GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.

    Trying to use this library with my GHE resulted in the following error message:

    The GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.

    I'm using the codebuild provider and narrowed it down to the --disableupdate flag.

    I'm new to this whole topic, but removing it from by buildspec manually resolved the issue. I'm guessing that the flag might even be irrelevant anyways since the runners are ephemeral?

    What are the impacts of removing that flag? could we make it optional?

    opened by laxgoalie392 8
  • fix:  container vulnerabilities

    fix: container vulnerabilities

    Hey,

    I use codebuild for my runners and the default linux image (no custom image) provided. Ecr has the capability to do a vulnerability scan (https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html). I found a lot of critical security vulnerabilities inside of the container image. Do you have a clue why ?

    br,

    flo

    opened by pharindoko 7
  • Unrecognized labels cancel entire workflow

    Unrecognized labels cancel entire workflow

    From https://github.com/CloudSnorkel/cdk-github-runners/issues/72#issuecomment-1289480905

    In your case it sounds like it's because we expect every job with the self-hosted label to also have a label we recognize. It sounds like you have multiple installations of cdk-github-runners in different accounts, each implementing different labels. That means some of the installations will not recognize the label and cancel the job. We can probably add a flag to disable this behavior. Let's do this in a separate ticket.

    @laxgoalie392

    opened by kichik 6
  • Git version problem with Ubuntu 18.04

    Git version problem with Ubuntu 18.04

    Problem

    Because the images use ubuntu:18.04, the git version is 2.17.1, checkout@v3 throws this warning message:

    The repository will be downloaded using the GitHub REST API
    To create a local Git repository instead, add Git 2.18 or higher to the PATH
    

    This causes some problems with committing inside the self-hosted runner, meaning you will get an error like this when you try to commit:

    fatal: not a git repository (or any of the parent directories): .git
    

    I don't know if there's a specific reason we use 18.04 but is it possible to bump the ubuntu version to 20.04 since it is LTS as well?

    opened by sercantor 6
  • feat: Ec2Runner VPC selection

    feat: Ec2Runner VPC selection

    I just tried out to use the EC2 runners. Within our accounts we do not have a default VPC which leads to the stack can not be deployed.

    const ec2Provider = new Ec2Runner(this, "ec2Runner", {
          subnet: subnets[0],
          spot: true,
        })
    
    10:28:42 AM | CREATE_FAILED        | AWS::ImageBuilder::Image                       | Dev/GitHubRunners/...mage Builder/Image
    Resource handler returned message: "Error occurred during operation 'No default VPC for this user. GroupName is only supported for EC2-Classic and default VPC.'." (RequestToken: ...., Handle
    rErrorCode: GeneralServiceException)
    

    Currently the Ec2RunnerProps also do not provide the option to set a VPC.

    https://github.com/CloudSnorkel/cdk-github-runners/blob/main/src/providers/ec2.ts#L126-L186

    opened by fwerkmeister 5
  • feat: Allow full customization of runner images and periodically update them

    feat: Allow full customization of runner images and periodically update them

    Build images in AWS using CodeBuild (or any user configured method) so that:

    1. We can automatically update images on a schedule to get the latest runner version and latest OS updates.
    2. We can build any type of image independent of the deployment platform. This will make it easy to provide Windows or ARM images (closes #7).
    3. We can expose an interface allowing the user to easily modify the Docker images by adding packages or commands to the build process (closes #26).

    BREAKING CHANGE: providers no longer take runner version directly

    auto-approve 
    opened by kichik 4
  • feat: Support multiple labels per-provider

    feat: Support multiple labels per-provider

    Allow user to ask for multiple labels for each provider instead of just one. This allows easier usage of runners without remembering specific order of parameters in a label. For example users can use runs-on: [self-hosted, windows, x64, team1] instead of runs-on: [self-hosted, windows-team1-x64].

    Resolves #128

    auto-approve 
    opened by kichik 3
  • bug: ContainerImageBuilder - cannot find image for Windows

    bug: ContainerImageBuilder - cannot find image for Windows

    Hey @kichik,

    can`t get that image - maybe because I`m in another region .. eu-central-1 I wanted to build a windows container image for codebuild ...

    code

        const windowsDefaultImage = new ContainerImageBuilder(
          this,
          `${props.serviceName}-${props.stage}-windows-image`,
          {
            architecture: Architecture.X86_64,
            os: Os.WINDOWS,
            runnerVersion: RunnerVersion.latest(),
            rebuildInterval: Duration.days(14),
            instanceType: ec2.InstanceType.of(
              ec2.InstanceClass.T3A,
              ec2.InstanceSize.LARGE
            ),
          }
        );
    

    error:

    The following required resource 'Image' cannot be found: 'arn:aws:imagebuilder:us-east-1:aws:image/windows-server-20
    19-x86-core-ltsc2019-amd64/2020.12.8'
    
    opened by pharindoko 3
  • [Question] How do I utilize the role that a codebuild runner is using?

    [Question] How do I utilize the role that a codebuild runner is using?

    I'm using a codebuild runner and trying to run an action that relies on aws credentials.

    i've tried using the following step in my workflow:

    - name: Test
      run: aws sts get-caller-identity
    

    but i end up getting the following error:

    Unable to locate credentials. You can configure credentials by running "aws configure".
    

    I also tried using the aws configure credentials action but am hitting basically the same error

    - name: AWS Secure Access
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-region: us-east-1
    

    My first impression was that I would be able to inherit the role that the codebuild runner was using

    opened by laxgoalie392 3
  • fix: Overlong agentName error from GitHub

    fix: Overlong agentName error from GitHub

    Ran into an issue where my org name + project name were 66 characters; GitHub errors if it's more than 64. This truncates that edge case at the cost of a couple bits of entropy from a UUID.

    opened by QuinnyPig 3
  • Should EC2 default to non-spot when spot is not available?

    Should EC2 default to non-spot when spot is not available?

    The following error is produced in SFN, when the spot is not available:

    {
      "resourceType": "aws-sdk:ec2",
      "resource": "runInstances.waitForTaskToken",
      "error": "Ec2.Ec2Exception",
      "cause": "There is no Spot capacity available that matches your request. (Service: Ec2, Status Code: 500, Request ID: 5b80a392-c6eb-42d1-99e9-d36db1909cf4)"
    }
    

    Catching this error, and then defaulting to non-spot would be optimal.

    Otherwise, GitHub runners continue running, waiting to be completed and nothing happens.

    opened by moltar 4
  • Re-use EC2 runner instances

    Re-use EC2 runner instances

    Does it make sense to launch multiple EC2 instances for each workflow?

    This really slows the process down. I think ideally it should launch one instance, and then re-use it for all runs, and then when idle - shut down.

    opened by moltar 9
  • Do not try to delete idle providers if no runner label match

    Do not try to delete idle providers if no runner label match

    There was no label match, yet the state machine still waits to reap idle providers. No real harm here, but I think it'd be more optimized if it didn't wait in the cases where there was no match.

    In fact, ideally, I think this selection should as early as possible.

    screenshot-20221215T163236-pJUkKUi2@2x
    opened by moltar 1
  • Bug: multi-labels don`t work as expected

    Bug: multi-labels don`t work as expected

    I added the ec2 runner for test ...

    cdk code:

        const cloudPlatformsEc2Runner = new Ec2Runner(
          this,
          `${props.serviceName}-${props.stage}-ec2-runner`,
          {
            labels: ["cloudplatforms", "ec2"],
            vpc: existingVpc,
            subnetSelection: vpcSubnets,
            spot: true,
            instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
          }
        );
    

    workflow.yml:

    name: fargate example
    on: workflow_dispatch
    jobs:
      self-hosted:
        runs-on: [self-hosted,cloudplatforms,ec2]
        steps:
          - run: echo hello world
    

    stepfunctions:

    these labels have been transmitted:

      "labels": {
        "self-hosted": true,
        "cloudplatforms": true,
        "ec2": true
      },
    

    result:

    it`s taking the wrong label :O

    image

    I assume because of this weird parent label image

    opened by pharindoko 3
Releases(v0.7.4)
Owner
CloudSnorkel
We do cool AWS stuff and way too much CloudFormation
CloudSnorkel
Easy-to-use CDK constructs for monitoring your AWS infrastructure

CDK Monitoring Constructs Easy-to-use CDK constructs for monitoring your AWS infrastructure. Easily add commonly-used alarms using predefined properti

CDK Labs at AWS 214 Jan 6, 2023
Deploy an Architect project from GitHub Actions with keys gathered from aws-actions/configure-aws-credentials

Deploy an Architect project from GitHub Actions with keys gathered from a specific AWS IAM Role federated by an IAM OIDCProvider. CloudFormation to cr

Taylor Beseda 4 Apr 6, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Cloudy is a set of constructs for the AWS Cloud Development Kit that aim to improve the DX by providing a faster and type-safe code environment.

cloudy-ts These packages aren't yet published on npm. This is still highly experimental. Need to figure out a few things before releasing the first ve

Cristian Pallarés 5 Nov 3, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
A fancy self-hosted monitoring tool

Uptime Kuma It is a self-hosted monitoring tool like "Uptime Robot". Features Monitoring uptime for HTTP(s) / TCP / Ping. Fancy, Reactive, Fast UI/UX.

Louis Lam 27.4k Jan 3, 2023
A self-hosted solution for backing up and viewing backed up mobile photos

Photostore Photostore is a self-hosted, client-server solution for backing up, viewing and downloading photos. How it works The Photostore API (writte

null 38 Oct 25, 2022
A self-hosted, customizable and ad-free Google Search experience

Giggle A self-hosted, customizable and ad-free Google Search experience. What does it do? Giggle lets you run Google searches against allow- and block

Dan Lovelace 213 Dec 15, 2022
Self-hosted environment variable management platform

envplat - environment platform This project is under development. Please contact me for any information or collaboration. Self-hosted environment vari

Environment Platform 4 Apr 25, 2022
A self-hosted file sharing platform.

Pingvin Share Pingvin Share is a self-hosted file sharing platform made for the Appwrite Hackathon. ?? Showcase Demo: https://pingvin-share.dev.eliass

Elias Schneider 354 Jan 7, 2023
⛺️ Tipi is a homeserver for everyone! One command setup, one click installs for your favorites self-hosted apps. ✨

⛺️ Tipi — A personal homeserver for everyone ⚠️ Tipi is still at an early stage of development and issues are to be expected. Feel free to open an iss

Nicolas Meienberger 4.9k Jan 4, 2023
A self-hosted solution for creating/managing forms and applications.

Centox - Self-hosted form website It is a self-hosted solution for creating/managing forms and applications. Users can login using their Discord Accou

Simon Maribo 11 Dec 26, 2022
Self-hosted TOTP authenticator PWA with FIDO2 (WebAuthn)

pasu Self-hosted TOTP authenticator PWA with FIDO2 (WebAuthn) Features 2FA secrets stored in your own server instead of your own device Codes are gene

ソ瑠璃(soruly) 11 Nov 2, 2022
A self-hosted eBooks Library for your family or yourself.

What is BookStairs? BookStairs is an open-source personal EPUB library which was highly inspired by talebook, calibre-web and BookBrowser. It's design

BookStairs 5 Dec 29, 2022
SCAchat - A self-hosted chatting application

SCAchat is a self-hosted chatting application similar to AOL Instant Messenger. The chatting application is privacy-respecting and does not store any messages or user-data. Once a session has ended, all messages are gone.

Chadano 4 Jul 18, 2022
A self-hosted Thumbnail generator/finder which creates thumbnails based on folder names and google search results.

Thumba A self hosted Thumbnail generator/finder which creates thumbnails based on folder names and google search results. Description This project use

Norbert Takács 20 Dec 15, 2022
An open source, self-hosted, and entirely free solution to social media management.

An open source, self-hosted, and entirely free solution to social media management. Status ?? In Development ?? Shoutify is currently early in the dev

TechSquidTV 202 Dec 22, 2022
Self-hosted Slack bot to run your code snippets

slack-code-runner Self-hosted Slack bot to run your code snippets Prerequisites Docker Usage Create a new Slack app and add it to your workspace. You

Myeonghyeon Kim 5 Sep 14, 2022