diff --git a/docs/pipelineruns.md b/docs/pipelineruns.md index 0d8fa9e8b79..bb8757b661b 100644 --- a/docs/pipelineruns.md +++ b/docs/pipelineruns.md @@ -216,6 +216,9 @@ allows to customize some Pod specific field per `Task` execution, aka - `volumes`: list of volumes that can be mounted by containers belonging to the pod. This lets the user of a Task define which type of volume to use for a Task `volumeMount` +- `runtimeClassName`: the name of a + [runtime class](https://kubernetes.io/docs/concepts/containers/runtime-class/) + to use to run the pod. In the following example, the Task is defined with a `volumeMount` (`my-cache`), that is provided by the PipelineRun, using a diff --git a/docs/taskruns.md b/docs/taskruns.md index 4250f6a511f..afaa2b5413b 100644 --- a/docs/taskruns.md +++ b/docs/taskruns.md @@ -186,7 +186,10 @@ allows to customize some Pod specific field per `Task` execution, aka - `volumes`: list of volumes that can be mounted by containers belonging to the pod. This lets the user of a Task define which type of volume to use for a Task `volumeMount` - +- `runtimeClassName`: the name of a + [runtime class](https://kubernetes.io/docs/concepts/containers/runtime-class/) + to use to run the pod. + In the following example, the Task is defined with a `volumeMount` (`my-cache`), that is provided by the TaskRun, using a PersistenceVolumeClaim. The Pod will also run as a non-root user. diff --git a/pkg/apis/pipeline/v1alpha1/pod.go b/pkg/apis/pipeline/v1alpha1/pod.go index c4e61458ac3..51cd147bdc7 100644 --- a/pkg/apis/pipeline/v1alpha1/pod.go +++ b/pkg/apis/pipeline/v1alpha1/pod.go @@ -45,4 +45,14 @@ type PodTemplate struct { // More info: https://kubernetes.io/docs/concepts/storage/volumes // +optional Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` + + // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io + // group, which should be used to run this pod. If no RuntimeClass resource + // matches the named class, the pod will not be run. If unset or empty, the + // "legacy" RuntimeClass will be used, which is an implicit class with an + // empty definition that uses the default runtime handler. + // More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md + // This is a beta feature as of Kubernetes v1.14. + // +optional + RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,2,opt,name=runtimeClassName"` } diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 7bc65cc3816..3da48c9eda2 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -1379,6 +1379,11 @@ func (in *PodTemplate) DeepCopyInto(out *PodTemplate) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.RuntimeClassName != nil { + in, out := &in.RuntimeClassName, &out.RuntimeClassName + *out = new(string) + **out = **in + } return } diff --git a/pkg/reconciler/taskrun/resources/pod.go b/pkg/reconciler/taskrun/resources/pod.go index f1e3f8b2494..eea57c256ed 100644 --- a/pkg/reconciler/taskrun/resources/pod.go +++ b/pkg/reconciler/taskrun/resources/pod.go @@ -355,6 +355,7 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha Tolerations: taskRun.Spec.PodTemplate.Tolerations, Affinity: taskRun.Spec.PodTemplate.Affinity, SecurityContext: taskRun.Spec.PodTemplate.SecurityContext, + RuntimeClassName: taskRun.Spec.PodTemplate.RuntimeClassName, }, }, nil } diff --git a/pkg/reconciler/taskrun/resources/pod_test.go b/pkg/reconciler/taskrun/resources/pod_test.go index f8e5c4efaa1..11049f6a6d0 100644 --- a/pkg/reconciler/taskrun/resources/pod_test.go +++ b/pkg/reconciler/taskrun/resources/pod_test.go @@ -117,6 +117,8 @@ func TestMakePod(t *testing.T) { VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "multi-creds"}}, }) + runtimeClassName := "gvisor" + randReader = strings.NewReader(strings.Repeat("a", 10000)) defer func() { randReader = rand.Reader }() @@ -209,6 +211,57 @@ func TestMakePod(t *testing.T) { }}, Volumes: implicitVolumesWithSecrets, }, + }, { + desc: "with-pod-template", + ts: v1alpha1.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "name", + Image: "image", + }}}, + }, + trs: v1alpha1.TaskRunSpec{ + PodTemplate: v1alpha1.PodTemplate{ + SecurityContext: &corev1.PodSecurityContext{ + Sysctls: []corev1.Sysctl{ + {Name: "net.ipv4.tcp_syncookies", Value: "1"}, + }, + }, + RuntimeClassName: &runtimeClassName, + }, + }, + want: &corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + InitContainers: []corev1.Container{{ + Name: containerPrefix + credsInit + "-9l9zj", + Image: credsImage, + Command: []string{"/ko-app/creds-init"}, + Args: []string{}, + Env: implicitEnvVars, + VolumeMounts: implicitVolumeMounts, + WorkingDir: workspaceDir, + }}, + Containers: []corev1.Container{{ + Name: "step-name", + Image: "image", + Env: implicitEnvVars, + VolumeMounts: implicitVolumeMounts, + WorkingDir: workspaceDir, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("0"), + corev1.ResourceMemory: resource.MustParse("0"), + corev1.ResourceEphemeralStorage: resource.MustParse("0"), + }, + }, + }}, + Volumes: implicitVolumes, + SecurityContext: &corev1.PodSecurityContext{ + Sysctls: []corev1.Sysctl{ + {Name: "net.ipv4.tcp_syncookies", Value: "1"}, + }, + }, + RuntimeClassName: &runtimeClassName, + }, }, { desc: "very-long-step-name", ts: v1alpha1.TaskSpec{