声明式 API 验证

特性状态: Kubernetes v1.33 [beta]

Kubernetes 1.36 包含了可选的声明式验证 (declarative validation) API。启用后,Kubernetes API 服务器可以使用此机制,而不是依赖手工编写的 Go 代码(validation.go 文件)的传统方法来确保 API 请求是有效的。Kubernetes 开发人员以及扩展 Kubernetes API 的人员,可以直接在 API 类型定义(types.go 文件)旁边定义验证规则。代码编写者定义特殊的注释标签(例如 +k8s:minimum=0),代码生成器(validation-gen)随后使用这些标签生成优化的 Go 代码用于 API 验证。

虽然此功能主要影响 Kubernetes 贡献者以及可能开发扩展 API 服务器的开发者,但集群管理员也应了解其行为,尤其是在其发布阶段。

声明式验证标签可以直接应用于全新的 API 字段,而无需任何生命周期机制(例如,可以使用 +k8s:minimum=1)。对于迁移现有的手工验证,且声明式验证正在替代现有的手工验证逻辑的情况,发布过程由验证生命周期标签(+k8s:alpha+k8s:beta)配合 DeclarativeValidationBeta 特性门控(feature gate)进行控制。

  • DeclarativeValidation:(v1.36 中为 GA,默认:true,锁定为默认:true)API 服务器对已迁移的类型/字段同时运行新的声明式验证旧的手工验证(处于“影子模式”,即 Alpha)。结果会在内部进行比较。
  • DeclarativeValidationBeta:(Beta,默认:true)v1.36 引入。此门控控制 Beta 阶段验证规则的执行。启用时,标记为 +k8s:beta 的规则具有权威性;禁用时,它们将回退到影子模式。
  • DeclarativeValidationTakeover:(v1.36 中已弃用)。以前用于确定声明式验证结果是否具有权威性。它不再被采纳,但仍可设置以避免“门控无法识别”错误。

默认行为(Kubernetes 1.36)

  • DeclarativeValidationBeta=true(默认值)时,两个验证系统都会对 Alpha 和影子规则进行运行。Beta 规则会被强制执行。
  • 手工验证的结果用于 Alpha 规则。声明式验证以不匹配模式运行以进行比较。
  • 两个验证系统之间的不匹配由 API 服务器记录,并增加 declarative_validation_mismatch_total 指标。这些数据允许贡献者在影子阶段识别并解决差异。

如果观察到意外的验证行为或回归,管理员可以显式禁用 DeclarativeValidationBeta 特性门控,强制 +k8s:beta 验证规则回退到影子模式。

禁用 DeclarativeValidationBeta

作为集群管理员,您可以在以下特定情况下考虑将 DeclarativeValidationBeta 设置为 false

  • 意外的验证行为: 如果启用 DeclarativeValidationBeta 导致了意外的验证错误,或允许了之前视为无效的对象。
  • 性能回归: 如果监控指标显示显著的延迟增加(例如 apiserver_request_duration_seconds),且与该功能的启用相关联。
  • 高不匹配率: 如果 declarative_validation_mismatch_total 指标显示频繁的不匹配,表明声明式规则中可能存在影响集群工作负载的潜在 bug,即使 DeclarativeValidationBeta 为 false 时也是如此。

要将 +k8s:beta 验证规则回退到影子模式,请禁用 DeclarativeValidationBeta 特性门控,例如通过命令行参数:(--feature-gates=DeclarativeValidationBeta=false)。

降级和回滚的考量

禁用 DeclarativeValidationBeta 特性门控是一种安全机制。然而,请注意一种边缘情况(由于广泛测试,认为可能性极低):如果在声明式验证中存在一个 bug(当 DeclarativeValidationBeta=true 时),错误地允许持久化了一个无效对象,那么禁用该特性门控可能会导致随后对该特定对象的更新被现在具有权威性(且正确)的手工验证所阻止。解决此问题可能需要手动更正存储的对象,在极少数情况下可能需要直接修改 etcd。

有关管理特性门控的详细信息,请参阅特性门控

声明式验证标签参考

