From 749134ccd32edf40fcbb3a0e590302208a03df40 Mon Sep 17 00:00:00 2001 From: gthao313 Date: Mon, 22 Feb 2021 23:50:56 +0000 Subject: [PATCH] Add new setting: eviction-hard --- README.md | 10 ++ packages/kubernetes-1.15/kubelet-config | 2 + packages/kubernetes-1.16/kubelet-config | 2 + packages/kubernetes-1.17/kubelet-config | 2 + packages/kubernetes-1.18/kubelet-config | 2 + packages/kubernetes-1.19/kubelet-config | 2 + sources/models/src/lib.rs | 3 +- .../models/src/modeled_types/kubernetes.rs | 117 ++++++++++++++++++ sources/models/src/modeled_types/mod.rs | 2 + 9 files changed, 141 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f388c0b4d6..6d0c40b7e9b 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,16 @@ The following settings are optional and allow you to further configure your clus * `settings.kubernetes.standalone-mode`: Whether to run the kubelet in standalone mode, without connecting to an API server. Defaults to `false`. * `settings.kubernetes.authentication-mode`: Which authentication method the kubelet should use to connect to the API server, and for incoming requests. Defaults to `aws` for AWS variants, and `tls` for other variants. * `settings.kubernetes.bootstrap-token`: The token to use for [TLS bootstrapping](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/). This is only used with the `tls` authentication mode, and is otherwise ignored. +* `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: + ``` + [settings.kubernetes.eviction-hard] + "memory.available" = "15%" + "nodefs.inodesFree" = "15Mi" + "pid.available" = "15%" + ``` + You can also optionally specify static pods for your node with the following settings. Static pods can be particularly useful when running in standalone mode. diff --git a/packages/kubernetes-1.15/kubelet-config b/packages/kubernetes-1.15/kubelet-config index 3ae6c21bec2..5ea10264227 100644 --- a/packages/kubernetes-1.15/kubelet-config +++ b/packages/kubernetes-1.15/kubelet-config @@ -29,6 +29,8 @@ authorization: clusterDomain: {{settings.kubernetes.cluster-domain}} clusterDNS: - {{settings.kubernetes.cluster-dns-ip}} +evictionHard: + {{join_map ": " "\n " "no-fail-if-missing" settings.kubernetes.eviction-hard}} resolvConf: "/etc/resolv.conf" hairpinMode: hairpin-veth cgroupDriver: systemd diff --git a/packages/kubernetes-1.16/kubelet-config b/packages/kubernetes-1.16/kubelet-config index 3ae6c21bec2..5ea10264227 100644 --- a/packages/kubernetes-1.16/kubelet-config +++ b/packages/kubernetes-1.16/kubelet-config @@ -29,6 +29,8 @@ authorization: clusterDomain: {{settings.kubernetes.cluster-domain}} clusterDNS: - {{settings.kubernetes.cluster-dns-ip}} +evictionHard: + {{join_map ": " "\n " "no-fail-if-missing" settings.kubernetes.eviction-hard}} resolvConf: "/etc/resolv.conf" hairpinMode: hairpin-veth cgroupDriver: systemd diff --git a/packages/kubernetes-1.17/kubelet-config b/packages/kubernetes-1.17/kubelet-config index 1a4007dba8d..0ff0e9a3dab 100644 --- a/packages/kubernetes-1.17/kubelet-config +++ b/packages/kubernetes-1.17/kubelet-config @@ -29,6 +29,8 @@ authorization: clusterDomain: {{settings.kubernetes.cluster-domain}} clusterDNS: - {{settings.kubernetes.cluster-dns-ip}} +evictionHard: + {{join_map ": " "\n " "no-fail-if-missing" settings.kubernetes.eviction-hard}} resolvConf: "/etc/resolv.conf" hairpinMode: hairpin-veth cgroupDriver: systemd diff --git a/packages/kubernetes-1.18/kubelet-config b/packages/kubernetes-1.18/kubelet-config index 1a4007dba8d..0ff0e9a3dab 100644 --- a/packages/kubernetes-1.18/kubelet-config +++ b/packages/kubernetes-1.18/kubelet-config @@ -29,6 +29,8 @@ authorization: clusterDomain: {{settings.kubernetes.cluster-domain}} clusterDNS: - {{settings.kubernetes.cluster-dns-ip}} +evictionHard: + {{join_map ": " "\n " "no-fail-if-missing" settings.kubernetes.eviction-hard}} resolvConf: "/etc/resolv.conf" hairpinMode: hairpin-veth cgroupDriver: systemd diff --git a/packages/kubernetes-1.19/kubelet-config b/packages/kubernetes-1.19/kubelet-config index 13aeb88f1f8..783941016bf 100644 --- a/packages/kubernetes-1.19/kubelet-config +++ b/packages/kubernetes-1.19/kubelet-config @@ -29,6 +29,8 @@ authorization: clusterDomain: {{settings.kubernetes.cluster-domain}} clusterDNS: - {{settings.kubernetes.cluster-dns-ip}} +evictionHard: + {{join_map ": " "\n " "no-fail-if-missing" settings.kubernetes.eviction-hard}} resolvConf: "/etc/resolv.conf" hairpinMode: hairpin-veth cgroupDriver: systemd diff --git a/sources/models/src/lib.rs b/sources/models/src/lib.rs index 9e221d59e45..23196ea3c9d 100644 --- a/sources/models/src/lib.rs +++ b/sources/models/src/lib.rs @@ -101,7 +101,7 @@ use crate::modeled_types::{ DNSDomain, ECSAgentLogLevel, ECSAttributeKey, ECSAttributeValue, FriendlyVersion, Identifier, KubernetesAuthenticationMode, KubernetesBootstrapToken, KubernetesClusterName, KubernetesLabelKey, KubernetesLabelValue, KubernetesTaintValue, - Lockdown, SingleLineString, SysctlKey, Url, ValidBase64, + Lockdown, SingleLineString, SysctlKey, Url, ValidBase64, EvictionHardKey, EvictionHardValue, }; // Kubernetes static pod manifest settings @@ -127,6 +127,7 @@ struct KubernetesSettings { authentication_mode: KubernetesAuthenticationMode, bootstrap_token: KubernetesBootstrapToken, standalone_mode: bool, + eviction_hard: HashMap, // Settings where we generate a value based on the runtime environment. The user can specify a // value to override the generated one, but typically would not. diff --git a/sources/models/src/modeled_types/kubernetes.rs b/sources/models/src/modeled_types/kubernetes.rs index e6c0d098a60..99fbcb78a16 100644 --- a/sources/models/src/modeled_types/kubernetes.rs +++ b/sources/models/src/modeled_types/kubernetes.rs @@ -437,3 +437,120 @@ mod test_kubernetes_bootstrap_token { } } } + +// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= + +/// EvictionHardKey represents a string that contains a valid Kubernetes eviction hard +/// signal. There are few valid eviction hard signals [memory.available], [nodefs.available], +/// [imagefs.available], and [nodefs.inodesFree]. +/// https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/ + + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct EvictionHardKey { + inner: String, +} + +impl TryFrom<&str> for EvictionHardKey { + type Error = error::Error; + + fn try_from(input: &str) -> Result { + let evitionsignal = vec![ + "memory.available","nodefs.available", + "nodefs.inodesFree","imagefs.available", + "imagefs.inodesFree","pid.available" + ]; + + ensure!( + evitionsignal.contains(&input), + error::InvalideEvictionHard { + input, + msg: format!("must be one of designated signals"), + } + ); + + Ok(EvictionHardKey { + inner: input.to_string(), + }) + } +} +string_impls_for!(EvictionHardKey, "EvictionHardKey"); + +#[cfg(test)] +mod test_kubernetes_eviction_hard_key { + use super::EvictionHardKey; + use std::convert::TryFrom; + + #[test] + fn good_eviction_hard_key() { + for ok in &[ + "memory.available", + "nodefs.available", + "nodefs.inodesFree", + "imagefs.available", + "imagefs.inodesFree", + "pid.available", + ] { + EvictionHardKey::try_from(*ok).unwrap(); + } + } + + #[test] + fn bad_eviction_hard_key() { + for err in &["", "storage.available", ".bad", "bad.", &"a".repeat(64)] { + EvictionHardKey::try_from(*err).unwrap_err(); + } + } +} + +// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= + +/// 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 +/// https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/ + + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct EvictionHardValue { + inner: String, +} + +impl TryFrom<&str> for EvictionHardValue { + type Error = error::Error; + + fn try_from(input: &str) -> Result { + + ensure!( + input.ends_with("Gi") || input.ends_with("Mi") || input.ends_with("%"), + error::InvalideEvictionHard { + input, + msg: format!("must be ends with Gi, Mi, or %"), + } + ); + + Ok(EvictionHardValue { + inner: input.to_string(), + }) + } +} +string_impls_for!(EvictionHardValue, "EvictionHardValue"); + +#[cfg(test)] +mod test_kubernetes_eviction_hard_value { + use super::EvictionHardValue; + use std::convert::TryFrom; + + #[test] + fn good_eviction_hard_value() { + for ok in &["10Gi", "500Mi", "30%"] { + EvictionHardValue::try_from(*ok).unwrap(); + } + } + + #[test] + fn bad_eviction_hard_value() { + for err in &["", "bad", "100", &"a".repeat(64)] { + EvictionHardValue::try_from(*err).unwrap_err(); + } + } +} \ No newline at end of file diff --git a/sources/models/src/modeled_types/mod.rs b/sources/models/src/modeled_types/mod.rs index 421b76135e4..d958a4ece88 100644 --- a/sources/models/src/modeled_types/mod.rs +++ b/sources/models/src/modeled_types/mod.rs @@ -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 }, } }