在运行中的集群上重新配置节点的 kubelet
Kubernetes v1.22 [deprecated]
注意: 动态 kubelet 配置 已经废弃不建议使用。请选择其他方法将配置分发到集群中的节点。
动态 kubelet 配置 允许你通过部署一个所有节点都会使用的 ConfigMap 达到在运行中的 Kubernetes 集群中更改 kubelet 配置的目的。
警告: 所有 kubelet 配置参数都可以被动态更改,但对某些参数来说这类更改是不安全的。 在决定动态更改参数之前,你需要深刻理解这个改动将会如何影响集群的行为。 在将变更扩散到整个集群之前,你需要先在小规模的节点集合上仔细地测试这些配置变动。 特定字段相关的配置建议可以在文档KubeletConfiguration
中找到。
准备开始
你需要一个 Kubernetes 集群。
你需要 v1.11 或更高版本的 kubectl,并配置好与集群的通信。
要获知版本信息,请输入 kubectl version
.
你的集群 API 服务器版本(如 v1.12)不能和你的 kubectl
版本相差超过一个小版本号。
例如,如果你的集群在运行 v1.16,那么你可以使用 v1.15、v1.16、v1.17 的 kubectl,
所有其他的组合都是
不支持的。
在某些例子中使用了命令行工具 jq。
你并不一定需要 jq
才能完成这些任务,因为总是有一些手工替代的方式。
针对你重新配置的每个节点,你必须设置 kubelet 的标志
-dynamic-config-dir
,使之指向一个可写的目录。
重配置 集群中运行节点上的 kubelet
基本工作流程概览
在运行中的集群中配置 kubelet 的基本工作流程如下:
- 编写一个包含 kubelet 配置的 YAML 或 JSON 文件。
- 将此文件包装在 ConfigMap 中并将其保存到 Kubernetes 控制平面。
- 更新 kubelet 所在节点对象以使用此 ConfigMap。
每个 kubelet 都会在其各自的节点对象上监测(Watch)配置引用。当引用更改时,kubelet 将下载新的配置文件, 更新本地引用指向该文件,然后退出。 为了使该功能正常地工作,你必须运行操作系统级别的服务管理器(如 systemd), 它将会在 kubelet 退出后将其重启。 kubelet 重新启动时,将开始使用新配置。
新配置将会完全地覆盖 --config
所提供的配置,并被命令行标志覆盖。
新配置中未指定的值将收到适合配置版本的默认值
(e.g. kubelet.config.k8s.io/v1beta1
),除非被命令行标志覆盖。
节点 kubelet 配置状态可通过 node.spec.status.config
获取。
一旦你更新了一个节点去使用新的 ConfigMap,
就可以通过观察此状态来确认该节点是否正在使用预期配置。
本文中使用命令 kubectl edit
来编辑节点,还有其他的方式可以修改节点的规约,
比如更利于脚本化工作流程的 kubectl patch
。
本文仅仅讲述在单节点上使用每个 ConfigMap。请注意对于多个节点使用相同的 ConfigMap 也是合法的。
警告: 尽管通过就地更新 ConfigMap 来更改配置是 可能的。 但是这样做会导致所有使用该 ConfigMap 配置的 kubelet 同时更新。 更安全的做法是按惯例将 ConfigMap 视为不可变更的,借助于kubectl
的--append-hash
选项逐步把更新推广到node.spec.configSource
。
节点鉴权器的自动 RBAC 规则
以前,你需要手动创建 RBAC 规则以允许节点访问其分配的 ConfigMap。节点鉴权器现在 能够自动配置这些规则。
生成包含当前配置的文件
动态 kubelet 配置特性允许你为整个配置对象提供一个重载配置,而不是靠单个字段的叠加。 这是一个更简单的模型,可以更轻松地跟踪配置值的来源,更便于调试问题。 然而,相应的代价是你必须首先了解现有配置,以确保你只更改你打算修改的字段。
组件 kubelet 从其配置文件中加载配置数据,不过你可以通过设置命令行标志 来重载文件中的一些配置。这意味着,如果你仅知道配置文件的内容,而你不知道 命令行重载了哪些配置,你就无法知道 kubelet 的运行时配置是什么。
因为你需要知道运行时所使用的配置才能重载之,你可以从 kubelet 取回其运行时配置。
你可以通过访问 kubelet 的 configz
末端来生成包含节点当前配置的配置文件;
这一操作可以通过 kubectl proxy
来完成。
下一节解释如何完成这一操作。
注意: 组件kubelet
上的configz
末端是用来协助调试的,并非 kubelet 稳定行为的一部分。 请不要在产品环境下依赖此末端的行为,也不要在自动化工具中使用此末端。
关于如何使用配置文件来配置 kubelet 行为的更多信息可参见 通过配置文件设置 kubelet 参数 文档。
生成配置文件
说明: 下面的任务步骤中使用了jq
命令以方便处理 JSON 数据。为了完成这里讲述的任务, 你需要安装jq
。如果你更希望手动提取kubeletconfig
子对象,也可以对这里 的对应步骤做一些调整。
-
选择要重新配置的节点。在本例中,此节点的名称为
NODE_NAME
。 -
使用以下命令在后台启动 kubectl 代理:
kubectl proxy --port=8001 &
-
运行以下命令从
configz
端点中下载并解压配置。这个命令很长,因此在复制粘贴时要小心。 如果你使用 zsh,请注意常见的 zsh 配置要添加反斜杠转义 URL 中变量名称周围的大括号。 例如:在粘贴时,${NODE_NAME}
将被重写为$\{NODE_NAME\}
。 你必须在运行命令之前删除反斜杠,否则命令将失败。NODE_NAME="the-name-of-the-node-you-are-reconfiguring"; curl -sSL "http://localhost:8001/api/v1/nodes/${NODE_NAME}/proxy/configz" | jq '.kubeletconfig|.kind="KubeletConfiguration"|.apiVersion="kubelet.config.k8s.io/v1beta1"' > kubelet_configz_${NODE_NAME}
说明: 你需要手动将kind
和apiVersion
添加到下载对象中,因为它们不是由configz
末端 返回的。
修改配置文件
使用文本编辑器,改变上述操作生成的文件中一个参数。
例如,你或许会修改 QPS 参数 eventRecordQPS
。
把配置文件推送到控制平面
用以下命令把编辑后的配置文件推送到控制平面:
kubectl -n kube-system create configmap my-node-config \
--from-file=kubelet=kubelet_configz_${NODE_NAME} \
--append-hash -o yaml
下面是合法响应的一个例子:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2017-09-14T20:23:33Z
name: my-node-config-gkt4c2m4b2
namespace: kube-system
resourceVersion: "119980"
selfLink: /api/v1/namespaces/kube-system/configmaps/my-node-config-gkt4c2m4b2
uid: 946d785e-998a-11e7-a8dd-42010a800006
data:
kubelet: |
{...}
你会在 kube-system
命名空间中创建 ConfigMap,因为 kubelet 是 Kubernetes 的系统组件。
--append-hash
选项给 ConfigMap 内容附加了一个简短校验和。
这对于先编辑后推送的工作流程很方便,
因为它自动并确定地为新 ConfigMap 生成新的名称。
在以下示例中,包含生成的哈希字符串的对象名被称为 CONFIG_MAP_NAME
。
配置节点使用新的配置
kubectl edit node ${NODE_NAME}
在你的文本编辑器中,在 spec
下增添以下 YAML:
configSource:
configMap:
name: CONFIG_MAP_NAME
namespace: kube-system
kubeletConfigKey: kubelet
你必须同时指定 name
、namespace
和 kubeletConfigKey
这三个属性。
kubeletConfigKey
这个参数通知 kubelet ConfigMap 中的哪个键下面包含所要的配置。
观察节点开始使用新配置
用 kubectl get node ${NODE_NAME} -o yaml
命令读取节点并检查 node.status.config
内容。
状态部分报告了对应 active
(使用中的)配置、assigned
(被赋予的)配置和
lastKnownGood
(最近已知可用的)配置的配置源。
active
是 kubelet 当前运行时所使用的版本。assigned
参数是 kubelet 基于node.spec.configSource
所解析出来的最新版本。lastKnownGood
参数是 kubelet 的回退版本;如果在node.spec.configSource
中 包含了无效的配置值,kubelet 可以回退到这个版本。
如果用本地配置部署节点,使其设置成默认值,这个 lastKnownGood
配置可能不存在。
在 kubelet 配置好后,将更新 lastKnownGood
为一个有效的 assigned
配置。
决定如何确定某配置成为 lastKnownGood
配置的细节并不在 API 保障范畴,
不过目前实现中采用了 10 分钟的宽限期。
你可以使用以下命令(使用 jq
)过滤出配置状态:
kubectl get no ${NODE_NAME} -o json | jq '.status.config'
以下是一个响应示例:
{
"active": {
"configMap": {
"kubeletConfigKey": "kubelet",
"name": "my-node-config-9mbkccg2cc",
"namespace": "kube-system",
"resourceVersion": "1326",
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002"
}
},
"assigned": {
"configMap": {
"kubeletConfigKey": "kubelet",
"name": "my-node-config-9mbkccg2cc",
"namespace": "kube-system",
"resourceVersion": "1326",
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002"
}
},
"lastKnownGood": {
"configMap": {
"kubeletConfigKey": "kubelet",
"name": "my-node-config-9mbkccg2cc",
"namespace": "kube-system",
"resourceVersion": "1326",
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002"
}
}
}
如果你没有安装 jq
,你可以查看整个响应对象,查找其中的 node.status.config
部分。
如果发生错误,kubelet 会在 Node.Status.Config.Error
中显示出错误信息的结构体。
错误可能出现在列表理解节点状态配置错误信息中。
你可以在 kubelet 日志中搜索相同的文本以获取更多详细信息和有关错误的上下文。
做出更多的改变
按照下面的工作流程做出更多的改变并再次推送它们。
你每次推送一个 ConfigMap 的新内容时,kubeclt 的 --append-hash
选项都会给
ConfigMap 创建一个新的名称。
最安全的上线策略是首先创建一个新的 ConfigMap,然后更新节点以使用新的 ConfigMap。
重置节点以使用其本地默认配置
要重置节点,使其使用节点创建时使用的配置,可以用
kubectl edit node $ {NODE_NAME}
命令编辑节点,并删除 node.spec.configSource
字段。
观察节点正在使用本地默认配置
在删除此字段后,node.status.config
最终变成空,所有配置源都已重置为 nil
。
这表示本地默认配置成为了 assigned
、active
和 lastKnownGood
配置,
并且没有报告错误。
kubectl patch
示例
你可以使用几种不同的机制来更改节点的 configSource。
本例使用kubectl patch
:
kubectl patch node ${NODE_NAME} -p "{\"spec\":{\"configSource\":{\"configMap\":{\"name\":\"${CONFIG_MAP_NAME}\",\"namespace\":\"kube-system\",\"kubeletConfigKey\":\"kubelet\"}}}}"
了解 Kubelet 如何为配置生成检查点
当为节点赋予新配置时,kubelet 会下载并解压配置负载为本地磁盘上的一组文件。
kubelet 还记录一些元数据,用以在本地跟踪已赋予的和最近已知良好的配置源,以便
kubelet 在重新启动时知道使用哪个配置,即使 API 服务器变为不可用。
在为配置信息和相关元数据生成检查点之后,如果检测到已赋予的配置发生改变,则 kubelet 退出。
当 kubelet 被 OS 级服务管理器(例如 systemd
)重新启动时,它会读取新的元数据并使用新配置。
当记录的元数据已被完全解析时,意味着它包含选择一个指定的配置版本所需的所有信息
-- 通常是 UID
和 ResourceVersion
。
这与 node.spec.configSource
形成对比,后者通过幂等的 namespace/name
声明来标识
目标 ConfigMap;kubelet 尝试使用此 ConfigMap 的最新版本。
当你在调试节点上问题时,可以检查 kubelet 的配置元数据和检查点。kubelet 的检查点目录结构是:
- --dynamic-config-dir (用于管理动态配置的根目录)
|-- meta
| - assigned (编码后的 kubeletconfig/v1beta1.SerializedNodeConfigSource 对象,对应赋予的配置)
| - last-known-good (编码后的 kubeletconfig/v1beta1.SerializedNodeConfigSource 对象,对应最近已知可用配置)
| - checkpoints
| - uid1 (用 uid1 来标识的对象版本目录)
| - resourceVersion1 (uid1 对象 resourceVersion1 版本下所有解压文件的目录)
| - ...
| - ...
理解 Node.Status.Config.Error
消息
下表描述了使用动态 kubelet 配置时可能发生的错误消息。 你可以在 kubelet 日志中搜索相同的文本来获取有关错误的其他详细信息和上下文。
错误信息 | 可能的原因 |
---|---|
failed to load config, see Kubelet log for details | kubelet 可能无法解析下载配置的有效负载,或者当尝试从磁盘中加载有效负载时,遇到文件系统错误。 |
failed to validate config, see Kubelet log for details | 有效负载中的配置,与命令行标志所产生的覆盖配置以及特行门控的组合、配置文件本身、远程负载被 kubelet 判定为无效。 |
invalid NodeConfigSource, exactly one subfield must be non-nil, but all were nil | 由于 API 服务器负责对 node.spec.configSource 执行验证,检查其中是否包含至少一个非空子字段,这个消息可能意味着 kubelet 比 API 服务器版本低,因而无法识别更新的源类型。 |
failed to sync: failed to download config, see Kubelet log for details | kubelet 无法下载配置数据。可能是 node.spec.configSource 无法解析为具体的 API 对象,或者网络错误破坏了下载。处于此错误状态时,kubelet 将重新尝试下载。 |
failed to sync: internal failure, see Kubelet log for details | kubelet 遇到了一些内部问题,因此无法更新其配置。 例如:发生文件系统错误或无法从内部缓存中读取对象。 |
internal failure, see Kubelet log for details | 在对配置进行同步的循环之外操作配置时,kubelet 遇到了一些内部问题。 |
接下来
- 关于如何通过配置文件来配置 kubelet 的更多细节信息,可参阅 使用配置文件设置 kubelet 参数.
- 阅读 API 文档中
NodeConfigSource
说明 - 查阅
KubeletConfiguration
文献进一步了解 kubelet 配置信息。