https://github.com/yannh/kubeconform
Kubeconform 官方定义为一个 Kubernetes manifest验证工具,可集成到 CI 流程中,直接在本地验证 Kubernetes 配置。
该项目受 Kubeval 启发,包含其部分代码,并致力于保持与 Kubeval 的相似性,但具有以下改进:
官网提供多种安装方式,mac下使用 brew 安装最为简便,执行brew install kubeconform,依旧使用验证kube-score的test.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25.3
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
执行kubeconform test.yaml; echo $?输出0,即代表通过校验。执行kubeconform -summary -output json test.yaml可以查看详细信息:
{
"resources": [],
"summary": {
"valid": 1,
"invalid": 0,
"errors": 0,
"skipped": 0
}
}
将test.yaml中.spec.replicas的值改成字符串"1",再次执行则会输出一个msg":
"problem validating schema. Check JSON formatting: jsonschema: '/spec/replicas' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/deployment-apps-v1.json#/properties/spec/properties/replicas/type: expected integer or null, but got string"
kubeconform默认使用宽容模式进行校验,即下述不合理的情况也能通过测试:
针对这样的场景,官方建议使用"-strict"参数来过滤未知或者自定义的字段。验证结果:
{
"resources": [
{
"filename": "test.yaml",
"kind": "Deployment",
"name": "nginx-deployment",
"version": "apps/v1",
"status": "statusInvalid",
"msg": "problem validating schema. Check JSON formatting: jsonschema: '' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone-strict/deployment-apps-v1.json#/additionalProperties: additionalProperties 'speci' not allowed",
"validationErrors": [
{
"path": "",
"msg": "additionalProperties 'speci' not allowed"
}
]
...
相比于kube score,这个项目感觉更加完备,但同样有类似的局限性。Kubeconform 局限性的来源是,其仅使用官方的 Kubernetes OpenAPI 规范来验证manifest。举例说明 https://github.com/yannh/kubeconform/issues/65:
在DNS-1035中明确规定"label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character",故下面的示例应当无法通过校验:
apiVersion: v1
kind: Service
metadata:
name: foo_bar
labels:
app: foo
spec:
...
因为"foo_bar"并不满足DNS-1035规范,而事实上kubeconform并不会抛出任何错误。每个Kubernetes版本会发布对应的OpenAPI规范文件(/openapi/v2端点),包含所有内置资源(如Pod)和CRD(自定义资源)的Schema,k8s 控制器在应用yaml时,除了执行上述OpenAPI 规范,还可能会做一些额外服务端验证,DNS-1035即为一个示例。官方给出的替代办法是使用第三方工具或 kubectl --dry-run=server 命令来进行校验。
k8s API 的OpenAPI 规范定义文件托管在 Kubernetes 主代码库中,kubeconform维护了一个更加精细的分支,地址在https://github.com/yannh/kubernetes-json-schema , 该分支持续保持更新,包含所有最新 Kubernetes 版本的验证模式。所有kubeconform提供的校验均基于此分支。
核心验证逻辑在ValidateResource函数中:
// https://github.com/yannh/kubeconform/blob/master/pkg/validator/validator.go
func (val *v) ValidateResource(res resource.Resource) Result {
skip := func(signature resource.Signature) bool {
if _, ok := val.opts.SkipKinds[signature.GroupVersionKind()]; ok {
return ok
}
_, ok := val.opts.SkipKinds[signature.Kind]
return ok
}
reject := func(signature resource.Signature) bool {
if _, ok := val.opts.RejectKinds[signature.GroupVersionKind()]; ok {
return ok
}
_, ok := val.opts.RejectKinds[signature.Kind]
return ok
}
if len(res.Bytes) == 0 {
return Result{Resource: res, Err: nil, Status: Empty}
}
var r map[string]interface{}
unmarshaller := yaml.Unmarshal
if val.opts.Strict {
unmarshaller = yaml.UnmarshalStrict
}
...
首先提取资源签名,解析指定类型判断是否跳过或拒绝指定的资源,然后通过多级缓存机制(内存缓存、动态下载)获取最新的schema并执行schema.Validate(r)进行验证,最终返回Result对象,即kubeconform -summary -output json test.yaml输出的结果,它包括以下信息:
kubeconform的结果依赖由 JSON Schema提供的Validate能力和kubernetes-json-schema对规范的定义,支持校验字段类型、必填项、格式规则,但对于某些特定业务场景仍显不足,如:
kube-score更注重安全、稳定性,校验内容可配置但相对固定,适用于发现配置中的隐患、推进yaml规范化;kubeconform更注重格式、数值、功能性等方面,更容易集成到go程序当中,也能通过自定义schema实现更灵活的定制校验逻辑。