kubectl apply 与 set/edit:选择正确的资源更新命令

在管理 Kubernetes 资源更新时,驾驭 `kubectl apply`(声明式)和 `kubectl set`/`kubectl edit`(命令式)之间的关键选择。本综合指南将详细介绍每个命令的工作原理、它们之间的根本区别以及何时有效使用它们。了解如何利用声明式管理来实现一致性和 GitOps,同时理解命令式命令在快速、临时修复中的作用。掌握最佳实践,以防止配置漂移,并确保稳定、可审计的 Kubernetes 部署。

35 浏览量

kubectl apply 与 set:选择正确的资源更新命令

Kubernetes 作为领先的容器编排平台,提供了强大的工具来管理应用程序的生命周期。管理的核心方面之一是更新现有的资源,如 Deployment、Service 或 ConfigMap。虽然 kubectl 提供了几个用于此目的的命令,但 kubectl applykubectl set/kubectl edit 系列代表了两种根本不同的理念:声明式更新与命令式更新。

理解何时以及如何使用每种方法对于维护稳定、可靠和可审计的 Kubernetes 部署至关重要。滥用这些命令可能导致配置漂移、调试困难和操作不一致。本文将深入探讨 kubectl applykubectl setkubectl edit 的细微差别,为您提供知识,以便在资源更新策略上做出明智的决策。

核心挑战:管理资源状态

在 Kubernetes 中,每个组件——从运行中的 Pod 到网络 Service——都表示为一个 API 对象。这些对象有一个期望状态,您在 YAML 或 JSON 清单文件中定义它;以及一个观测状态,它反映了它们在集群中的当前现实。任何 kubectl 更新命令的主要目标都是协调这两个状态,但协调方法却大不相同。

理解 kubectl apply:声明式方法

kubectl apply 是 Kubernetes 中声明式资源管理的基石。使用此方法,您可以在本地配置文件(或文件目录)中定义资源的期望状态,然后告诉 Kubernetes 使集群状态与该定义匹配。

kubectl apply 的工作原理(三向合并)

当您运行 kubectl apply -f your-manifest.yaml 时,Kubernetes 会执行复杂的三向三向合并three-way merge):

  1. 上次应用配置(Last Applied Configuration):使用 kubectl apply 上次应用时的资源状态。此状态存储在实时对象上的一个注解(kubectl.kubernetes.io/last-applied-configuration)中。
  2. 实时配置(Live Configuration):Kubernetes API 服务器中资源的当前状态。
  3. 新配置(New Configuration):在您的 your-manifest.yaml 文件中定义的状态。

The merge algorithm compares these three versions to determine what changes need to be made. It intelligently handles conflicts, prioritizing changes from the new configuration while respecting fields that have been imperatively modified since the last apply (though this can lead to issues, as discussed below).

该合并算法比较这三个版本,以确定需要进行哪些更改。它智能地处理冲突,优先考虑来自新配置的更改,同时尊重自上次应用以来被命令式修改过的字段(尽管如下文所述,这可能导致问题)。

此过程确保了幂等性:只要没有发生其他更改,多次应用相同的清单将产生相同的集群状态,而不会产生意外的副作用。

应用 Deployment 的实际示例

假设您有一个 deployment.yaml 文件:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-webapp
  labels:
    app: my-webapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-webapp
  template:
    metadata:
      labels:
        app: my-webapp
    spec:
      containers:
      - name: webapp-container
        image: nginx:1.21.0
        ports:
        - containerPort: 80

要创建或更新此部署,您将运行:

kubectl apply -f deployment.yaml

如果您稍后在 deployment.yaml 中将 image 更改为 nginx:1.22.0 并再次运行 kubectl apply,Kubernetes 将更新 Deployment 以使用新映像,同时保留其他设置。

kubectl apply 的优势

  • 事实来源 (Source of Truth):您的配置文件成为集群期望状态的单一事实来源。这与 GitOps 原则非常吻合。
  • 可审计性和版本控制:更改记录在您的版本控制系统(例如 Git)中,提供了清晰的审计跟踪和轻松的回滚。
  • 一致性:确保跨环境(开发、暂存、生产)的一致性。
  • 幂等性:重复的 apply 操作具有相同的效果,防止意外修改。
  • 复杂更新:处理涉及多种资源类型或跨多个字段的重大更改的复杂更新。

何时使用 kubectl apply

  • 所有资源创建和更新的主要方法。
  • 通过 CI/CD 流水线部署应用程序时。
  • 用于管理基础设施即代码。
  • 团队协作以确保配置一致性时。

kubectl apply 的提示和警告

  • 始终保持清单文件与期望状态同步。任何未反映在清单文件中的 kubectl setkubectl edit 更改都将在下次 apply 时被覆盖或导致合并冲突。
  • 字段管理器 (Field Managers):Kubernetes 1.16+ 引入了服务器端应用 (SSA),它跟踪负责资源中每个字段的“字段管理器”(例如 kubectl、控制器)。这有助于防止多个源修改同一资源时发生冲突。虽然功能强大,但请注意不同工具如何与字段管理交互。

理解 kubectl setkubectl edit:命令式方法

kubectl setkubectl edit 属于命令式命令家族。您不是在文件中定义期望状态,而是直接指示 Kubernetes 在集群内执行特定操作或修改实时对象。这些命令非常适合快速、临时性的更改,但也有一定的注意事项。

kubectl set:专注的命令式修改

kubectl set 旨在对资源进行特定的、常见的修改,而无需触及清单文件。它提供了几个子命令来修改特定字段。

kubectl set 的工作原理

kubectl set 根据您提供的命令行参数直接修改 Kubernetes API 服务器中的实时对象。它不会与本地清单文件交互,也不会更新 last-applied-configuration 注解。

设置映像的实际示例

要更新名为 my-webapp 的部署中容器的映像:

kubeclt set image deployment/my-webapp webapp-container=nginx:1.22.0

此命令直接修改 my-webapp Deployment 中 webapp-containerimage 字段。如果您之前使用 kubectl apply 管理过 my-webapp,此更改将在本地 deployment.yaml 和实时集群状态之间创建“漂移”。

其他常见的 kubectl set 命令:

  • kubectl set resources:设置资源请求/限制。
  • kubectl set env:添加或更新环境变量。
  • kubectl set selector:修改资源的选定器。

kubectl edit:交互式命令式修改

kubectl edit 允许您使用配置的默认文本编辑器(例如 vinano)直接修改集群中实时资源对象的任何字段。

kubectl edit 的工作原理

当您运行 kubectl edit <resource-type>/<resource-name> 时:

  1. kubectl 从 API 服务器获取实时资源的当前 YAML 定义。
  2. 它在您的本地文本编辑器中打开此定义。
  3. 您进行所需的更改并保存文件。
  4. 然后 kubectl 将修改后的定义发送回 API 服务器,服务器会尝试应用更改。如果存在语法错误或无效字段,更改将被拒绝。

kubectl set 一样,kubectl edit 也直接操作实时对象,不会更新本地清单文件或 last-applied-configuration 注解。

编辑 Deployment 的实际示例

要在编辑器中打开 my-webapp 部署:

kubeclt edit deployment/my-webapp

您的编辑器将打开实时部署的 YAML 表示。然后您可以更改 replicasimage 等字段,或添加新的注解/标签。保存并关闭编辑器后,kubectl 会尝试应用这些更改。

kubectl setkubectl edit 的优势

  • 速度:非常适合在开发环境中进行快速、一次性的修复或调试。
  • 灵活性:直接修改资源的任何字段(使用 edit)。
  • 临时性更改:当您手头没有现成的清单文件或不想为微小更改创建文件时非常有用。

