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

[Draft] Add new setting: eviction-hard #1341

Closed
wants to merge 1 commit into from
Closed

Conversation

gthao313
Copy link
Member

Get some feedbacks from this draft, which can help me in implementing another three settings

Issue number:
#1140

Description of changes:
Add new setting eviction-hard to k8s. User can specify this setting in userdata.

  • example:
    [settings.kubernetes.eviction-hard]
    "memory.available" = "10Gi"
    "nodefs.inodesFree" = “15%”

Testing done:
Build aws-eks-* images and launched instance.

Test step1:
Go to control container run apiclient -u /settings to check if expected setting is there.
eviction-hard":{"memory.available":"99.999%"}

Test step2:
ssh to admin contianer and look etc/kubernetes/kubelet/config to check if expected config is there.

evictionHard:
  memory.available: 15%

Test step3 - test effected/behavior:
set up eviction threshold to a high value for triggering eviction.

[evictionHard.memory]
"memory.available" = "99.99%" (high percentage to trigger eviction)

a) Go to EKS to check node condition

MemoryPressure True kubelet has insufficient memory available

b) In admin contianer, check kubelet log by journalctl -u kubelet

eviction_manager.go:335] eviction manager: attempting to reclaim memory
eviction_manager.go:346] eviction manager: must evict pod(s) to reclaim memory

Terms of contribution:

By submitting this pull request, I agree that this contribution is dual-licensed under the terms of both the Apache License, version 2.0, and the MIT license.

* `settings.kubernetes.eviction-hard`: The hard eviction Signal and Thresholds you set up to reclaim the associated starved resource.
Remember to quote keys (since they often contain ".") and to quote all values.
* Example user data for setting up eviction hard:
```
Copy link
Member Author

Choose a reason for hiding this comment

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

I'll fix this indent.

"nodefs.inodesFree" = "15Mi"
"pid.available" = "15%"
```


You can also optionally specify static pods for your node with the following settings.
Copy link
Member Author

Choose a reason for hiding this comment

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

Question: There are four settings, and wonder if it's better to make four PRs for them (one PR for each setting.) Ben mentioned that we should make them in different commits and same PR. I think maybe it's better to have four PR, because all of them have different testing and implementation requirement. Can I get some suggestions on that? thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

If the commits have no inter-dependencies and can stand alone by themselves I don't think we have to have them in the same PR. That being said, if you already have them ready, and they're similar in scope to this commit you have out right now, it'd be nice to have them all in the PR and reviewers can just review commit by commit instead of having to jump through 4 PRs that might end up with similar review comments.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to that

@tjkirch tjkirch marked this pull request as draft February 23, 2021 01:04
Copy link
Contributor

@srgothi92 srgothi92 left a comment

Choose a reason for hiding this comment

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

Nice ! 🎉

EvictionHardValue::try_from(*err).unwrap_err();
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: new line

@@ -62,6 +62,8 @@ pub mod error {
field: String,
source: serde_plain::Error,
},
#[snafu(display("Invalid eviction hard '{}': {}", input, msg))]
InvalideEvictionHard { input: String, msg: String },
Copy link
Contributor

Choose a reason for hiding this comment

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

we can create two different error enums, one for Key and other for value. So, that you don't have to specifically pass a msg string and we can include msg string as part of #[snafu(display to create string you want.
Did you refer it from somewhere, where we are using same enum ? I checked ECSAttributeKey and ECSAttributeValue we are using different error enum there.

Copy link
Member Author

Choose a reason for hiding this comment

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

Your suggestion could be a way as well. The reason why I make them as one is trying to make simple and clear. and I agree with you that different error enums could be a better way. Btw, I got this idea from KubernetesLableKey and KubernetesLabelValue.

Copy link
Contributor

@etungsten etungsten Feb 23, 2021

Choose a reason for hiding this comment

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

The reason why we have error variants like this is because there might be a lot of special cases we check for and capturing each one as a separate error variant would be too much when all we want to convey is the value is invalid for so-and-so reason. An example of this is InvalidSysctlKey.

If we only return this error in one location I would use #[snafu(display)]. If there's more than one check that check for different things that might return this, then I think having it like this is fine.

type Error = error::Error;

fn try_from(input: &str) -> Result<Self, Self::Error> {
let evitionsignal = vec![
Copy link
Contributor

Choose a reason for hiding this comment

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

we can also use enum here for example: https://github.com/bottlerocket-os/bottlerocket/blob/develop/sources/models/src/modeled_types/ecs.rs#L189
However, I don't know which aligns more to our existing style, I would let other comment on what we should use.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was trying to use enum to handle this part; however, I think enum could be not that efficient and clear there because too many works on dealing with variables which contains dots like memory.available. I got some ideas that if we can use rename attributes for each enum variant #[serde(rename = "memory.available")] , and I'm not sure if that worths. Appreciate for the comments! :)

Copy link
Contributor

@etungsten etungsten Feb 23, 2021

Choose a reason for hiding this comment

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

Another plus to just having it as an enum is being able to reuse it elsewhere (e.g. in your tests) for matching/validation etc.

I also wonder if we even need any of the traits here for converting to/from strings if EvictionHardKey itself was the enum. We've never tried that before but I don't see a clear reason why we can't just rely on serde's deserialization trait (with the appropriate attributes like you mentioned) for validation.

Copy link
Contributor

Choose a reason for hiding this comment

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

@gthao313 I think the rename attributes you mentioned above should allow us to use an enum. If so, that's probably the preferred route as other folks mentioned.

@@ -29,6 +29,8 @@ authorization:
clusterDomain: {{settings.kubernetes.cluster-domain}}
clusterDNS:
- {{settings.kubernetes.cluster-dns-ip}}
evictionHard:
Copy link
Contributor

Choose a reason for hiding this comment

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

what would happen if user does not set this setting ? I guess this setting would still exist in kubelet config without any value. Should we wrap setting in if ? for example:

{{~#if settings.kubernetes.evictionHard }}
evictionHard:
      {{join_map ": " "\n  " "no-fail-if-missing" settings.kubernetes.eviction-hard}}
{{~/if}}

I would let others weigh in, I am also learning in this commit :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct. The eviction-hard setting would still there and would not effect kubelet start. Your example is a good suggestion to me. Thanks 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes - I think we should wrap this in an if.

"nodefs.inodesFree" = "15Mi"
"pid.available" = "15%"
```


You can also optionally specify static pods for your node with the following settings.
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to that

@@ -29,6 +29,8 @@ authorization:
clusterDomain: {{settings.kubernetes.cluster-domain}}
clusterDNS:
- {{settings.kubernetes.cluster-dns-ip}}
evictionHard:
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes - I think we should wrap this in an if.

// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=

/// EvictionHardKey represents a string that contains a valid Kubernetes eviction hard
/// signal. There are few valid eviction hard signals [memory.available], [nodefs.available],
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Rather than naming the currently available values, let's just point to the relevant k8s page so if more are added or if they change, we don't need to remember to update this comment.

Available eviction hard signals: <link here>

type Error = error::Error;

fn try_from(input: &str) -> Result<Self, Self::Error> {
let evitionsignal = vec![
Copy link
Contributor

Choose a reason for hiding this comment

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

@gthao313 I think the rename attributes you mentioned above should allow us to use an enum. If so, that's probably the preferred route as other folks mentioned.

// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=

/// EvictionHardValue represents a string that contains a valid Kubernetes eviction threshold quantity
/// An eviction threshold can be expressed as Gi/Mi or a percentage using the % token
Copy link
Contributor

Choose a reason for hiding this comment

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

Same down here - let's just point to the docs rather than reiterating them.

fn try_from(input: &str) -> Result<Self, Self::Error> {

ensure!(
input.ends_with("Gi") || input.ends_with("Mi") || input.ends_with("%"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's make sure that these are the only values that are possible (Gi, Mi, %) I took a peek at the doc page, but perhaps I missed the listing of acceptable values.

@@ -62,6 +62,8 @@ pub mod error {
field: String,
source: serde_plain::Error,
},
#[snafu(display("Invalid eviction hard '{}': {}", input, msg))]
InvalideEvictionHard { input: String, msg: String },
Copy link
Contributor

Choose a reason for hiding this comment

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

s/InvalideEvictionHard/InvalidEvictionHard (There's an extra "e" after Invalid)

input.ends_with("Gi") || input.ends_with("Mi") || input.ends_with("%"),
error::InvalideEvictionHard {
input,
msg: format!("must be ends with Gi, Mi, or %"),
Copy link
Contributor

Choose a reason for hiding this comment

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

"must end with ..."

@gthao313 gthao313 closed this Feb 24, 2021
@gthao313 gthao313 deleted the new-setting branch February 24, 2021 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants