Self hosted GitHub Actions Runner.
GitHub Actions allows you to host your own runners for actions. This project presents a docker container capable of setup, run and register itself on a Organization or Repository, being available to execute workflows.
This image depends on sysbox, an alternative OCI runtime. In that way we can have the Docker in a Docker (DinD) mechanism (since GitHub Actions can run containers) without all the serious issues of the traditional privileged
approach. You can install sysbox using stable packages/binaries or building from the source. In the later case do not forget do initialize it (/usr/local/sbin/sysbox
) or create a service do start it automatically every time you start your machine.
This image is available public at Docker Hub. To run it, you just need to:
cp .env-example .env # modify with your custom configuration, such as the PAT, Repostitory and Organization.
docker run --runtime sysbox-runc --name=gh-runner --rm --env-file=.env passeidireto/gh-runner
Note that the runtime
option is needed only if you do not have sysbox as your default runtime. Just wait while it registers itself. You will see this output shortly:
You can also see the runner registered at the repository on repo > settings > actions
:
After you kill the container (with ctrl+C or docker stop gh-runner
) you will see as it deregisters itself and stops:
Note that it won't be able to unregisters nicely if you docker kill
it or somehow send a SIGKILL
.
If you want it registered at organization level, just let the GITHUB_REPOSITORY
variable empty. See more about configuration variables at Environment Variables section. Also, keep in mind that you will need organization privilege levels to perform this action. More details are provided at Personal Access Token (PAT).
If you intend to use this image with ECS, be aware that they do not officially support custom runtimes yet. However, it is possible to use a custom AMI. You can use our public AMI with ECS Agent and sysbox installed:
aws ec2 describe-images --filters "Name=name,Values=passeidireto-ecs-sysbox*"
For a detailed example of how to use this image, you can check our CDK stack repository.
- You can set arbitrary names and register at organization or repository level
- The runner executes just one workflow and then it stops and unregisters itself
- You can have multiple runners in the same host
- Docker in a Docker (Dind) with sysbox
- ECS and Kubernetes Ready
- Label customization
The following scopes are necessary in order to register a runner at organization level:
admin:org
The following scopes are necessary in order to register at repository level:
repo
(all)read:public_key
(onadmin:public_key
)read:repo_hook
(onadmin:repo_hook
)admin:org_hook
notifications
workflow
Name | Description |
---|---|
RUNNER_NAME | Runner name. A random suffix will be generated to assert the uniqueness |
GITHUB_PERSONAL_TOKEN | Yours (or bot's) PAT |
GITHUB_OWNER | Organization's name (e.g. PasseiDireto). |
GITHUB_REPOSITORY | Repository's name (optional). |
RUNNER_LABELS | Comma separated list of labels. They will be passed to runner on setup time. |
The image has three basic components: the docker engine, runner dependencies and the runner listener:
Users of this approach should bear in mind that technically the GHA Runner does not even support container execution, although that's something they (and the community) want and are working into. The --ephemeral
flag recently added allows that runners configure themselves as available for one and just one job execution, making it easier to remove (and unconfigure) the container right after its execution.
Finally, we use dumb-init to manage the service execution. The most important feature is to deal with the SIGINT/SIGKILL
signals and how docker reacts to them. With this approach we properly stop and unregister the listener in most of the scenarios, such as scale in and out, to work with platforms like (ECS/Fargate/EC2) and Kubernetes. Otherwise, the runner would hang forever as Offline on the repository/organization.
We can resume the container's lifecycle as:
- Init (
docker run
) - Authentication (with the PAT and receiving a runner token)
- Runner repo/organization registration
- Waiting for taks (as long as needed)
- Workflow execution
- Interruption (
docker stop
or workflow conclusion )- Listener stop
- Unsregisters the container (using a new runner token, as the old one might be expired for long running tasks)
- Container removal
Some projects are trying to fill the lack of a official GHA Self Hosted Runners for containers and ephemeral approaches, such as ECS and Kubernetes. We can list some of them: