Skip to content

Commit

Permalink
runner: Add support for ruby/setup-ruby (actions#224)
Browse files Browse the repository at this point in the history
It turned out previous versions of runner images were unable to run actions that require `AGENT_TOOLSDIRECTORY` or `libyaml` to exist in the runner environment. One of notable examples of such actions is [`ruby/setup-ruby`](https://github.com/ruby/setup-ruby).

This change adds the support for those actions, by setting up AGENT_TOOLSDIRECTORY and installing libyaml-dev within runner images.
  • Loading branch information
mumoshu authored and erikkn committed Dec 7, 2020
1 parent 85c29a9 commit bb70019
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 20 deletions.
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ example-runnerdeploy2475h595fr mumoshu/actions-runner-controller-ci Running
example-runnerdeploy2475ht2qbr mumoshu/actions-runner-controller-ci Running
```

#### Autoscaling
### Autoscaling

#### Repository runners Autoscaling

`RunnerDeployment` can scale the number of runners between `minReplicas` and `maxReplicas` fields, depending on pending workflow runs.

Expand Down Expand Up @@ -241,6 +243,8 @@ The scale out performance is controlled via the manager containers startup `--sy
Additionally, the autoscaling feature has an anti-flapping option that prevents periodic loop of scaling up and down.
By default, it doesn't scale down until the grace period of 10 minutes passes after a scale up. The grace period can be configured by setting `scaleDownDelaySecondsAfterScaleUp`:

Please note that if your `RunnerDeployment` has the `Repository` key set, then do not use the `<owner/repository_name>` notation, only provide the `<repository_name>`.

```yaml
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
Expand All @@ -267,6 +271,36 @@ spec:
- summerwind/actions-runner-controller
```

#### Organization runners Autoscaling
To autoscale on an organizational level, you need to remove the `repositoryNames` mapping and leave it empty. The Github Actions API doesn’t offer an endpoint to check the currently queued workflows on an organizational level. The way how the controller tries to get around this is by - after each `sync-period` - select the repositories with the latest `pushed` time and check the Actions workflow queue of those repositories. At the moment, the controller checks the last 10 repositories.

Please note, in case you want to autoscale your organization runners, that you should modify your Github organization permissions accordingly; for instance, if you are using an organization PAT (Personal Access Token), update the permissions of your PAT to allow the controller to list all the repositories under your organization.

An example of scaling your organization runners is shown below:

```yaml
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
name: example-runnerdeploy
spec:
template:
spec:
organization: "your-organization-name"
---
apiVersion: actions.summerwind.dev/v1alpha1
kind: HorizontalRunnerAutoscaler
metadata:
name: example-runnerdeploy-autoscaler
spec:
scaleTargetRef:
name: example-runnerdeploy
minReplicas: 1
maxReplicas: 3
metrics:
- type: TotalNumberOfQueuedAndInProgressWorkflowRuns
```

## Runner with DinD

When using default runner, runner pod starts up 2 containers: runner and DinD (Docker-in-Docker). This might create issues if there's `LimitRange` set to namespace.
Expand Down Expand Up @@ -321,7 +355,7 @@ spec:
requests:
cpu: "2.0"
memory: "4Gi"
# If set to false, there are no privileged container and you cannot use docker.
# If set to false, there are no privileged container and you cannot use docker.
dockerEnabled: false
# If set to true, runner pod container only 1 container that's expected to be able to run docker, too.
# image summerwind/actions-runner-dind or custom one should be used with true -value
Expand Down
65 changes: 47 additions & 18 deletions controllers/autoscaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package controllers

import (
"context"
"errors"
"fmt"
"log"
"strings"

"github.com/google/go-github/v32/github"
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
)

Expand All @@ -18,30 +19,58 @@ func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alp

var repos [][]string

repoID := rd.Spec.Template.Spec.Repository
if repoID == "" {
orgName := rd.Spec.Template.Spec.Organization
if orgName == "" {
return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
}
orgName := rd.Spec.Template.Spec.Organization
if orgName == "" {
return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
}

metrics := hra.Spec.Metrics
if len(metrics) == 0 {
return nil, fmt.Errorf("validating autoscaling metrics: one or more metrics is required")
} else if tpe := metrics[0].Type; tpe != v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q: only supported value is %s", tpe, v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns)
}

metrics := hra.Spec.Metrics
if len(metrics[0].RepositoryNames) == 0 {
options := &github.RepositoryListByOrgOptions{
Type: "private",
Sort: "pushed",
}
orgRepos, _, err := r.GitHubClient.Repositories.ListByOrg(context.Background(), orgName, options)
if err != nil {
return nil, fmt.Errorf("[ERROR] error fetching a list of repositories for the %s organization with error message: %s", orgName, err)
}

if len(metrics) == 0 {
return nil, fmt.Errorf("validating autoscaling metrics: one or more metrics is required")
} else if tpe := metrics[0].Type; tpe != v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q: only supported value is %s", tpe, v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns)
} else if len(metrics[0].RepositoryNames) == 0 {
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].repositoryNames is required and must have one more more entries for organizational runner deployment")
if len(orgRepos) < 1 {
return nil, fmt.Errorf("[ERROR] ListByOrg returned empty slice! Does your PAT have enough access and is it authorized to list the organizational repositories?")
}

for _, repoName := range metrics[0].RepositoryNames {
for _, v := range orgRepos {
repoName := fmt.Sprint(*v.Name)

// We kind of already make sure that we don't use these repo's by using the `ListByOrgOptions` field, this is just an extra safeguard.
if *v.Archived || *v.Disabled {
continue
}

// Some organizations have hundreds to thousands of repositories; we only need the X most recent ones.
if len(repos) >= 10 {
log.Printf("[INFO] Reached the limit of repos, performing check on these repositories: %s", repos)
break
}
repos = append(repos, []string{orgName, repoName})
}
log.Printf("[INFO] watching the following organizational repositories: %s", repos)
} else {
repo := strings.Split(repoID, "/")

repos = append(repos, repo)
repoID := rd.Spec.Template.Spec.Repository
if repoID == "" {
for _, repoName := range metrics[0].RepositoryNames {
repos = append(repos, []string{orgName, repoName})
}
} else {
repo := strings.Split(repoID, "/")
repos = append(repos, repo)
}
}

var total, inProgress, queued, completed, unknown int
Expand Down

0 comments on commit bb70019

Please sign in to comment.