本文档提供了所有可用声明式验证标签的综合参考。

标签目录

标签描述稳定性
+k8s:alpha将验证标签置于影子模式(仅记录指标)。稳定 (Stable)
+k8s:beta将验证标签置于强制执行模式(可通过 DeclarativeValidationBeta 禁用)。稳定 (Stable)
+k8s:eachKey为映射(map)中的每个键声明验证。Alpha
+k8s:eachVal为映射或列表中的每个值声明验证。Alpha
+k8s:enum指示字符串类型为枚举。Beta
+k8s:forbidden指示字段不可指定。Alpha
+k8s:format指示字符串字段具有特定格式。稳定 (Stable)
+k8s:ifDisabled声明仅在选项被禁用时适用的验证。Alpha
+k8s:ifEnabled声明仅在选项被启用时适用的验证。Alpha
+k8s:isSubresource指定包中的验证仅适用于特定的子资源。稳定 (Stable)
+k8s:item为声明为 +k8s:listType=map 的切片项声明验证。稳定 (Stable)
+k8s:listMapKey声明列表值类型的命名子字段作为列表映射键的一部分。稳定 (Stable)
+k8s:listType声明列表字段的语义类型。稳定 (Stable)
+k8s:maxItems指示列表字段的大小有限制。稳定 (Stable)
+k8s:maxLength指示字符串字段的长度有限制。稳定 (Stable)
+k8s:minimum指示数值字段具有最小值。稳定 (Stable)
+k8s:neq验证字段值不等于特定的禁止值。Alpha
+k8s:opaqueType指示引用类型上的任何声明验证将被忽略。Alpha
+k8s:optional指示客户端可选此字段。稳定 (Stable)
+k8s:required指示客户端必须指定此字段。稳定 (Stable)
+k8s:subfield声明结构体子字段的验证。稳定 (Stable)
+k8s:supportsSubresource声明包内类型支持的子资源。稳定 (Stable)
+k8s:unionDiscriminator指示此字段是联合(union)的判别符。稳定 (Stable)
+k8s:unionMember指示此字段是联合组的成员。稳定 (Stable)
+k8s:zeroOrOneOfMember指示此字段是“零或一”成员组的成员。稳定 (Stable)

标签参考

+k8s:alpha

描述

+k8s:alpha 标签为验证规则启用影子模式。它代表了将现有的手工验证逻辑安全迁移到声明式标签的验证生命周期的第一阶段。不要将此标签用于全新的 API 字段,全新的字段应直接应用声明式验证标签。

当验证被 +k8s:alpha 影子化时,执行的验证逻辑包括原始的手工验证逻辑,同时以非阻塞方式运行影子声明式验证,并验证结果是否匹配。任何不匹配或 panic 都会通过指标记录(例如:declarative_validation_mismatch_totaldeclarative_validation_panic_total)。此影子机制使贡献者和管理员能够在实时环境中评估声明式验证规则,而不影响集群行为。通过监控不匹配指标,您可以在将验证升级到 beta 之前验证声明式规则的行为与现有手工逻辑完全相同。

稳定性级别: 稳定 (Stable)

参数

  • since(字符串,必填):该验证首次被影子化的 Kubernetes 版本。

负载

  • <validation-tag>:要影子化的标准声明式验证标签(例如 +k8s:minimum=1)。

使用示例

type MyStruct struct {
    // +k8s:alpha(since:"1.36")=+k8s:minimum=1
    MyField int `json:"myField"`
}

+k8s:beta

描述

+k8s:beta 标签为从手工逻辑迁移的验证规则启用强制执行模式,受 DeclarativeValidationBeta 特性门控控制。不要将此标签用于全新的 API 字段,全新的字段应直接应用声明式验证标签。

当验证规则在影子模式(通过 +k8s:alpha)下评估后,它会被提升为 beta。当启用 DeclarativeValidationBeta(默认)时,+k8s:beta 规则将被强制执行并具有权威性。禁用该特性门控会将 +k8s:beta 规则回退到影子模式,如果发生回归,这提供了回滚机制。