何时使用 kubectl set/kubectl edit

  • 在开发/暂存集群中进行调试:临时增加副本数量或更改映像以测试修复。
  • 在非生产环境中进行小的、非关键的、临时性的更改。
  • 探索资源定义kubectl edit 是一种查看资源完整实时 YAML 的便捷方式。

kubectl setkubectl edit 的警告

  • 配置漂移 (Configuration Drift):使用 setedit 所做的更改不会反映在您的本地清单文件中。下次从清单文件运行 kubectl apply 将覆盖这些命令式更改或导致冲突。
  • 缺乏可审计性:这些更改未在版本控制中跟踪,使得难以了解谁在何时更改了什么,从而阻碍了调试和合规性。
  • 非幂等性:如果初始状态未知,重复执行相同的命令式更改可能导致意外行为。
  • 出错风险:手动编辑(尤其使用 edit)会增加引入语法错误或无效配置的机会。

关键区别:kubectl applykubectl set/kubectl edit

总结核心区别:

特性 kubectl apply (声明式) kubectl set/kubectl edit (命令式)
方法 在文件中定义期望状态,Kubernetes 协调。 直接操作实时对象或特定字段。
事实来源 本地配置文件(例如 Git 仓库)。 实时集群对象本身(短暂的)。
幂等性 是的,应用相同文件会产生相同结果。 不是,本质上不是。每个命令都是一个明确的操作。
可审计性 高(更改记录在 Git 中,有 last-applied-configuration)。 低(没有版本控制,更改立即在集群上发生)。
冲突管理 三向合并,使用 last-applied-configuration 注解。 直接覆盖(对于 set)或交互式合并(对于 edit)。
使用场景 生产部署、CI/CD、GitOps、团队协作。 快速修复、调试、非生产环境中的临时更改。
漂移风险 低,只要文件保持最新。 高,极有可能导致与源文件配置漂移。

选择正确的命令:最佳实践

对于生产环境和协作团队,选择是明确的:

  • 始终优先使用 kubectl apply(或基于它的 GitOps 工具,如 Argo CD 或 Flux CD)来管理 Kubernetes 资源。 这可确保您的集群状态经过版本控制、可审计且一致。
  • 将您的 Kubernetes 清单文件视为单一事实来源。 所有对资源配置的更改理想情况下都应源自这些文件并提交到版本控制中。

kubectl setkubectl edit 这样的命令式命令应保留用于:

  • 在开发/暂存集群中进行临时调试或测试。 如果您使用它们,请确保您要恢复更改,或者立即更新源清单文件以反映新状态。
  • 不代表长期期望状态的一次性、短暂操作(例如,暂时暂停部署)。

混合方法(谨慎使用)

在某些情况下,您可能会发现需要在生产环境中快速修复一些问题。虽然通常不鼓励这样做,但如果您必须使用 kubectl edit

  1. 了解配置漂移的影响。
  2. 立即捕获更改,方法是运行 kubectl get <resource> -o yaml > new-manifest.yaml
  3. 尽快将这些更改集成到您的版本控制的清单文件中。

警告:定期在生产环境中使用 kubectl editkubectl set 而不更新源清单文件,将导致集群状态变得无法管理、无法恢复,其中实际配置与团队认为的配置严重不符。

结论

kubectl applykubectl setkubectl edit 都是与 Kubernetes 集群交互的强大工具。然而,它们服务于不同的目的,体现了不同的资源管理理念。通过理解 kubectl apply 的声明式特性以及 kubectl setkubectl edit 的命令式特性,您可以采用最佳实践,从而实现更稳定、更可靠、更易于维护的 Kubernetes 部署。

对于几乎所有持久性资源管理,尤其是在生产环境中,请拥抱 kubectl apply 并对您的配置文件进行版本控制。将命令式命令保留用于临时、临时的故障排除,并确保任何关键更改都能快速反映回您的声明式清单中。这种纪律对于在 Kubernetes 环境中实现顺利的操作和无缝的协作将是无价的。