An open API service indexing awesome lists of open source software.

https://github.com/vmvarela/terraform-github-actions-runner-scale-set

This Terraform module simplifies the deployment of self-hosted GitHub Actions runners on any Kubernetes cluster. It uses the official Actions Runner Controller (ARC) to create and manage auto-scaling runner sets.
https://github.com/vmvarela/terraform-github-actions-runner-scale-set

actions-runner-controller terraform-module

Last synced: 8 days ago
JSON representation

This Terraform module simplifies the deployment of self-hosted GitHub Actions runners on any Kubernetes cluster. It uses the official Actions Runner Controller (ARC) to create and manage auto-scaling runner sets.

Awesome Lists containing this project

README

          

# GitHub Actions Runner Scale Set on Kubernetes

Terraform module that deploys self-hosted GitHub Actions runners on Kubernetes using the official [Actions Runner Controller (ARC)](https://github.com/actions/actions-runner-controller).

This module automates the deployment of:
- **ARC Controller**: Manages the lifecycle of runner scale sets
- **Runner Scale Sets**: Auto-scaling GitHub Actions runners
- **Runner Groups**: Organized runner access control (optional)
- **Authentication**: Support for both GitHub Apps and Personal Access Tokens

## Features

- ✅ Multiple scale sets with independent configurations
- ✅ Auto-scaling runners (min/max configuration)
- ✅ GitHub App or PAT authentication
- ✅ Private container registry support
- ✅ Runner group management with repository and workflow restrictions
- ✅ Flexible runner image configuration
- ✅ Container mode support (Docker-in-Docker or Kubernetes)
- ✅ Automatic namespace creation

## Usage

### Basic Example

```hcl
module "github_runners" {
source = "path/to/module"

github_org = "my-organization"
github_token = var.github_token
}
```

### Complete Example with Multiple Scale Sets

```hcl
module "github_runners" {
source = "path/to/module"

github_org = "my-organization"
github_token = var.github_token

controller = {
name = "arc-controller"
namespace = "arc-system"
create_namespace = true
version = "0.13.0"
}

scale_sets = {
"default-runners" = {
namespace = "arc-runners-default"
create_namespace = true
min_runners = 1
max_runners = 10
runner_image = "ghcr.io/actions/actions-runner:latest"
container_mode = "dind"
visibility = "all"
create_runner_group = true
}

"production-runners" = {
namespace = "arc-runners-prod"
create_namespace = true
min_runners = 2
max_runners = 20
runner_group = "production"
visibility = "selected"
repositories = ["repo1", "repo2"]
create_runner_group = true
}

"ci-runners" = {
namespace = "arc-runners-ci"
create_namespace = true
min_runners = 3
max_runners = 15
runner_group = "ci"
visibility = "selected"
workflows = [".github/workflows/ci.yml"]
create_runner_group = true
}
}
}
```

### GitHub App Authentication

```hcl
module "github_runners" {
source = "path/to/module"

github_org = "my-organization"
github_app_id = 123456
github_app_installation_id = 789012
github_app_private_key = file("${path.module}/github-app-key.pem")
}
```

### Private Container Registry

```hcl
module "github_runners" {
source = "path/to/module"

github_org = "my-organization"
github_token = var.github_token

private_registry = "registry.example.com"
private_registry_username = var.registry_username
private_registry_password = var.registry_password

scale_sets = {
"custom-image-runners" = {
runner_image = "registry.example.com/custom/runner:latest"
}
}
}
```

## Requirements

| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.0 |
| [github](#requirement\_github) | ~> 6.0 |
| [helm](#requirement\_helm) | ~> 3.0 |
| [kubernetes](#requirement\_kubernetes) | ~> 2.0 |

## Providers

| Name | Version |
|------|---------|
| [github](#provider\_github) | ~> 6.0 |
| [helm](#provider\_helm) | ~> 3.0 |
| [kubernetes](#provider\_kubernetes) | ~> 2.0 |

## Resources

| Name | Type |
|------|------|
| [github_actions_runner_group.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_runner_group) | resource |
| [helm_release.controller](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
| [helm_release.scale_set](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
| [kubernetes_namespace.controller](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
| [kubernetes_namespace.scale_set](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
| [kubernetes_secret.github_creds](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
| [kubernetes_secret.private_registry_creds](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
| [github_repositories.all](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/repositories) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [github\_org](#input\_github\_org) | GitHub organization name | `string` | n/a | yes |
| [controller](#input\_controller) | Controller configuration |

object({
name = optional(string, "arc")
namespace = optional(string, "arc-systems")
create_namespace = optional(bool, true)
version = optional(string, "0.13.0")
})
|
{
"name": "arc",
"namespace": "arc-systems",
"create_namespace": true,
"version": "0.13.0"
}
| no |
| [scale\_sets](#input\_scale\_sets) | Scale sets configuration (map) |
map(object({
runner_group = optional(string, null)
create_runner_group = optional(bool, true)
namespace = optional(string, "arc-runners")
create_namespace = optional(bool, true)
version = optional(string, "0.13.0")
min_runners = optional(number, 1)
max_runners = optional(number, 5)
runner_image = optional(string, "ghcr.io/actions/actions-runner:latest")
pull_always = optional(bool, true)
container_mode = optional(string, "dind")
visibility = optional(string, "all")
workflows = optional(list(string), null)
repositories = optional(list(string), null)
}))
|
{
"arc-runner-set": {
"runner_group": null,
"create_runner_group": true,
"namespace": "arc-runners",
"create_namespace": true,
"version": "0.13.0",
"min_runners": 1,
"max_runners": 5,
"runner_image": "ghcr.io/actions/actions-runner:latest",
"pull_always": true,
"container_mode": "dind",
"visibility": "all",
"workflows": null,
"repositories": null
}
}
| no |
| [github\_token](#input\_github\_token) | GitHub Token (use either token or GitHub App credentials) | `string` | `null` | no |
| [github\_app\_id](#input\_github\_app\_id) | GitHub App ID (use either token or GitHub App credentials) | `number` | `null` | no |
| [github\_app\_installation\_id](#input\_github\_app\_installation\_id) | GitHub App Installation ID | `number` | `null` | no |
| [github\_app\_private\_key](#input\_github\_app\_private\_key) | GitHub App private key (PEM format) | `string` | `null` | no |
| [github\_repositories](#input\_github\_repositories) | All repositories in the organization. If not provided, they will be fetched by the module | `any` | `null` | no |
| [private\_registry](#input\_private\_registry) | Private container registry URL | `string` | `null` | no |
| [private\_registry\_username](#input\_private\_registry\_username) | Private container registry username | `string` | `null` | no |
| [private\_registry\_password](#input\_private\_registry\_password) | Private container registry password | `string` | `null` | no |

## Outputs

| Name | Description |
|------|-------------|
| [controller](#output\_controller) | The Helm release name of the controller |
| [scale\_set](#output\_scale\_set) | List of scale set names created |

## Authentication Methods

This module supports two authentication methods with GitHub:

### Personal Access Token (PAT)

```hcl
module "github_runners" {
source = "path/to/module"
github_org = "my-organization"
github_token = var.github_token # Classic PAT with admin:org scope
}
```

**Required Scopes:**
- `admin:org` (for runner group management)
- `repo` (if managing repository runners)

### GitHub App

```hcl
module "github_runners" {
source = "path/to/module"
github_org = "my-organization"
github_app_id = var.github_app_id
github_app_installation_id = var.github_app_installation_id
github_app_private_key = file("github-app-key.pem")
}
```

**Required Permissions:**
- Repository permissions: `Actions: Read & Write`, `Administration: Read & Write`
- Organization permissions: `Self-hosted runners: Read & Write`

## Scale Set Configuration

### Container Modes

- **`dind`** (Docker-in-Docker): Runs Docker daemon inside the runner container
- **`kubernetes`**: Uses Kubernetes-native container execution
- **`null`**: No container mode (bare runner)

### Visibility Options

- **`all`**: Runners available to all repositories in the organization
- **`selected`**: Runners limited to specific repositories
- **`private`**: Runners available only to private repositories

### Runner Groups

Runner groups organize runners and control access:

```hcl
scale_sets = {
"backend-runners" = {
runner_group = "backend-team"
create_runner_group = true
visibility = "selected"
repositories = ["api", "database", "worker"]
workflows = [".github/workflows/deploy.yml"]
}
}
```

## Testing

This module includes comprehensive Terraform native tests using mock providers:

```bash
terraform test
```

Tests cover:
- Controller creation
- Multiple scale sets
- GitHub App authentication
- Private registry configuration
- Runner groups
- Variable validations
- Container modes
- Resource dependencies

## License

MIT License - see [LICENSE](LICENSE) for details.

## Contributing

Contributions are welcome! Please open an issue or submit a pull request.

## Authors

Created and maintained by [Your Name/Organization]