Kubernetes 通常被描述为一个声明式系统。大多数时候,您使用 YAML 来定义系统的最终状态应该是什么样子。不过,Kubernetes 也支持命令式 API,您可以在其中发出命令并立即获得输出。

在本文中,我们将探讨这两种对象管理形式之间的区别。即使您不认识这些术语,您也可能已经使用过这两种术语。

声明式与命令式:定义

首先,检查术语很有帮助。

声明性的东西是对最终结果的陈述,表明意图而不是实现它的过程。在 Kubernetes 中,这就是说“应该有一个包含三个 Pod 的 ReplicaSet”。

命令式充当命令。声明式是被动的,而命令式是主动且直接的:“创建一个包含三个 Pod 的 ReplicaSet”。

Kubernetes 生态系统提供了以这两种形式与您的集群交互的机制。命令式方法由 CLI 命令和单独的 YAML 文件提供。使用组合成最终资源表示的文件目录来促进声明式配置。

命令式管理对象

这是一个命令式创建部署的示例:

kubectl create deployment my-deployment --image my-image:latest

您正在指示 Kubernetes 立即将新部署添加到您的集群。该命令包括一个动词 ( create) 和您正在使用的资源类型的名称 ( deployment)。

您还可以编写一个 YAML 文件并使用以下create命令强制应用它:

apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
        # ...
kubectl create -f deployment.yml

和以前一样,Kubernetes 将从您的文件中获取配置并在集群中创建相应的资源。如果您需要更新资源,则必须修改 YAML 并使用replace命令来使更改生效:

kubectl replace -f deployment.yml

此操作将删除任何现有资源的规范并将其替换为配置文件中的版本。这通过replace命令的名称来传达。这意味着您将丢失对 YAML 中不存在的活动对象所做的任何更改。

当 Kubernetes 使用命令式命令时,需要准确地告诉它要做什么。因此,无法选择性地仅应用 YAML 的更改部分。为此,您需要切换到声明式操作。

尝试声明式管理

声明式管理仅在您使用 YAML 配置文件时可用。没有声明性命令之类的东西。当您使用声明式操作时,您不会通过提供动词 ( createreplace) 来告诉 Kubernetes 要做什么。相反,您使用单个apply命令并信任 Kubernetes 来制定要执行的操作。

继续上面的部署示例,上述 YAML 应用到您的集群最初的行为与  命令式create命令相同。一开始就不存在匹配的资源,因此 Kubernetes 必须创建一个新资源。

然后,您可以将该replicas字段更改为5并重复该apply命令。这次 Kubernetes 将匹配现有资源,检测 YAML 中的更改,并在不影响任何其他字段的情况下扩展部署。

使用命令式方法,您需要使用kubectl scale命令来更改现有部署的副本数。如果您修改了与 一起使用的 YAML kubectl create,则需要运行kubectl replace– 但这将替换部署的整个spec,而不是简单地扩展其副本数。

声明式与命令式:比较权衡

命令式操作很容易理解和推理。每个动作都表示为具有明确定义的后果的动词。出于这个原因,大多数人将使用命令式命令开始他们最早的 Kubernetes 交互,这些命令式命令可以松散地映射到其他技术,例如 Docker。

声明式管理暴露了 Kubernetes 的真正力量。你声明最终状态应该是什么样子,然后让 Kubernetes 完成剩下的工作。每个命令都有相同的命令性操作——apply这组 YAML 文件并将集群推进到它们定义的状态。

声明式管理是自动化部署的理想选择。每次更新资源时,您都不需要花时间制定一组迁移说明。相反,请调整您的 YAML,以便在当前重新创建它们时生成正确配置的对象。Kubernetes 将处理现有对象的更新,以便它们也匹配新状态。

声明性 YAML 文件很容易作为源代码控制系统的一部分进行版本控制、审查和合并。如果您使用命令式命令,您将无法跟踪您的集群是如何演变的,并且回滚到较早的状态会更加棘手。与命令式操作不同,声明式更新不会覆盖整个对象,因此您将保留通过其他机制所做的更改,而与您的 YAML 文件无关。

尽管如此,命令式管理确实保留了一些优势。声明式配置增加了复杂性,并且可能更难调试,尤其是当 Kubernetes 选择意外的操作过程时。每个更改都会导致合并和修补操作,以使您的对象与您想要的状态对齐。使用命令式模型,您所要求的就是您将得到的,除非发生错误。

与以往一样,当提供两种方法时,两种策略都是有用的,您选择哪一种应取决于具体情况。对于托管具有频繁更改的实时应用程序的生产集群,您可能需要版本化的声明性 YAML 文件。如果您在开发集群中快速启动新容器,命令式命令将节省时间并且更易于使用。

结论

声明式管理和命令式管理是与 Kubernetes 集群及其资源交互的两种方式。Kubectl 已经集成了对这两种策略的支持,但这些技术不应该在每个对象的基础上混合使用。如果您以声明方式创建对象,则应在其整个生命周期中以这种方式对其进行管理——对其使用命令式命令可能会导致意外行为。

命令式操作会影响集群中的活动对象。您可以通过命令参数和标志定义动词、资源和配置。kubectl diff声明式管理基于对本地配置文件的更改,当您使用andkubectl apply命令时,Kubectl 会区分并通过补丁应用到集群。

发表评论