Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make generated pods only request the maximum necessary resources #723

Merged
merged 1 commit into from
Apr 12, 2019

Conversation

dwnusbaum
Copy link
Contributor

@dwnusbaum dwnusbaum commented Apr 4, 2019

Changes

Before this change, if CPU, memory, or ephemeral storage resource requests were set in a Task's steps (which are Containers), the generated Pod would require the sum of all of the steps' requests to be scheduled on a Node. However, because Tekton overwrites Container entrypoints in Tasks to make the Containers logically execute one at a time, we want to make Pods generated by the TaskRun only request the maximum resources that will be necessary for any single Container rather than the sum of all resource requests.

To make this happen, when generating a Pod for a Task, we find the Step with largest resource requests among all Steps, and set the resource requests for all other steps to 0 for the respective resource. If no Step has an explicit resource request, all requests are set to 0. If we unset resource requests instead of setting them to 0 explicitly, then the limits would be used for the requests, which would defeat the purpose of unsetting the requested values (and could end up making the Pod request more memory than it did in the first place).

I did not add any e2e tests, but would be happy to do so if desired by reviewers. I think the tests would need to look up Nodes in the cluster to find the maximum allowed resources and then create some tasks dynamically that would have been unschedulable before this change but work after the change.

CC @bbrowning, @abayer

Fixes #598

Submitter Checklist

These are the criteria that every PR should meet, please check them off as you
review them:

See the contribution guide
for more details.

Release Notes

Set CPU, memory, and ephemeral storage resource requests for each
step in a Task to zero if the step does not have the largest resource
request out of all steps in the Task. This ensures that the Pod that
executes the Task will only request the resources necessary to
execute any single step in the Task, rather than requesting the sum
of all of the step's resource requests, and is safe because Tekton
executes steps sequentially rather than all at once.

@googlebot googlebot added the cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit label Apr 4, 2019
@tekton-robot tekton-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 4, 2019
pkg/reconciler/v1alpha1/taskrun/resources/pod.go Outdated Show resolved Hide resolved
ignorePrivateResourceFields = cmpopts.IgnoreUnexported(resource.Quantity{})
nopContainer = corev1.Container{
resourceQuantityCmp = cmp.Comparer(func(x, y resource.Quantity) bool {
return x.Cmp(y) == 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this comparator in 3 places. It would be nice to have a default comparator with some helpful default settings for use in tests, but I didn't see any kind of util package or anything for that kind of thing. Is there a place for something like that?

}
}

func Memory(val string) ResourceListOp {
Copy link
Contributor Author

@dwnusbaum dwnusbaum Apr 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively we could just have func Resource(name corev1.ResourceName, val string) so we don't need a separate method for every function, but that would be a little more verbose in the tests.

@dwnusbaum
Copy link
Contributor Author

/test pull-tekton-pipeline-integration-tests

@dwnusbaum
Copy link
Contributor Author

I guess the tests are failing for the reason Nader described here?

/test pull-tekton-pipeline-integration-tests

@dwnusbaum
Copy link
Contributor Author

/test pull-tekton-pipeline-integration-tests

Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Desgin wise I'm torn between:

  • the current implement, that let the Max request of each type on it's original container (step)
  • an implementation where we would get the Max for each and apply to the first container (step)

The later makes it easier to know where to look for those resource requests.

@dwnusbaum @bobcatfish wdyt ? 🚴‍♂️

@dwnusbaum
Copy link
Contributor Author

@vdemeester No preference from me, it would be relatively easy to switch to applying the max requests to the first container. It might be a bit cleaner to do things that way rather than needing to track indices.

@dwnusbaum
Copy link
Contributor Author

@vdemeester Actually I think moving the max requests to the first container is problematic because of resource limits. Take the following example:

steps:
  - name: step1
    ...
    resources:
      limits:
        memory: "1Gi"
      requests:
        memory: "1Gi"
  - name: step2
    ...
    resources:
      requests:
        memory: "5Gi"

The current approach turns this into:

steps:
  - name: step1
    ...
    resources:
      limits:
        memory: "1Gi"
      requests:
        memory: "0"
  - name: step2
    ...
    resources:
      requests:
        memory: "5Gi"

But the other approach would cause the first step to request resources beyond its limit:

steps:
  - name: step1
    ...
    resources:
      limits:
        memory: "1Gi"
      requests:
        memory: "5Gi"
  - name: step2
    ...
    resources:
      requests:
        memory: "0"

We could adjust the limit in these cases, but I'd prefer to avoid modifying limits if we don't have to.

@vdemeester
Copy link
Member

@vdemeester Actually I think moving the max requests to the first container is problematic because of resource limits. Take the following example:

[…]

But the other approach would cause the first step to request resources beyond its limit:

[…]

We could adjust the limit in these cases, but I'd prefer to avoid modifying limits if we don't have to.

Ah ! Make sense 😅 Let's go for the initial take then 👼

@dwnusbaum dwnusbaum force-pushed the container-resource-limits branch 2 times, most recently from db2eab3 to d9c4eb1 Compare April 5, 2019 17:45
@@ -129,6 +129,12 @@ or container images that you define:
the configuration file.
- Each container image runs until completion or until the first failure is
detected.
- The CPU, memory, and ephemeral storage resource requests will be set to zero
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any thoughts on a better place to put this documentation or a better way to phrase it would be welcome!

Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm
/hold

Waiting for @abayer and/or @bobcatfish review 👼 🙏

@tekton-robot tekton-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. lgtm Indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Apr 6, 2019
@abayer
Copy link
Contributor

abayer commented Apr 11, 2019

/lgtm
/cancel hold

@abayer
Copy link
Contributor

abayer commented Apr 11, 2019

/hold cancel

...forgot the syntax. =)

@tekton-robot tekton-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 11, 2019
@dwnusbaum
Copy link
Contributor Author

Looks like the unit tests are failing after other PRs were merged (maybe #748?), probably a logical conflict somewhere with the changes in this PR. I'll rebase and fix the tests.

@vdemeester
Copy link
Member

arf sorry @dwnusbaum 😓 🙇‍♂️

@dwnusbaum
Copy link
Contributor Author

@vdemeester No problem, probably trivial to fix 😄

Before this change, if CPU, memory, or ephemeral storage resource
requests were set in a Task's steps (which are Containers), the
generated Pod would require the sum of all of the steps' requests
to be scheduled on a Node. However, because Tekton overwrites
Container entrypoints in Tasks to make the Containers logically
execute one at a time, we want to make Pods generated by the TaskRun
only request the maximum resources that will be necessary for any
single Container rather than the sum of all resource requests.

To make this happen, when generating a Pod for a Task, we find the
Step with largest resource requests among all Steps, and set the
resource requests for all other steps to 0 for the respective
resource. If no Step has an explicit resource request, all requests
are set to 0. If we unset resource requests instead of setting them
to 0 explicitly, then the limits would be used for the requests,
which would defeat the purpose of unsetting the requested values
(and could end up making the Pod request more memory than it did in
the first place).

Fixes tektoncd#598
@tekton-robot tekton-robot removed the lgtm Indicates that a PR is ready to be merged. label Apr 12, 2019
Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@tekton-robot tekton-robot added the lgtm Indicates that a PR is ready to be merged. label Apr 12, 2019
@tekton-robot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dwnusbaum, vdemeester

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@abayer
Copy link
Contributor

abayer commented Apr 12, 2019

/lgtm

@tekton-robot tekton-robot merged commit 9f52dad into tektoncd:master Apr 12, 2019
Copy link
Collaborator

@bobcatfish bobcatfish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful commit message!!! a8c6493 ❤️ 😻 ❤️

I did not add any e2e tests

Totally reasonable imo! We often add too many end to end tests tbh

// one at a time, so we want pods to only request the maximum resources needed
// at any single point in time. If no contianer has an explicit resource
// request, all requests are set to 0.
func zeroNonMaxResourceRequests(container *corev1.Container, containerIndex int, maxIndicesByResource map[corev1.ResourceName]int) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these functions are excellent! nice focused interface and clear short functions. My only too-late-to-the-party request would be to have unit tests covering these functions directly as well but im fully expecting to be ignored since im so late haha :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I'm going to file an issue for a followup I thought of the other day, and if I'm in this area again I'll add some unit tests.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, that sounds great @dwnusbaum ❤️ !!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cla: yes Trying to make the CLA bot happy with ppl from different companies work on one commit lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

All containers in a TaskRun's Pod are combined to calculate required resources
6 participants