Skip to content

Commit 3268eaf

Browse files
committed
Allow setting sidecar ready annotation early
If no sidercars are present, we can set the `tekton.dev/ready` annotation during pod creation itself instead waiting for the controller to set it after pod creation. This commit adds an option to the `feature-flags` ConfigMap to control this behavior (`enable-ready-annotation-on-pod-create`). By default, the option is set to "false".Setting this flag to "true" will set the annotation at pod creation time for Taskruns without Sidercars. Enabling this option should decrease the time it takes for a TaskRun to start running. However, for clusters that use injected sidecars e.g. istio enabling this option can lead to unexpected behavior. Fixes #2080 Signed-off-by: Dibyo Mukherjee <[email protected]>
1 parent 8f427a8 commit 3268eaf

File tree

4 files changed

+260
-32
lines changed

4 files changed

+260
-32
lines changed

config/config-feature-flags.yaml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ data:
2525
# $HOME environment variable but this will change in an upcoming
2626
# release.
2727
#
28-
# See https://github.com/tektoncd/pipeline/issues/2013 for more
29-
# info.
28+
# See https://github.com/tektoncd/pipeline/issues/2013 for more info.
3029
disable-home-env-overwrite: "false"
3130
# Setting this flag to "true" will prevent Tekton overriding your
3231
# Task container's working directory.
@@ -35,6 +34,15 @@ data:
3534
# working directory if not set by the user but this will change
3635
# in an upcoming release.
3736
#
38-
# See https://github.com/tektoncd/pipeline/issues/1836 for more
39-
# info.
37+
# See https://github.com/tektoncd/pipeline/issues/1836 for more info.
4038
disable-working-directory-overwrite: "false"
39+
40+
# Setting this flag to "true" will set the `tekton.dev/ready` annotation
41+
# at pod creation time for Taskruns without sidecars.
42+
#
43+
# Enabling this option should decrease the time it takes for a TaskRun to
44+
# start running. However, for clusters that use injected sidecars e.g. istio
45+
# enabling this option can lead to unexpected behavior.
46+
#
47+
# See https://github.com/tektoncd/pipeline/issues/2080 for more info.
48+
enable-ready-annotation-on-pod-create: "false"

docs/install.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,12 @@ The default value is `false`, which causes Tekton to override the working direct
273273
for each `Step` that does not have its working directory explicitly set with `/workspace`.
274274
For more information, see the [associated issue](https://github.com/tektoncd/pipeline/issues/1836).
275275

276+
- `enable-ready-annotation-on-pod-create`: set this flag to `"true"` to allow the
277+
Tekton controller to set the `tekon.dev/ready` annotation at pod creation time for
278+
TaskRuns with no Sidecars specified. Enabling this option should decrease the time it takes for a TaskRun to
279+
start running. However, for clusters that use injected sidecars e.g. istio
280+
enabling this option can lead to unexpected behavior.
281+
276282
For example:
277283

278284
```yaml

pkg/pod/pod.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
2424
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
25+
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
2526
"github.com/tektoncd/pipeline/pkg/names"
2627
"github.com/tektoncd/pipeline/pkg/system"
2728
"github.com/tektoncd/pipeline/pkg/version"
@@ -37,9 +38,10 @@ const (
3738
// ResultsDir is the folder used by default to create the results file
3839
ResultsDir = "/tekton/results"
3940

40-
featureFlagConfigMapName = "feature-flags"
41-
featureFlagDisableHomeEnvKey = "disable-home-env-overwrite"
42-
featureFlagDisableWorkingDirKey = "disable-working-directory-overwrite"
41+
featureFlagConfigMapName = "feature-flags"
42+
featureFlagDisableHomeEnvKey = "disable-home-env-overwrite"
43+
featureFlagDisableWorkingDirKey = "disable-working-directory-overwrite"
44+
featureFlagSetReadyAnnotationOnPodCreate = "enable-ready-annotation-on-pod-create"
4345

4446
taskRunLabelKey = pipeline.GroupName + pipeline.TaskRunLabelKey
4547
)
@@ -224,6 +226,10 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha
224226
podAnnotations := taskRun.Annotations
225227
podAnnotations[ReleaseAnnotation] = ReleaseAnnotationValue
226228

229+
if shouldAddReadyAnnotationonPodCreate(taskSpec.Sidecars, kubeclient) {
230+
podAnnotations[readyAnnotation] = readyAnnotationValue
231+
}
232+
227233
return &corev1.Pod{
228234
ObjectMeta: metav1.ObjectMeta{
229235
// We execute the build's pod in the same namespace as where the build was
@@ -336,3 +342,22 @@ func shouldOverrideWorkingDir(kubeclient kubernetes.Interface) bool {
336342
}
337343
return true
338344
}
345+
346+
// shouldAddReadyAnnotationonPodCreate returns a bool indicating whether the
347+
// controller should add the `Ready` annotation when creating the Pod. The
348+
// default behavior is to add the Ready annotation after Pod has been created
349+
// and all of its sidecars are in a Ready state.
350+
//
351+
// For further reference see https://github.com/tektoncd/pipeline/issues/2080
352+
func shouldAddReadyAnnotationonPodCreate(sidecars []v1beta1.Sidecar, kubeclient kubernetes.Interface) bool {
353+
// If the TaskRun has sidecars, we cannot set the READY annotation early
354+
if len(sidecars) > 0 {
355+
return false
356+
}
357+
// If the TaskRun has no sidecars, check if the feature is enabled.
358+
configMap, err := kubeclient.CoreV1().ConfigMaps(system.GetNamespace()).Get(featureFlagConfigMapName, metav1.GetOptions{})
359+
if err == nil && configMap != nil && configMap.Data != nil && configMap.Data[featureFlagSetReadyAnnotationOnPodCreate] == "true" {
360+
return true
361+
}
362+
return false
363+
}

pkg/pod/pod_test.go

Lines changed: 214 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"testing"
2424

2525
"github.com/google/go-cmp/cmp"
26+
"github.com/google/go-cmp/cmp/cmpopts"
2627
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
2728
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
2829
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
@@ -40,41 +41,46 @@ var (
4041
CredsImage: "override-with-creds:latest",
4142
ShellImage: "busybox",
4243
}
44+
45+
ignoreReleaseAnnotation = func(k string, v string) bool {
46+
return k == ReleaseAnnotation
47+
}
4348
)
4449

4550
func TestMakePod(t *testing.T) {
46-
names.TestingSeed()
47-
48-
implicitEnvVars := []corev1.EnvVar{{
49-
Name: "HOME",
50-
Value: homeDir,
51-
}}
52-
secretsVolumeMount := corev1.VolumeMount{
53-
Name: "tekton-internal-secret-volume-multi-creds-9l9zj",
54-
MountPath: "/tekton/creds-secrets/multi-creds",
55-
}
56-
secretsVolume := corev1.Volume{
57-
Name: "tekton-internal-secret-volume-multi-creds-9l9zj",
58-
VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "multi-creds"}},
59-
}
51+
var (
52+
secretsVolumeMount = corev1.VolumeMount{
53+
Name: "tekton-internal-secret-volume-multi-creds-9l9zj",
54+
MountPath: "/tekton/creds-secrets/multi-creds",
55+
}
56+
secretsVolume = corev1.Volume{
57+
Name: "tekton-internal-secret-volume-multi-creds-9l9zj",
58+
VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "multi-creds"}},
59+
}
6060

61-
placeToolsInit := corev1.Container{
62-
Name: "place-tools",
63-
Image: images.EntrypointImage,
64-
Command: []string{"cp", "/ko-app/entrypoint", "/tekton/tools/entrypoint"},
65-
VolumeMounts: []corev1.VolumeMount{toolsMount},
66-
}
61+
implicitEnvVars = []corev1.EnvVar{{
62+
Name: "HOME",
63+
Value: homeDir,
64+
}}
6765

68-
runtimeClassName := "gvisor"
69-
automountServiceAccountToken := false
70-
dnsPolicy := corev1.DNSNone
71-
enableServiceLinks := false
72-
priorityClassName := "system-cluster-critical"
66+
placeToolsInit = corev1.Container{
67+
Name: "place-tools",
68+
Image: images.EntrypointImage,
69+
Command: []string{"cp", "/ko-app/entrypoint", "/tekton/tools/entrypoint"},
70+
VolumeMounts: []corev1.VolumeMount{toolsMount},
71+
}
72+
runtimeClassName = "gvisor"
73+
automountServiceAccountToken = false
74+
dnsPolicy = corev1.DNSNone
75+
enableServiceLinks = false
76+
priorityClassName = "system-cluster-critical"
77+
)
7378

7479
for _, c := range []struct {
7580
desc string
7681
trs v1alpha1.TaskRunSpec
7782
ts v1alpha1.TaskSpec
83+
featureFlags map[string]string
7884
want *corev1.PodSpec
7985
wantAnnotations map[string]string
8086
}{{
@@ -113,6 +119,48 @@ func TestMakePod(t *testing.T) {
113119
}},
114120
Volumes: append(implicitVolumes, toolsVolume, downwardVolume),
115121
},
122+
}, {
123+
desc: "simple with enable-ready-annotation-on-pod-create",
124+
ts: v1alpha1.TaskSpec{TaskSpec: v1beta1.TaskSpec{
125+
Steps: []v1alpha1.Step{{Container: corev1.Container{
126+
Name: "name",
127+
Image: "image",
128+
Command: []string{"cmd"}, // avoid entrypoint lookup.
129+
}}},
130+
}},
131+
featureFlags: map[string]string{
132+
featureFlagSetReadyAnnotationOnPodCreate: "true",
133+
},
134+
want: &corev1.PodSpec{
135+
RestartPolicy: corev1.RestartPolicyNever,
136+
InitContainers: []corev1.Container{placeToolsInit},
137+
Containers: []corev1.Container{{
138+
Name: "step-name",
139+
Image: "image",
140+
Command: []string{"/tekton/tools/entrypoint"},
141+
Args: []string{
142+
"-wait_file",
143+
"/tekton/downward/ready",
144+
"-wait_file_content",
145+
"-post_file",
146+
"/tekton/tools/0",
147+
"-termination_path",
148+
"/tekton/termination",
149+
"-entrypoint",
150+
"cmd",
151+
"--",
152+
},
153+
Env: implicitEnvVars,
154+
VolumeMounts: append([]corev1.VolumeMount{toolsMount, downwardMount}, implicitVolumeMounts...),
155+
WorkingDir: pipeline.WorkspaceDir,
156+
Resources: corev1.ResourceRequirements{Requests: allZeroQty()},
157+
TerminationMessagePath: "/tekton/termination",
158+
}},
159+
Volumes: append(implicitVolumes, toolsVolume, downwardVolume),
160+
},
161+
wantAnnotations: map[string]string{
162+
readyAnnotation: readyAnnotationValue,
163+
},
116164
}, {
117165
desc: "with service account",
118166
ts: v1alpha1.TaskSpec{TaskSpec: v1beta1.TaskSpec{
@@ -471,6 +519,58 @@ sidecar-script-heredoc-randomly-generated-mz4c7
471519
}},
472520
Volumes: append(implicitVolumes, scriptsVolume, toolsVolume, downwardVolume),
473521
},
522+
}, {
523+
desc: "sidecar container with enable-ready-annotation-on-pod-create",
524+
ts: v1alpha1.TaskSpec{TaskSpec: v1beta1.TaskSpec{
525+
Steps: []v1alpha1.Step{{Container: corev1.Container{
526+
Name: "primary-name",
527+
Image: "primary-image",
528+
Command: []string{"cmd"}, // avoid entrypoint lookup.
529+
}}},
530+
Sidecars: []v1alpha1.Sidecar{{
531+
Container: corev1.Container{
532+
Name: "sc-name",
533+
Image: "sidecar-image",
534+
},
535+
}},
536+
}},
537+
featureFlags: map[string]string{
538+
featureFlagSetReadyAnnotationOnPodCreate: "true",
539+
},
540+
wantAnnotations: map[string]string{}, // no ready annotations on pod create since sidecars are present
541+
want: &corev1.PodSpec{
542+
RestartPolicy: corev1.RestartPolicyNever,
543+
InitContainers: []corev1.Container{placeToolsInit},
544+
Containers: []corev1.Container{{
545+
Name: "step-primary-name",
546+
Image: "primary-image",
547+
Command: []string{"/tekton/tools/entrypoint"},
548+
Args: []string{
549+
"-wait_file",
550+
"/tekton/downward/ready",
551+
"-wait_file_content",
552+
"-post_file",
553+
"/tekton/tools/0",
554+
"-termination_path",
555+
"/tekton/termination",
556+
"-entrypoint",
557+
"cmd",
558+
"--",
559+
},
560+
Env: implicitEnvVars,
561+
VolumeMounts: append([]corev1.VolumeMount{toolsMount, downwardMount}, implicitVolumeMounts...),
562+
WorkingDir: pipeline.WorkspaceDir,
563+
Resources: corev1.ResourceRequirements{Requests: allZeroQty()},
564+
TerminationMessagePath: "/tekton/termination",
565+
}, {
566+
Name: "sidecar-sc-name",
567+
Image: "sidecar-image",
568+
Resources: corev1.ResourceRequirements{
569+
Requests: nil,
570+
},
571+
}},
572+
Volumes: append(implicitVolumes, toolsVolume, downwardVolume),
573+
},
474574
}, {
475575
desc: "resource request",
476576
ts: v1alpha1.TaskSpec{TaskSpec: v1beta1.TaskSpec{
@@ -734,6 +834,10 @@ script-heredoc-randomly-generated-78c5n
734834
t.Run(c.desc, func(t *testing.T) {
735835
names.TestingSeed()
736836
kubeclient := fakek8s.NewSimpleClientset(
837+
&corev1.ConfigMap{
838+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
839+
Data: c.featureFlags,
840+
},
737841
&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}},
738842
&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "service-account", Namespace: "default"},
739843
Secrets: []corev1.ObjectReference{{
@@ -780,6 +884,12 @@ script-heredoc-randomly-generated-78c5n
780884
if d := cmp.Diff(c.want, &got.Spec, resourceQuantityCmp); d != "" {
781885
t.Errorf("Diff(-want, +got):\n%s", d)
782886
}
887+
888+
if c.wantAnnotations != nil {
889+
if d := cmp.Diff(c.wantAnnotations, got.ObjectMeta.Annotations, cmpopts.IgnoreMapEntries(ignoreReleaseAnnotation)); d != "" {
890+
t.Errorf("Annotation Diff(-want, +got):\n%s", d)
891+
}
892+
}
783893
})
784894
}
785895
}
@@ -888,3 +998,82 @@ func TestShouldOverrideWorkingDir(t *testing.T) {
888998
})
889999
}
8901000
}
1001+
1002+
func TestShouldAddReadyAnnotationonPodCreate(t *testing.T) {
1003+
sd := v1beta1.Sidecar{
1004+
Container: corev1.Container{
1005+
Name: "a-sidecar",
1006+
},
1007+
}
1008+
tcs := []struct {
1009+
description string
1010+
sidecars []v1beta1.Sidecar
1011+
configMap *corev1.ConfigMap
1012+
expected bool
1013+
}{{
1014+
description: "Default behavior with sidecars present: Ready annotation not set on pod create",
1015+
sidecars: []v1beta1.Sidecar{sd},
1016+
configMap: &corev1.ConfigMap{
1017+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
1018+
Data: map[string]string{},
1019+
},
1020+
expected: false,
1021+
}, {
1022+
description: "Default behavior with no sidecars present: Ready annotation not set on pod create",
1023+
sidecars: []v1beta1.Sidecar{},
1024+
configMap: &corev1.ConfigMap{
1025+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
1026+
Data: map[string]string{},
1027+
},
1028+
expected: false,
1029+
}, {
1030+
description: "Setting enable-ready-annotation-on-pod-create to false with sidecars present results in false",
1031+
sidecars: []v1beta1.Sidecar{sd},
1032+
configMap: &corev1.ConfigMap{
1033+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
1034+
Data: map[string]string{
1035+
featureFlagSetReadyAnnotationOnPodCreate: "false",
1036+
},
1037+
},
1038+
expected: false,
1039+
}, {
1040+
description: "Setting enable-ready-annotation-on-pod-create to false with no sidecars present results in false",
1041+
sidecars: []v1beta1.Sidecar{},
1042+
configMap: &corev1.ConfigMap{
1043+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
1044+
Data: map[string]string{
1045+
featureFlagSetReadyAnnotationOnPodCreate: "false",
1046+
},
1047+
},
1048+
expected: false,
1049+
}, {
1050+
description: "Setting enable-ready-annotation-on-pod-create to true with sidecars present results in false",
1051+
sidecars: []v1beta1.Sidecar{sd},
1052+
configMap: &corev1.ConfigMap{
1053+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
1054+
Data: map[string]string{
1055+
featureFlagSetReadyAnnotationOnPodCreate: "true",
1056+
},
1057+
},
1058+
expected: false,
1059+
}, {
1060+
description: "Setting enable-ready-annotation-on-pod-create to true with no sidecars present results in true",
1061+
sidecars: []v1beta1.Sidecar{},
1062+
configMap: &corev1.ConfigMap{
1063+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
1064+
Data: map[string]string{
1065+
featureFlagSetReadyAnnotationOnPodCreate: "true",
1066+
},
1067+
},
1068+
expected: true,
1069+
}}
1070+
1071+
for _, tc := range tcs {
1072+
t.Run(tc.description, func(t *testing.T) {
1073+
kubclient := fakek8s.NewSimpleClientset(tc.configMap)
1074+
if result := shouldAddReadyAnnotationonPodCreate(tc.sidecars, kubclient); result != tc.expected {
1075+
t.Errorf("expected: %t Recieved: %t", tc.expected, result)
1076+
}
1077+
})
1078+
}
1079+
}

0 commit comments

Comments
 (0)