Allow disabling /runner emptydir mounts and setting storage volume (#674)

* Allow disabling /runner emptydir mounts

* Support defining storage medium for emptydirs

* Fix typos
This commit is contained in:
Rolf Ahrenberg 2021-07-15 00:29:58 +03:00 committed by GitHub
parent 7f2795b5d6
commit 14564c7b8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 58 additions and 18 deletions

View File

@ -961,13 +961,13 @@ spec:
As it is based on `StatefulSet`, `selector` and `template.medatada.labels` needs to be defined and haev the exact same set of labels. `serviceName` must be set to some non-empty string as it is also required by `StatefulSet`.
Runner-related fields like `ephemeral`, `repository`, `organiåtion`, `enterprise`, and so on should be written directly under `spec`.
Runner-related fields like `ephemeral`, `repository`, `organization`, `enterprise`, and so on should be written directly under `spec`.
Fields like `volumeClaimTemplates` that originates from `StatefulSet` shuold also be written directly under `spec`.
Fields like `volumeClaimTemplates` that originates from `StatefulSet` should also be written directly under `spec`.
Pod-related fields like security contexts and volumes are written under `spec.template.spec` like `StatefulSet`.
Simillarly, container-related fields like resource requests and limits, container image names and tags, security context, and so on are written under `spec.template.spec.containers`. There are two reserved container `name`, `runner` and `docker`. The former is for the container that runs [actions runner](https://github.com/actions/runner) and the latter is for the container that runs a dockerd.
Similarly, container-related fields like resource requests and limits, container image names and tags, security context, and so on are written under `spec.template.spec.containers`. There are two reserved container `name`, `runner` and `docker`. The former is for the container that runs [actions runner](https://github.com/actions/runner) and the latter is for the container that runs a dockerd.
For a more complex example, see the below:
@ -1018,7 +1018,7 @@ https://github.com/actions-runner-controller/actions-runner-controller/pull/629
Under the hood, `RunnerSet` relies on Kubernetes's `StatefulSet` and Mutating Webhook. A statefulset is used to create a number of pods that has stable names and dynamically provisioned persistent volumes, so that each statefulset-managed pod gets the same persisntet volume even after restarting. A mutating webhook is used to dynamically inject a runner's "registration token" which is used to call GitHub's "Create Runner" API.
We envision that `RunnerSet` will eventually replaces `RunnerDeployment`, as `RunnerSet` provides a more standard API that is easy to learn and use because it is based on `StatefulSet`, and it has a support for `volumeClaimTemplates` which is crucial to manage dynamically provisioned persistent volumes.
We envision that `RunnerSet` will eventually replace `RunnerDeployment`, as `RunnerSet` provides a more standard API that is easy to learn and use because it is based on `StatefulSet`, and it has a support for `volumeClaimTemplates` which is crucial to manage dynamically provisioned persistent volumes.
### Software Installed in the Runner Image

View File

@ -69,6 +69,8 @@ type RunnerConfig struct {
DockerRegistryMirror *string `json:"dockerRegistryMirror,omitempty"`
// +optional
VolumeSizeLimit *resource.Quantity `json:"volumeSizeLimit,omitempty"`
// +optional
VolumeStorageMedium *string `json:"volumeStorageMedium,omitempty"`
}
// RunnerPodSpec defines the desired pod spec fields of the runner pod

View File

@ -408,6 +408,11 @@ func (in *RunnerConfig) DeepCopyInto(out *RunnerConfig) {
x := (*in).DeepCopy()
*out = &x
}
if in.VolumeStorageMedium != nil {
in, out := &in.VolumeStorageMedium, &out.VolumeStorageMedium
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfig.

View File

@ -984,6 +984,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
volumes:
items:
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.

View File

@ -981,6 +981,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
volumes:
items:
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.

View File

@ -927,6 +927,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
volumes:
items:
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.

View File

@ -7113,6 +7113,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
workDir:
type: string
required:

View File

@ -984,6 +984,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
volumes:
items:
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.

View File

@ -981,6 +981,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
volumes:
items:
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.

View File

@ -927,6 +927,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
volumes:
items:
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.

View File

@ -7113,6 +7113,8 @@ spec:
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
volumeStorageMedium:
type: string
workDir:
type: string
required:

View File

@ -886,32 +886,49 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
// When you're NOT using dindWithinRunner=true,
// it must also be shared with the dind container as it seems like required to run docker steps.
//
// Setting VolumeSizeLimit to zero will disable /runner emptydir mount
//
// VolumeStorageMedium defines ways that storage can be allocated to a volume: "", "Memory", "HugePages", "HugePages-<size>"
//
runnerVolumeName := "runner"
runnerVolumeMountPath := "/runner"
runnerVolumeEmptyDir := &corev1.EmptyDirVolumeSource{}
if runnerSpec.VolumeStorageMedium != nil {
runnerVolumeEmptyDir.Medium = corev1.StorageMedium(*runnerSpec.VolumeStorageMedium)
}
if runnerSpec.VolumeSizeLimit != nil {
runnerVolumeEmptyDir.SizeLimit = runnerSpec.VolumeSizeLimit
}
pod.Spec.Volumes = append(pod.Spec.Volumes,
corev1.Volume{
Name: runnerVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: runnerVolumeEmptyDir,
if runnerSpec.VolumeSizeLimit == nil || !runnerSpec.VolumeSizeLimit.IsZero() {
pod.Spec.Volumes = append(pod.Spec.Volumes,
corev1.Volume{
Name: runnerVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: runnerVolumeEmptyDir,
},
},
},
)
)
runnerContainer.VolumeMounts = append(runnerContainer.VolumeMounts,
corev1.VolumeMount{
Name: runnerVolumeName,
MountPath: runnerVolumeMountPath,
},
)
runnerContainer.VolumeMounts = append(runnerContainer.VolumeMounts,
corev1.VolumeMount{
Name: runnerVolumeName,
MountPath: runnerVolumeMountPath,
},
)
}
if !dockerdInRunner && dockerEnabled {
if runnerSpec.VolumeSizeLimit != nil && runnerSpec.VolumeSizeLimit.IsZero() {
return *pod, fmt.Errorf(
"%s volume can't be disabled because it is required to share the working directory between the runner and the dockerd containers",
runnerVolumeName,
)
}
pod.Spec.Volumes = append(pod.Spec.Volumes,
corev1.Volume{
Name: "work",

View File

@ -203,7 +203,7 @@ func main() {
log.Info(
"Initializing actions-runner-controller",
"github-api-cahce-duration", gitHubAPICacheDuration,
"github-api-cache-duration", gitHubAPICacheDuration,
"sync-period", syncPeriod,
"runner-image", runnerImage,
"docker-image", dockerImage,