在运行中的集群上重新配置节点的 kubelet

    Caution: 动态 kubelet 配置 已经废弃不建议使用。请选择其他方法将配置分发到集群中的节点。

    允许你通过部署一个所有节点都会使用的 ConfigMap 达到在运行中的 Kubernetes 集群中更改 kubelet 配置的目的。

    Warning: 所有 kubelet 配置参数都可以被动态更改,但对某些参数来说这类更改是不安全的。 在决定动态更改参数之前,你需要深刻理解这个改动将会如何影响集群的行为。 在将变更扩散到整个集群之前,你需要先在小规模的节点集合上仔细地测试这些配置变动。 特定字段相关的配置建议可以在文档 KubeletConfiguration中找到。

    你需要一个 Kubernetes 集群。 你还需要 kubectl,并配置好与集群的通信。 To check the version, enter kubectl version. 确保你使用的 kubectl 版本与集群 兼容

    在某些例子中使用了命令行工具 。 你并不一定需要 jq 才能完成这些任务,因为总是有一些手工替代的方式。

    针对你重新配置的每个节点,你必须设置 kubelet 的标志 -dynamic-config-dir,使之指向一个可写的目录。

    重配置 集群中运行节点上的 kubelet

    在运行中的集群中配置 kubelet 的基本工作流程如下:

    1. 编写一个包含 kubelet 配置的 YAML 或 JSON 文件。
    2. 将此文件包装在 ConfigMap 中并将其保存到 Kubernetes 控制平面。
    3. 更新 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 也是合法的。

    Warning: 尽管通过就地更新 ConfigMap 来更改配置是 可能的。 但是这样做会导致所有使用该 ConfigMap 配置的 kubelet 同时更新。 更安全的做法是按惯例将 ConfigMap 视为不可变更的,借助于 kubectl--append-hash 选项逐步把更新推广到 node.spec.configSource

    以前,你需要手动创建 RBAC 规则以允许节点访问其分配的 ConfigMap。节点鉴权器现在 能够自动配置这些规则。

    动态 kubelet 配置特性允许你为整个配置对象提供一个重载配置,而不是靠单个字段的叠加。 这是一个更简单的模型,可以更轻松地跟踪配置值的来源,更便于调试问题。 然而,相应的代价是你必须首先了解现有配置,以确保你只更改你打算修改的字段。

    因为你需要知道运行时所使用的配置才能重载之,你可以从 kubelet 取回其运行时配置。 你可以通过访问 kubelet 的 configz 末端来生成包含节点当前配置的配置文件; 这一操作可以通过 kubectl proxy 来完成。 下一节解释如何完成这一操作。

    Caution: 组件 kubelet 上的 configz 末端是用来协助调试的,并非 kubelet 稳定行为的一部分。 请不要在产品环境下依赖此末端的行为,也不要在自动化工具中使用此末端。

    关于如何使用配置文件来配置 kubelet 行为的更多信息可参见 文档。

    生成配置文件

    Note: 下面的任务步骤中使用了 jq 命令以方便处理 JSON 数据。为了完成这里讲述的任务, 你需要安装 jq。如果你更希望手动提取 kubeletconfig 子对象,也可以对这里 的对应步骤做一些调整。

    1. 选择要重新配置的节点。在本例中,此节点的名称为 NODE_NAME

    2. 使用以下命令在后台启动 kubectl 代理:

    Note: 你需要手动将 kindapiVersion 添加到下载对象中,因为它们不是由 configz 末端 返回的。

    修改配置文件

    使用文本编辑器,改变上述操作生成的文件中一个参数。 例如,你或许会修改 QPS 参数 eventRecordQPS

    把配置文件推送到控制平面

    用以下命令把编辑后的配置文件推送到控制平面:

    1. kubectl -n kube-system create configmap my-node-config \
    2. --from-file=kubelet=kubelet_configz_${NODE_NAME} \
    3. --append-hash -o yaml

    下面是合法响应的一个例子:

    你会在 kube-system 命名空间中创建 ConfigMap,因为 kubelet 是 Kubernetes 的系统组件。

    --append-hash 选项给 ConfigMap 内容附加了一个简短校验和。 这对于先编辑后推送的工作流程很方便, 因为它自动并确定地为新 ConfigMap 生成新的名称。 在以下示例中,包含生成的哈希字符串的对象名被称为 CONFIG_MAP_NAME

    配置节点使用新的配置

    在你的文本编辑器中,在 spec 下增添以下 YAML:

    1. configSource:
    2. configMap:
    3. name: CONFIG_MAP_NAME
    4. namespace: kube-system
    5. kubeletConfigKey: kubelet

    你必须同时指定 namenamespacekubeletConfigKey 这三个属性。 kubeletConfigKey 这个参数通知 kubelet ConfigMap 中的哪个键下面包含所要的配置。

    观察节点开始使用新配置

    • active 是 kubelet 当前运行时所使用的版本。
    • assigned 参数是 kubelet 基于 node.spec.configSource 所解析出来的最新版本。
    • lastKnownGood 参数是 kubelet 的回退版本;如果在 node.spec.configSource 中 包含了无效的配置值,kubelet 可以回退到这个版本。

    如果用本地配置部署节点,使其设置成默认值,这个 lastKnownGood 配置可能不存在。 在 kubelet 配置好后,将更新 lastKnownGood 为一个有效的 assigned 配置。 决定如何确定某配置成为 lastKnownGood 配置的细节并不在 API 保障范畴, 不过目前实现中采用了 10 分钟的宽限期。

    你可以使用以下命令(使用 jq)过滤出配置状态:

    以下是一个响应示例:

    1. {
    2. "active": {
    3. "configMap": {
    4. "kubeletConfigKey": "kubelet",
    5. "name": "my-node-config-9mbkccg2cc",
    6. "namespace": "kube-system",
    7. "resourceVersion": "1326",
    8. "uid": "705ab4f5-6393-11e8-b7cc-42010a800002"
    9. }
    10. "assigned": {
    11. "configMap": {
    12. "name": "my-node-config-9mbkccg2cc",
    13. "namespace": "kube-system",
    14. "resourceVersion": "1326",
    15. "uid": "705ab4f5-6393-11e8-b7cc-42010a800002"
    16. }
    17. },
    18. "lastKnownGood": {
    19. "configMap": {
    20. "kubeletConfigKey": "kubelet",
    21. "name": "my-node-config-9mbkccg2cc",
    22. "namespace": "kube-system",
    23. "resourceVersion": "1326",
    24. "uid": "705ab4f5-6393-11e8-b7cc-42010a800002"
    25. }
    26. }
    27. }

    如果你没有安装 jq,你可以查看整个响应对象,查找其中的 node.status.config 部分。

    如果发生错误,kubelet 会在 Node.Status.Config.Error 中显示出错误信息的结构体。 错误可能出现在列表中。 你可以在 kubelet 日志中搜索相同的文本以获取更多详细信息和有关错误的上下文。

    做出更多的改变

    按照下面的工作流程做出更多的改变并再次推送它们。 你每次推送一个 ConfigMap 的新内容时,kubectl 的 --append-hash 选项都会给 ConfigMap 创建一个新的名称。 最安全的上线策略是首先创建一个新的 ConfigMap,然后更新节点以使用新的 ConfigMap。

    重置节点以使用其本地默认配置

    要重置节点,使其使用节点创建时使用的配置,可以用 kubectl edit node $ {NODE_NAME} 命令编辑节点,并删除 node.spec.configSource 字段。

    观察节点正在使用本地默认配置

    在删除此字段后,node.status.config 最终变成空,所有配置源都已重置为 nil。 这表示本地默认配置成为了 assignedactivelastKnownGood 配置, 并且没有报告错误。

    你可以使用几种不同的机制来更改节点的 configSource。

    本例使用kubectl patch

    1. 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)重新启动时,它会读取新的元数据并使用新配置。

    当记录的元数据已被完全解析时,意味着它包含选择一个指定的配置版本所需的所有信息 — 通常是 UIDResourceVersion。 这与 node.spec.configSource 形成对比,后者通过幂等的 namespace/name 声明来标识 目标 ConfigMap;kubelet 尝试使用此 ConfigMap 的最新版本。

    当你在调试节点上问题时,可以检查 kubelet 的配置元数据和检查点。kubelet 的检查点目录结构是:

    下表描述了使用动态 kubelet 配置时可能发生的错误消息。 你可以在 kubelet 日志中搜索相同的文本来获取有关错误的其他详细信息和上下文。

    What’s next

    • 说明了配置 kubelet 的方法。
    • 阅读 Node 的参考文档,包括 .spec 里的 configSource 字段

    最后修改 February 14, 2022 at 2:05 PM PST: