Skip to content

Commit 5175c4a

Browse files
dibyomtekton-robot
authored andcommitted
Optimize start time for TaskRuns with no sidecars
When no sidercars are present **and** the cluster does not use injected sidecars, the pipeline controller can optimize the TaskRun Pod creation process by setting the `tekton.dev/ready` annotation before pod creation itself instead of setting it after the pod has been created. This commit adds an option to a new `config-features` ConfigMap called `running-in-environment-with-injected-sidecars`. Enabling this option will decrease the time it takes for a TaskRun to start running(when no sidecars are present). However, for clusters that use injected sidecars e.g. istio enabling this option can lead to unexpected behavior.By default, the option is set to "true" for backwards compatibility. Fixes #2080 Signed-off-by: Dibyo Mukherjee <[email protected]>
1 parent 038ce4e commit 5175c4a

File tree

4 files changed

+231
-6
lines changed

4 files changed

+231
-6
lines changed

config/config-feature-flags.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,11 @@ data:
4141
# See https://github.com/tektoncd/pipeline/issues/1836 for more
4242
# info.
4343
disable-working-directory-overwrite: "false"
44+
# This option should be set to false when Pipelines is running in a
45+
# cluster that does not use injected sidecars such as Istio. Setting
46+
# it to false should decrease the time it takes for a TaskRun to start
47+
# running. For clusters that use injected sidecars, setting this
48+
# option to false can lead to unexpected behavior.
49+
#
50+
# See https://github.com/tektoncd/pipeline/issues/2080 for more info.
51+
running-in-environment-with-injected-sidecars: "true"

docs/install.md

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

294+
- `running-in-environment-with-injected-sidecars`: set this flag to `"true"` to allow the
295+
Tekton controller to set the `tekon.dev/ready` annotation at pod creation time for
296+
TaskRuns with no Sidecars specified. Enabling this option should decrease the time it takes for a TaskRun to
297+
start running. However, for clusters that use injected sidecars e.g. istio
298+
enabling this option can lead to unexpected behavior.
299+
294300
For example:
295301

296302
```yaml

pkg/pod/pod.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ const (
4646
// ResultsDir is the folder used by default to create the results file
4747
ResultsDir = "/tekton/results"
4848

49-
featureFlagDisableHomeEnvKey = "disable-home-env-overwrite"
50-
featureFlagDisableWorkingDirKey = "disable-working-directory-overwrite"
49+
featureInjectedSidecar = "running-in-environment-with-injected-sidecars"
50+
featureFlagDisableHomeEnvKey = "disable-home-env-overwrite"
51+
featureFlagDisableWorkingDirKey = "disable-working-directory-overwrite"
52+
featureFlagConfigMapName = "feature-flags"
53+
featureFlagSetReadyAnnotationOnPodCreate = "enable-ready-annotation-on-pod-create"
5154

5255
taskRunLabelKey = pipeline.GroupName + pipeline.TaskRunLabelKey
5356
)
@@ -250,6 +253,10 @@ func MakePod(images pipeline.Images, taskRun *v1beta1.TaskRun, taskSpec v1beta1.
250253
podAnnotations := taskRun.Annotations
251254
podAnnotations[ReleaseAnnotation] = ReleaseAnnotationValue
252255

256+
if shouldAddReadyAnnotationOnPodCreate(taskSpec.Sidecars, kubeclient) {
257+
podAnnotations[readyAnnotation] = readyAnnotationValue
258+
}
259+
253260
return &corev1.Pod{
254261
ObjectMeta: metav1.ObjectMeta{
255262
// We execute the build's pod in the same namespace as where the build was
@@ -382,3 +389,21 @@ func shouldOverrideWorkingDir(kubeclient kubernetes.Interface) bool {
382389
}
383390
return true
384391
}
392+
393+
// shouldAddReadyAnnotationonPodCreate returns a bool indicating whether the
394+
// controller should add the `Ready` annotation when creating the Pod. We cannot
395+
// add the annotation if Tekton is running in a cluster with injected sidecars
396+
// or if the Task specifies any sidecars.
397+
func shouldAddReadyAnnotationOnPodCreate(sidecars []v1beta1.Sidecar, kubeclient kubernetes.Interface) bool {
398+
// If the TaskRun has sidecars, we cannot set the READY annotation early
399+
if len(sidecars) > 0 {
400+
return false
401+
}
402+
// If the TaskRun has no sidecars, check if we are running in a cluster where sidecars can be injected by other
403+
// controllers.
404+
configMap, err := kubeclient.CoreV1().ConfigMaps(system.GetNamespace()).Get(GetFeatureFlagsConfigName(), metav1.GetOptions{})
405+
if err == nil && configMap != nil && configMap.Data != nil && configMap.Data[featureInjectedSidecar] == "false" {
406+
return true
407+
}
408+
return false
409+
}

pkg/pod/pod_test.go

Lines changed: 190 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import (
2424
"testing"
2525

2626
"github.com/google/go-cmp/cmp"
27+
"github.com/google/go-cmp/cmp/cmpopts"
2728
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
29+
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
2830
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
2931
"github.com/tektoncd/pipeline/pkg/system"
3032
"github.com/tektoncd/pipeline/test/diff"
@@ -41,11 +43,13 @@ var (
4143
CredsImage: "override-with-creds:latest",
4244
ShellImage: "busybox",
4345
}
46+
47+
ignoreReleaseAnnotation = func(k string, v string) bool {
48+
return k == ReleaseAnnotation
49+
}
4450
)
4551

4652
func TestMakePod(t *testing.T) {
47-
names.TestingSeed()
48-
4953
implicitEnvVars := []corev1.EnvVar{{
5054
Name: "HOME",
5155
Value: pipeline.HomeDir,
@@ -58,14 +62,12 @@ func TestMakePod(t *testing.T) {
5862
Name: "tekton-internal-secret-volume-multi-creds-9l9zj",
5963
VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "multi-creds"}},
6064
}
61-
6265
placeToolsInit := corev1.Container{
6366
Name: "place-tools",
6467
Image: images.EntrypointImage,
6568
Command: []string{"cp", "/ko-app/entrypoint", "/tekton/tools/entrypoint"},
6669
VolumeMounts: []corev1.VolumeMount{toolsMount},
6770
}
68-
6971
runtimeClassName := "gvisor"
7072
automountServiceAccountToken := false
7173
dnsPolicy := corev1.DNSNone
@@ -77,6 +79,7 @@ func TestMakePod(t *testing.T) {
7779
trs v1beta1.TaskRunSpec
7880
trAnnotation map[string]string
7981
ts v1beta1.TaskSpec
82+
featureFlags map[string]string
8083
want *corev1.PodSpec
8184
wantAnnotations map[string]string
8285
}{{
@@ -115,6 +118,48 @@ func TestMakePod(t *testing.T) {
115118
}},
116119
Volumes: append(implicitVolumes, toolsVolume, downwardVolume),
117120
},
121+
}, {
122+
desc: "simple with running-in-environment-with-injected-sidecar set to false",
123+
ts: v1beta1.TaskSpec{
124+
Steps: []v1alpha1.Step{{Container: corev1.Container{
125+
Name: "name",
126+
Image: "image",
127+
Command: []string{"cmd"}, // avoid entrypoint lookup.
128+
}}},
129+
},
130+
featureFlags: map[string]string{
131+
featureInjectedSidecar: "false",
132+
},
133+
want: &corev1.PodSpec{
134+
RestartPolicy: corev1.RestartPolicyNever,
135+
InitContainers: []corev1.Container{placeToolsInit},
136+
Containers: []corev1.Container{{
137+
Name: "step-name",
138+
Image: "image",
139+
Command: []string{"/tekton/tools/entrypoint"},
140+
Args: []string{
141+
"-wait_file",
142+
"/tekton/downward/ready",
143+
"-wait_file_content",
144+
"-post_file",
145+
"/tekton/tools/0",
146+
"-termination_path",
147+
"/tekton/termination",
148+
"-entrypoint",
149+
"cmd",
150+
"--",
151+
},
152+
Env: implicitEnvVars,
153+
VolumeMounts: append([]corev1.VolumeMount{toolsMount, downwardMount}, implicitVolumeMounts...),
154+
WorkingDir: pipeline.WorkspaceDir,
155+
Resources: corev1.ResourceRequirements{Requests: allZeroQty()},
156+
TerminationMessagePath: "/tekton/termination",
157+
}},
158+
Volumes: append(implicitVolumes, toolsVolume, downwardVolume),
159+
},
160+
wantAnnotations: map[string]string{
161+
readyAnnotation: readyAnnotationValue,
162+
},
118163
}, {
119164
desc: "with service account",
120165
ts: v1beta1.TaskSpec{
@@ -473,6 +518,58 @@ sidecar-script-heredoc-randomly-generated-mz4c7
473518
}},
474519
Volumes: append(implicitVolumes, scriptsVolume, toolsVolume, downwardVolume),
475520
},
521+
}, {
522+
desc: "sidecar container with enable-ready-annotation-on-pod-create",
523+
ts: v1beta1.TaskSpec{
524+
Steps: []v1alpha1.Step{{Container: corev1.Container{
525+
Name: "primary-name",
526+
Image: "primary-image",
527+
Command: []string{"cmd"}, // avoid entrypoint lookup.
528+
}}},
529+
Sidecars: []v1alpha1.Sidecar{{
530+
Container: corev1.Container{
531+
Name: "sc-name",
532+
Image: "sidecar-image",
533+
},
534+
}},
535+
},
536+
featureFlags: map[string]string{
537+
featureFlagSetReadyAnnotationOnPodCreate: "true",
538+
},
539+
wantAnnotations: map[string]string{}, // no ready annotations on pod create since sidecars are present
540+
want: &corev1.PodSpec{
541+
RestartPolicy: corev1.RestartPolicyNever,
542+
InitContainers: []corev1.Container{placeToolsInit},
543+
Containers: []corev1.Container{{
544+
Name: "step-primary-name",
545+
Image: "primary-image",
546+
Command: []string{"/tekton/tools/entrypoint"},
547+
Args: []string{
548+
"-wait_file",
549+
"/tekton/downward/ready",
550+
"-wait_file_content",
551+
"-post_file",
552+
"/tekton/tools/0",
553+
"-termination_path",
554+
"/tekton/termination",
555+
"-entrypoint",
556+
"cmd",
557+
"--",
558+
},
559+
Env: implicitEnvVars,
560+
VolumeMounts: append([]corev1.VolumeMount{toolsMount, downwardMount}, implicitVolumeMounts...),
561+
WorkingDir: pipeline.WorkspaceDir,
562+
Resources: corev1.ResourceRequirements{Requests: allZeroQty()},
563+
TerminationMessagePath: "/tekton/termination",
564+
}, {
565+
Name: "sidecar-sc-name",
566+
Image: "sidecar-image",
567+
Resources: corev1.ResourceRequirements{
568+
Requests: nil,
569+
},
570+
}},
571+
Volumes: append(implicitVolumes, toolsVolume, downwardVolume),
572+
},
476573
}, {
477574
desc: "resource request",
478575
ts: v1beta1.TaskSpec{
@@ -839,6 +936,10 @@ script-heredoc-randomly-generated-78c5n
839936
t.Run(c.desc, func(t *testing.T) {
840937
names.TestingSeed()
841938
kubeclient := fakek8s.NewSimpleClientset(
939+
&corev1.ConfigMap{
940+
ObjectMeta: metav1.ObjectMeta{Name: featureFlagConfigMapName, Namespace: system.GetNamespace()},
941+
Data: c.featureFlags,
942+
},
842943
&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}},
843944
&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "service-account", Namespace: "default"},
844945
Secrets: []corev1.ObjectReference{{
@@ -892,6 +993,12 @@ script-heredoc-randomly-generated-78c5n
892993
if d := cmp.Diff(c.want, &got.Spec, resourceQuantityCmp); d != "" {
893994
t.Errorf("Diff %s", diff.PrintWantGot(d))
894995
}
996+
997+
if c.wantAnnotations != nil {
998+
if d := cmp.Diff(c.wantAnnotations, got.ObjectMeta.Annotations, cmpopts.IgnoreMapEntries(ignoreReleaseAnnotation)); d != "" {
999+
t.Errorf("Annotation Diff(-want, +got):\n%s", d)
1000+
}
1001+
}
8951002
})
8961003
}
8971004
}
@@ -1031,3 +1138,82 @@ func TestShouldOverrideWorkingDir(t *testing.T) {
10311138
})
10321139
}
10331140
}
1141+
1142+
func TestShouldAddReadyAnnotationonPodCreate(t *testing.T) {
1143+
sd := v1beta1.Sidecar{
1144+
Container: corev1.Container{
1145+
Name: "a-sidecar",
1146+
},
1147+
}
1148+
tcs := []struct {
1149+
description string
1150+
sidecars []v1beta1.Sidecar
1151+
configMap *corev1.ConfigMap
1152+
expected bool
1153+
}{{
1154+
description: "Default behavior with sidecars present: Ready annotation not set on pod create",
1155+
sidecars: []v1beta1.Sidecar{sd},
1156+
configMap: &corev1.ConfigMap{
1157+
ObjectMeta: metav1.ObjectMeta{Name: GetFeatureFlagsConfigName(), Namespace: system.GetNamespace()},
1158+
Data: map[string]string{},
1159+
},
1160+
expected: false,
1161+
}, {
1162+
description: "Default behavior with no sidecars present: Ready annotation not set on pod create",
1163+
sidecars: []v1beta1.Sidecar{},
1164+
configMap: &corev1.ConfigMap{
1165+
ObjectMeta: metav1.ObjectMeta{Name: GetFeatureFlagsConfigName(), Namespace: system.GetNamespace()},
1166+
Data: map[string]string{},
1167+
},
1168+
expected: false,
1169+
}, {
1170+
description: "Setting running-in-environment-with-injected-sidecars to true with sidecars present results in false",
1171+
sidecars: []v1beta1.Sidecar{sd},
1172+
configMap: &corev1.ConfigMap{
1173+
ObjectMeta: metav1.ObjectMeta{Name: GetFeatureFlagsConfigName(), Namespace: system.GetNamespace()},
1174+
Data: map[string]string{
1175+
featureInjectedSidecar: "true",
1176+
},
1177+
},
1178+
expected: false,
1179+
}, {
1180+
description: "Setting running-in-environment-with-injected-sidecars to true with no sidecars present results in false",
1181+
sidecars: []v1beta1.Sidecar{},
1182+
configMap: &corev1.ConfigMap{
1183+
ObjectMeta: metav1.ObjectMeta{Name: GetFeatureFlagsConfigName(), Namespace: system.GetNamespace()},
1184+
Data: map[string]string{
1185+
featureInjectedSidecar: "true",
1186+
},
1187+
},
1188+
expected: false,
1189+
}, {
1190+
description: "Setting running-in-environment-with-injected-sidecars to false with sidecars present results in false",
1191+
sidecars: []v1beta1.Sidecar{sd},
1192+
configMap: &corev1.ConfigMap{
1193+
ObjectMeta: metav1.ObjectMeta{Name: GetFeatureFlagsConfigName(), Namespace: system.GetNamespace()},
1194+
Data: map[string]string{
1195+
featureInjectedSidecar: "false",
1196+
},
1197+
},
1198+
expected: false,
1199+
}, {
1200+
description: "Setting running-in-environment-with-injected-sidecars to false with no sidecars present results in true",
1201+
sidecars: []v1beta1.Sidecar{},
1202+
configMap: &corev1.ConfigMap{
1203+
ObjectMeta: metav1.ObjectMeta{Name: GetFeatureFlagsConfigName(), Namespace: system.GetNamespace()},
1204+
Data: map[string]string{
1205+
featureInjectedSidecar: "false",
1206+
},
1207+
},
1208+
expected: true,
1209+
}}
1210+
1211+
for _, tc := range tcs {
1212+
t.Run(tc.description, func(t *testing.T) {
1213+
kubclient := fakek8s.NewSimpleClientset(tc.configMap)
1214+
if result := shouldAddReadyAnnotationOnPodCreate(tc.sidecars, kubclient); result != tc.expected {
1215+
t.Errorf("expected: %t Recieved: %t", tc.expected, result)
1216+
}
1217+
})
1218+
}
1219+
}

0 commit comments

Comments
 (0)