This project defines a Dockerfile
to run a self-hosted Github Actions runner.
The runner is hosted on Heroku as a docker image via heroku.yml
.
Once the self-hosted runner is running on Heroku you can start adding workflows to your private GitHub repositories (see this project template as an example) to automate Heroku Review Apps creation and Heroku Apps deploys using the following actions:
- https://github.com/abernicchia-heroku/heroku-review-apps-action
- https://github.com/abernicchia-heroku/heroku-sources-endpoint-deploy-action
The Heroku self-hosted runner will autoregister with your GitHub Org (1). When git push / pull-request commands are executed toward your private GitHub repository (2) your workflows will trigger the code fetch from your repository (3).
The source code will be automatically compressed and uploaded to a temporary Heroku bucket (4) then built and deployed to your apps (5). When a pull request is created a new Review App is created and once it is closed the associated Review App is automatically removed.
The author of this article makes any warranties about the completeness, reliability and accuracy of this information. Any action you take upon the information of this website is strictly at your own risk, and the author will not be liable for any losses and damages in connection with the use of the website and the information provided. None of the items included in this repository form a part of the Heroku Services.
Things you'll need
- Administrator access to your GitHub organization
- Administrator access to your Heroku organization
- GitHub personal access token (classic) with admin:org and repo scopes or fine-grained token with "Self-hosted runners" organization permissions (read and write) (see https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization)
- Heroku API token from a non-SSO user (service/automation user) with view and deploy access
- Heroku CLI
- Git CLI
The setup requires configurations in both your GitHub organization and your Heroku organization.
You will switch between them throughout the following instructions.
-
In GitHub, enable GitHub Actions for your organization
- https://github.com/organizations/{YOUR_ORGANIZATION}/settings/actions
- Under Policies
- Choose Allow {YOUR_ORGANIZATION}, and select non-{YOUR_ORGANIZATION}, actions and reusable workflows
- Select Allow actions created by GitHub
- Click Save
-
In GitHub, add your Heroku Private Space's outbound IP addresses to your organization's allow list (see this article) and check the Enable IP allow list box
-
In GitHub, create a personal access token with admin:org and repo scopes (see these articles 1, 2) or a fine-grained token with "Self-hosted runners" organization permissions (read and write) (see https://github.blog/security/application-security/introducing-fine-grained-personal-access-tokens-for-github/#creating-personal-access-tokens). This token will be used only to configure the runner. Authenticated users must have admin access to the organization. (see https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization).
Don't forget to authorize your access token to SSO to your organization
-
In Heroku, create a new app in your private space
-
In Heroku, add two configuration variables to the new app
GITHUB_ACCESS_TOKEN
with the token you created previouslyGITHUB_ORGANIZATION
with the name of your organization
-
From the Heroku CLI login as the service/automation Heroku user to create an API token (SSO users cannot create tokens)
-
Generate a new Heroku API key
heroku authorizations:create -d "GitHub self-hosted actions automation" --expires-in=<set expiration time in seconds>
setting an adequate expiration time
-
Login as the Heroku administrator and grant the service/automation Heroku user access to view and deploy to your new app
-
In GitHub, add an organization secret to store the Heroku information
- https://github.com/organizations/{YOUR_ORGANIZATION}/settings/secrets/actions
HEROKU_API_KEY
with the api key you created previously
-
In GitHub, add an organization/repository variable to store the Heroku self-hosted runner app name
- https://github.com/organizations/{YOUR_ORGANIZATION}/settings/variables/actions
- https://github.com/{YOUR_ORGANIZATION}/{YOUR_REPOSITORY}/settings/variables/actions
HEROKU_SELFHOSTED_RUNNER_APPNAME
with the name of the Heroku self-hosted runner app
-
Locally, clone and deploy this repository to your Heroku app or click on the Heroku Button
git clone https://github.com/abernicchia-heroku/heroku-github-actions-runner.git heroku git:remote --app HEROKU_SELFHOSTED_RUNNER_APPNAME heroku apps:stacks:set --app HEROKU_SELFHOSTED_RUNNER_APPNAME container git push heroku main
-
In Heroku, scale your runner resource appropriate for your expected usage
- https://dashboard.heroku.com/apps/{YOUR_APP}/resources
- A single dyno can run one GitHub Actions job at a time
- Recommended: Private-M dyno type scaled to 4 dynos
Voila!
Now when GitHub Action workflows are launched by your repositories, GitHub will orchestrate with your Heroku-hosted runner to do the work just as if you were using GitHub-hosted runners.
GitHub frequently releases updates to the GitHub Action runner package.
If you don't keep the package up-to-date within 30 days then GitHub won't enqueue jobs.
This project includes a workflow that can be run manually or once a week. It will rebuild the docker container and download the latest updates automatically and it will deploy automatically to your Heroku self-hosted runner app.
To take advantage of this automation you need to fork or mirror this repository to your private organisation's repository and enable workflows run.
The following is how to use the config.sh
and run.sh
scripts installed by the runner package (see https://github.com/actions/runner/blob/main/src/Runner.Listener/Runner.cs).
Commands:
./config.sh Configures the runner
./config.sh remove Unconfigures the runner
./run.sh Runs the runner interactively. Does not require any options.
Options:
--help Prints the help for each command
--version Prints the runner version
--commit Prints the runner commit
--check Check the runner's network connectivity with GitHub server
Config Options:
--unattended Disable interactive prompts for missing arguments. Defaults will be used for missing options
--url string Repository to add the runner to. Required if unattended
--token string Registration token. Required if unattended
--name string Name of the runner to configure (default hostname on Linux - from C# Environment.MachineName)
--runnergroup string Name of the runner group to add this runner to (defaults to the default runner group)
--labels string Custom labels that will be added to the runner. This option is mandatory if --no-default-labels is used.
--no-default-labels Disables adding the default labels: e.g. 'self-hosted,Linux,X64'
--local Removes the runner config files from your local machine. Used as an option to the remove command
--work string Relative runner work directory (default _work)
--replace Replace any existing runner with the same name (default false)
--pat GitHub personal access token with repo scope. Used for checking network connectivity when executing `./run.sh --check`
--disableupdate Disable self-hosted runner automatic update to the latest released version`
--ephemeral Configure the runner to only take one job and then let the service un-configure the runner after the job finishes (default false);
Examples:
Check GitHub server network connectivity:
./run.sh --check --url <url> --pat <pat>
Configure a runner non-interactively:
./config.sh --unattended --url <url> --token <token>
Configure a runner non-interactively, replacing any existing runner with the same name:
./config.sh --unattended --url <url> --token <token> --replace [--name <name>]
Configure a runner non-interactively with three extra labels:
./config.sh --unattended --url <url> --token <token> --labels L1,L2,L3;
This new release:
- uses a new GitHub Action to build and deploy the runner on Heroku using the sources endpoint API. This action allows you to deploy code living on GitHub repositories, even private, to apps running on Heroku without requiring the Heroku GitHub integration
- uses ephemeral containers to allow autoscaling and hardening of self-hosted runners. Ephemeral runners are short-lived containers that are executed only once for a single job, providing isolated environments to reduce the risk of data leakage
- logs the self-runner name to manage it from the GitHub dashboard
- reduces the Docker image footprint and it's possible to run it as one-off dyno (CMD vs. ENTRYPOINT)
- includes all the recent GitHub self-hosted runners features and streamlines the configuration and setup
- integrates the Heroku Button to install the runner in one-click
- supports fine-grained GitHub tokens
Credits to the owner of the original project that inspired this new updated version.