稳定性级别: 稳定 (Stable)

参数

  • since(字符串,必填):验证被提升为 beta 的 Kubernetes 版本。

负载

  • <validation-tag>:要强制执行的标准声明式验证标签(例如 +k8s:minimum=1)。

使用示例

type MyStruct struct {
    // +k8s:beta(since:"1.37")=+k8s:minimum=1
    MyField int `json:"myField"`
}

+k8s:eachKey

描述

为映射(map)中的每个键声明验证。

稳定性级别: Alpha

负载

  • <validation-tag>:针对每个键进行评估的标签。

使用示例

type MyStruct struct {
    // +k8s:eachKey=+k8s:minimum=1
    MyMap map[int]string `json:"myMap"`
}

在此示例中,eachKey 用于指定 +k8s:minimum 标签应应用于 MyMap 中的每个 int 键。这意味着映射中的所有键都必须 >= 1。

+k8s:eachVal

描述

为映射或列表中的每个值声明验证。

稳定性级别: Alpha

负载

  • <validation-tag>:针对每个值进行评估的标签。

使用示例

type MyStruct struct {
    // +k8s:eachVal=+k8s:minimum=1
    MyMap map[string]int `json:"myMap"`
}

在此示例中,eachVal 用于指定 +k8s:minimum 标签应应用于 MyList 中的每个元素。这意味着 MyStruct 中的所有字段都必须 >= 1。

+k8s:enum

描述

指示字符串类型为枚举。该类型的所有常量值都被视为枚举中的值。

稳定性级别: Beta

使用示例

首先,定义一个新的字符串类型和该类型的一些常量。

// +k8s:enum
type MyEnum string

const (
    MyEnumA MyEnum = "A"
    MyEnumB MyEnum = "B"
)

然后,在另一个结构体中使用此类型。

type MyStruct struct {
    MyField MyEnum `json:"myField"`
}

验证逻辑将确保 MyField 是已定义的枚举值("A""B")之一。

+k8s:forbidden

描述

指示字段不可指定。

稳定性级别: Alpha

使用示例

type MyStruct struct {
    // +k8s:forbidden
    MyField string `json:"myField"`
}

在此示例中,创建或更新 MyStruct 时不能提供 MyField(它被禁止)。

+k8s:format

描述

指示字符串字段具有特定格式。

稳定性级别: 稳定 (Stable)

负载

  • k8s-ip:该字段持有 IPv4 或 IPv6 地址值。IPv4 八位组可能有前导零。
  • k8s-long-name:该字段持有 Kubernetes “长名称”,即“DNS 子域名”值。
  • k8s-short-name:该字段持有 Kubernetes “短名称”,即“DNS 标签”值。

使用示例

type MyStruct struct {
    // +k8s:format=k8s-ip
    IPAddress string `json:"ipAddress"`

    // +k8s:format=k8s-long-name
    Subdomain string `json:"subdomain"`

    // +k8s:format=k8s-short-name
    Label string `json:"label"`
}

在本例中

  • IPAddress 必须是有效的 IP 地址。
  • Subdomain 必须是有效的 DNS 子域名。
  • Label 必须是有效的 DNS 标签。

+k8s:ifDisabled

描述

声明仅在选项被禁用时适用的验证。

稳定性级别: Alpha

参数

  • <option>(字符串,必填):选项的名称。

负载

  • <validation-tag>:仅当验证选项被禁用时,此验证标签才会被评估。

使用示例

type MyStruct struct {
    // +k8s:ifDisabled("my-feature")=+k8s:required
    MyField string `json:"myField"`
}

在此示例中,仅当 “my-feature” 选项被禁用时,MyField 才是必需的。

+k8s:ifEnabled

描述

声明仅在选项被启用时适用的验证。

稳定性级别: Alpha

参数

  • <option>(字符串,必填):选项的名称。

负载

  • <validation-tag>:仅当验证选项被启用时,此验证标签才会被评估。

使用示例

type MyStruct struct {
    // +k8s:ifEnabled("my-feature")=+k8s:required
    MyField string `json:"myField"`
}

在此示例中,仅当 “my-feature” 选项被启用时,MyField 才是必需的。

+k8s:isSubresource

稳定性级别: 稳定 (Stable)

描述

+k8s:isSubresource 标签是一个包级注释,将该包内的验证规则限制为特定的子资源。它本质上告诉代码生成器:“此处定义的验证逻辑是此子资源的特定实现,不应应用于根对象或任何其他子资源。”

关键依赖

此标签依赖于在定义主 API 类型的包中存在相应的 +k8s:supportsSubresource 标签。

  • +k8s:supportsSubresource 通过告诉分发器子资源是有效的来打开大门。
  • +k8s:isSubresource 提供了当请求通过该门时运行的专用验证逻辑。

如果您在主类型上没有相应的 +k8s:supportsSubresource 声明的情况下使用 +k8s:isSubresource,则会生成专用的验证代码,但它是不可达的。主分发器不会识别子资源路径,并会在路由到您的特定验证逻辑之前拒绝请求。

这种依赖允许进行强大的组织,例如将主 API 类型放在一个包中,并将它们特定于子资源的验证定义在单独的、专用的包中。

作用域: 包 (Package)

负载

  • <subresource-path>:此包中验证应适用的子资源路径(例如 "/status""/scale")。

使用示例

这个分两部分的示例演示了关注点分离的预期使用场景。

1. 在主 API 包中声明支持: 首先,在主包中声明 Deployment 类型支持 /scale 验证。

文件: staging/src/k8s.io/api/apps/v1/doc.go

// This enables the validation dispatcher to handle requests for "/scale".
// +k8s:supportsSubresource="/scale"
package v1

// ... includes the definition for the Deployment type

2. 在单独的包中限定验证逻辑: 接下来,为仅对 /scale 子资源有效的验证规则创建一个单独的包。

文件: staging/src/k8s.io/api/apps/v1/validations/scale/doc.go

// This ensures the rules in this package ONLY run for the "/scale" subresource.
// +k8s:isSubresource="/scale"
package scale

import "k8s.io/api/apps/v1"

// Validation code in this package would reference types from package v1 (e.g., v1.Scale).
// The generated validation function will only be invoked for requests to the "/scale"
// subresource of a type defined in a package that supports it.

+k8s:item

描述

为声明为 +k8s:listType=map 的切片项声明验证。要匹配的项是通过提供字段-值对参数来声明的,其中字段是 listMapKey。必须指定所有 listMapKey 键字段。

稳定性级别: 稳定 (Stable)

用法

+k8s:item(<listMapKey-JSON-field-name>: <value>,...)=<validation-tag>

+k8s:item(stringKey: "value", intKey: 42, boolKey: true)=<validation-tag>

参数必须使用列表映射键字段的 JSON 名称命名。值可以是字符串、整数或布尔值。

负载

  • <validation-tag>:针对匹配的列表项进行评估的标签。

使用示例

type MyStruct struct {
	// +k8s:listType=map
	// +k8s:listMapKey=type
	// +k8s:item(type: "Approved")=+k8s:zeroOrOneOfMember
	// +k8s:item(type: "Denied")=+k8s:zeroOrOneOfMember
	MyConditions []MyCondition `json:"conditions"`
}

type MyCondition struct {
    Type string `json:"type"`
    Status string `json:"status"`
}

在本例中

  • type 为 “Approved” 的条件是“零或一”成员组的一部分。
  • type 为 “Denied” 的条件是“零或一”成员组的一部分。

+k8s:listMapKey

描述

声明列表值类型的命名子字段作为列表映射键的一部分。当使用 +k8s:listType=map 时,需要此标签。可以在列表映射上使用多个 +k8s:listMapKey 标签,以指定它是基于多个字段进行键控的。

稳定性级别: 稳定 (Stable)

负载

  • <field-json-name>:用作键的字段的 JSON 名称。

使用示例

// +k8s:listType=map
// +k8s:listMapKey=keyFieldOne
// +k8s:listMapKey=keyFieldTwo
type MyList []MyStruct

type MyStruct struct {
    keyFieldOne string `json:"keyFieldOne"`
    keyFieldTwo string `json:"keyFieldTwo"`
    valueField string `json:"valueField"`
}

在此示例中,listMapKey 用于指定 MyStructkeyField 应作为列表映射的键。

+k8s:listType

描述

声明列表字段的语义类型。此标签用于指定列表的处理方式,例如作为映射或集合。

稳定性级别: 稳定 (Stable)

负载

  • atomic:列表被视为单个原子值。
  • map:列表被视为映射,其中每个元素都有一个唯一的键。需要使用 +k8s:listMapKey
  • set:列表被视为集合,其中每个元素都是唯一的。

使用示例

// +k8s:listType=map
// +k8s:listMapKey=keyField
type MyList []MyStruct

type MyStruct struct {
    keyField string `json:"keyField"`
    valueField string `json:"valueField"`
}

在此示例中,MyList 被声明为类型为 map 的列表,并以 keyField 为键。这意味着验证逻辑将确保列表中的每个元素都有一个唯一的 keyField

+k8s:maxItems

描述

指示列表字段的大小有限制。

稳定性级别: 稳定 (Stable)

负载

  • <非负整数>:此字段的项数不得超过 X 个。

使用示例

type MyStruct struct {
    // +k8s:maxItems=5
    MyList []string `json:"myList"`
}

在此示例中,MyList 不能包含超过 5 个项。

+k8s:maxLength

描述

指示字符串字段的长度有限制。

稳定性级别: 稳定 (Stable)

负载

  • <非负整数>:此字段的字符数不得超过 X 个。

使用示例

type MyStruct struct {
    // +k8s:maxLength=10
    MyString string `json:"myString"`
}

在此示例中,MyString 的长度不能超过 10 个字符。

+k8s:minimum

描述

指示数值字段具有最小值。

稳定性级别: 稳定 (Stable)

负载

  • <整数>:此字段必须大于或等于 x。

使用示例

type MyStruct struct {
    // +k8s:minimum=0
    MyInt int `json:"myInt"`
}

在此示例中,MyInt 必须大于或等于 0。

+k8s:neq

描述

验证字段值不等于特定的禁止值。支持字符串、整数和布尔类型。

稳定性级别: Alpha

负载

  • <value>:禁止的值。解析器将推断类型(字符串、整数、布尔值)。

使用示例

type MyStruct struct {
    // +k8s:neq="disallowed"
    MyString string `json:"myString"`

    // +k8s:neq=0
    MyInt int `json:"myInt"`

    // +k8s:neq=true
    MyBool bool `json:"myBool"`
}

在本例中

  • MyString 不能等于 "disallowed"
  • MyInt 不能等于 0
  • MyBool 不能等于 true

+k8s:opaqueType

描述

指示引用类型上的任何声明验证将被忽略。如果引用类型的包没有包含在生成器的当前标志中,则必须设置此标签,否则代码生成将失败(以防止静默错误)。如果验证不应被忽略,请使用 --readonly-pkg 标志将该类型的包添加到生成器中。

稳定性级别: Alpha

使用示例

import "some/external/package"

type MyStruct struct {
    // +k8s:opaqueType
    ExternalField package.ExternalType `json:"externalField"`
}

在此示例中,package.ExternalType 上的任何验证标签都将被忽略。

+k8s:optional

描述

指示客户端可选此字段。

稳定性级别: 稳定 (Stable)

使用示例

type MyStruct struct {
    // +k8s:optional
    MyField string `json:"myField"`
}

在此示例中,创建或更新 MyStruct 时不需要提供 MyField

+k8s:required

描述

指示客户端必须指定此字段。

稳定性级别: 稳定 (Stable)

使用示例

type MyStruct struct {
    // +k8s:required
    MyField string `json:"myField"`
}

在此示例中,创建或更新 MyStruct 时必须提供 MyField

+k8s:subfield

描述

声明结构体子字段的验证。

稳定性级别: Beta

参数

  • <field-json-name>(字符串,必填):子字段的 JSON 名称。

负载

  • <validation-tag>:针对子字段进行评估的标签。

使用示例

type MyStruct struct {
    // +k8s:subfield("mySubfield")=+k8s:required
    MyStruct MyStruct `json:"MyStruct"`
}

type MyStruct struct {
    MySubfield string `json:"mySubfield"`
}

在此示例中,MyStruct 中的 MySubfield 是必需的。

+k8s:supportsSubresource

稳定性级别: 稳定 (Stable)

描述

+k8s:supportsSubresource 标签是一个包级注释标签,声明了对于该包内的类型,哪些子资源是有效的验证目标。将此标签视为注册一个端点;它告诉验证框架识别特定的子资源路径,且不应立即拒绝该请求。

当生成验证代码时,此标签会将指定的子资源路径添加到类型的分发函数中。这允许针对该子资源的传入请求被路由到验证实现。

可以使用多个标签来声明对多个子资源的支持。如果包中不存在 +k8s:supportsSubresource 标签,则仅对根资源启用验证(例如 .../myresources/myobject),对任何子资源的请求都将失败并返回 “no validation found” 错误。

独立使用

如果您在没有对应 +k8s:isSubresource 标签的情况下使用 +k8s:supportsSubresource,则默认会将根对象的验证规则应用于子资源。

作用域: 包 (Package)

负载

  • <subresource-path>:要支持的子资源路径(例如 "/status""/scale")。

使用示例

通过添加这些标签,您可以使验证系统能够处理包 v1 中定义的类型的 /status/scale 子资源请求。

文件: staging/src/k8s.io/api/core/v1/doc.go

// +k8s:supportsSubresource="/status"
// +k8s:supportsSubresource="/scale"
package v1

+k8s:unionDiscriminator

描述

指示此字段是联合(union)的判别符。

稳定性级别: 稳定 (Stable)

参数

  • union(字符串,可选):联合的名称(如果存在多个)。

使用示例

type MyStruct struct {
	TypeMeta int

	// +k8s:unionDiscriminator
	D D `json:"d"`

	// +k8s:unionMember
	// +k8s:optional
	M1 *M1 `json:"m1"`

	// +k8s:unionMember
	// +k8s:optional
	M2 *M2 `json:"m2"`
}

type D string

const (
	DM1 D = "M1"
	DM2 D = "M2"
)

type M1 struct{}

type M2 struct{}

在此示例中,Type 字段是联合的判别符。Type 的值将决定预期存在联合成员(M1M2)中的哪一个。

+k8s:unionMember

描述

指示此字段是联合的成员。

稳定性级别: 稳定 (Stable)

参数

  • union(字符串,可选):联合的名称(如果存在多个)。
  • memberName(字符串,可选):该成员的判别值。默认为字段的名称。

使用示例

type MyStruct struct {
	// +k8s:unionMember(union: "union1")
	// +k8s:optional
	M1 *M1 `json:"u1m1"`

	// +k8s:unionMember(union: "union1")
	// +k8s:optional
	M2 *M2 `json:"u1m2"`
}

type M1 struct{}

type M2 struct{}

在此示例中,M1M2 是命名联合 union1 的成员。

+k8s:zeroOrOneOfMember

描述

指示此字段是“零或一”联合的成员。“零或一”联合允许最多设置一个成员。与常规联合不同,不设置任何成员也是有效的。

稳定性级别: 稳定 (Stable)

参数

  • union(字符串,可选):联合的名称(如果存在多个)。
  • memberName(字符串,可选):该成员的自定义名称。默认为字段的名称。

使用示例

type MyStruct struct {
	// +k8s:zeroOrOneOfMember
	// +k8s:optional
	M1 *M1 `json:"m1"`

	// +k8s:zeroOrOneOfMember
	// +k8s:optional
	M2 *M2 `json:"m2"`
}

type M1 struct{}

type M2 struct{}

在此示例中,最多只能设置 AB 中的一个。两者都不设置也是有效的。


最后修改时间:2026 年 4 月 1 日 下午 12:36 PST: 更新 content/en/docs/reference/using-api/declarative-validation.md (1d5c3750fd)