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:
parent
7f2795b5d6
commit
14564c7b8e
|
|
@ -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`.
|
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`.
|
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:
|
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.
|
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
|
### Software Installed in the Runner Image
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ type RunnerConfig struct {
|
||||||
DockerRegistryMirror *string `json:"dockerRegistryMirror,omitempty"`
|
DockerRegistryMirror *string `json:"dockerRegistryMirror,omitempty"`
|
||||||
// +optional
|
// +optional
|
||||||
VolumeSizeLimit *resource.Quantity `json:"volumeSizeLimit,omitempty"`
|
VolumeSizeLimit *resource.Quantity `json:"volumeSizeLimit,omitempty"`
|
||||||
|
// +optional
|
||||||
|
VolumeStorageMedium *string `json:"volumeStorageMedium,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerPodSpec defines the desired pod spec fields of the runner pod
|
// RunnerPodSpec defines the desired pod spec fields of the runner pod
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,11 @@ func (in *RunnerConfig) DeepCopyInto(out *RunnerConfig) {
|
||||||
x := (*in).DeepCopy()
|
x := (*in).DeepCopy()
|
||||||
*out = &x
|
*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.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfig.
|
||||||
|
|
|
||||||
|
|
@ -984,6 +984,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
|
|
|
||||||
|
|
@ -981,6 +981,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
|
|
|
||||||
|
|
@ -927,6 +927,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
|
|
|
||||||
|
|
@ -7113,6 +7113,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
workDir:
|
workDir:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|
|
||||||
|
|
@ -984,6 +984,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
|
|
|
||||||
|
|
@ -981,6 +981,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
|
|
|
||||||
|
|
@ -927,6 +927,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
volumes:
|
volumes:
|
||||||
items:
|
items:
|
||||||
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
description: Volume represents a named volume in a pod that may be accessed by any container in the pod.
|
||||||
|
|
|
||||||
|
|
@ -7113,6 +7113,8 @@ spec:
|
||||||
- type: string
|
- type: string
|
||||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
x-kubernetes-int-or-string: true
|
x-kubernetes-int-or-string: true
|
||||||
|
volumeStorageMedium:
|
||||||
|
type: string
|
||||||
workDir:
|
workDir:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|
|
||||||
|
|
@ -886,32 +886,49 @@ func newRunnerPod(template corev1.Pod, runnerSpec v1alpha1.RunnerConfig, default
|
||||||
// When you're NOT using dindWithinRunner=true,
|
// 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.
|
// 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"
|
runnerVolumeName := "runner"
|
||||||
runnerVolumeMountPath := "/runner"
|
runnerVolumeMountPath := "/runner"
|
||||||
runnerVolumeEmptyDir := &corev1.EmptyDirVolumeSource{}
|
runnerVolumeEmptyDir := &corev1.EmptyDirVolumeSource{}
|
||||||
|
|
||||||
|
if runnerSpec.VolumeStorageMedium != nil {
|
||||||
|
runnerVolumeEmptyDir.Medium = corev1.StorageMedium(*runnerSpec.VolumeStorageMedium)
|
||||||
|
}
|
||||||
|
|
||||||
if runnerSpec.VolumeSizeLimit != nil {
|
if runnerSpec.VolumeSizeLimit != nil {
|
||||||
runnerVolumeEmptyDir.SizeLimit = runnerSpec.VolumeSizeLimit
|
runnerVolumeEmptyDir.SizeLimit = runnerSpec.VolumeSizeLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
pod.Spec.Volumes = append(pod.Spec.Volumes,
|
if runnerSpec.VolumeSizeLimit == nil || !runnerSpec.VolumeSizeLimit.IsZero() {
|
||||||
corev1.Volume{
|
pod.Spec.Volumes = append(pod.Spec.Volumes,
|
||||||
Name: runnerVolumeName,
|
corev1.Volume{
|
||||||
VolumeSource: corev1.VolumeSource{
|
Name: runnerVolumeName,
|
||||||
EmptyDir: runnerVolumeEmptyDir,
|
VolumeSource: corev1.VolumeSource{
|
||||||
|
EmptyDir: runnerVolumeEmptyDir,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
|
|
||||||
runnerContainer.VolumeMounts = append(runnerContainer.VolumeMounts,
|
runnerContainer.VolumeMounts = append(runnerContainer.VolumeMounts,
|
||||||
corev1.VolumeMount{
|
corev1.VolumeMount{
|
||||||
Name: runnerVolumeName,
|
Name: runnerVolumeName,
|
||||||
MountPath: runnerVolumeMountPath,
|
MountPath: runnerVolumeMountPath,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if !dockerdInRunner && dockerEnabled {
|
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,
|
pod.Spec.Volumes = append(pod.Spec.Volumes,
|
||||||
corev1.Volume{
|
corev1.Volume{
|
||||||
Name: "work",
|
Name: "work",
|
||||||
|
|
|
||||||
2
main.go
2
main.go
|
|
@ -203,7 +203,7 @@ func main() {
|
||||||
|
|
||||||
log.Info(
|
log.Info(
|
||||||
"Initializing actions-runner-controller",
|
"Initializing actions-runner-controller",
|
||||||
"github-api-cahce-duration", gitHubAPICacheDuration,
|
"github-api-cache-duration", gitHubAPICacheDuration,
|
||||||
"sync-period", syncPeriod,
|
"sync-period", syncPeriod,
|
||||||
"runner-image", runnerImage,
|
"runner-image", runnerImage,
|
||||||
"docker-image", dockerImage,
|
"docker-image", dockerImage,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue