ConfigMap 验证

Tekton Pruner 使用 ValidatingWebhook 来确保 ConfigMap 在集群中被创建或更新之前满足所需规范。本文档说明了验证的工作方式以及必须满足的要求。

概述

pruner webhook 会验证 ConfigMap,以便:

  • 强制执行所需的标签和命名约定
  • 防止无效配置被应用
  • 防止关键配置被意外删除
  • 确保命名空间级配置遵守全局边界

验证如何工作

验证 webhook 会随 pruner 自动安装,并拦截 ConfigMap 的 CREATE、UPDATE 和 DELETE 操作。它只会验证带有标签 app.kubernetes.io/part-of: tekton-pruner 的 ConfigMap,从而确保集群中的普通 ConfigMap 不受影响。

验证规则

1. 必需标签

所有 pruner ConfigMap 都必须包含以下标签:

metadata:
  labels:
    app.kubernetes.io/part-of: tekton-pruner
    pruner.tekton.dev/config-type: <global|namespace>

验证检查:

  • 两个标签都必须存在
  • app.kubernetes.io/part-of 必须等于 tekton-pruner
  • pruner.tekton.dev/config-type 必须是 global 或 namespace

错误示例:

Invalid pruner ConfigMap labels: ConfigMap must have label app.kubernetes.io/part-of=tekton-pruner

2. 选择器限制

CRITICAL: 选择器(matchLabels/matchAnnotations)仅支持命名空间级 ConfigMap(tekton-pruner-namespace-spec),不支持全局 ConfigMap。

有效示例 - 命名空间 ConfigMap 中的选择器:

apiVersion: v1
kind: ConfigMap
metadata:
  name: tekton-pruner-namespace-spec
  namespace: dev
  labels:
    app.kubernetes.io/part-of: tekton-pruner
    pruner.tekton.dev/config-type: namespace
data:
  ns-config: |
    pipelineRuns:
      - selector:                  # OK - This is a namespace ConfigMap
          - matchLabels:
              app: myapp
        ttlSecondsAfterFinished: 1800

无效示例 - 全局 ConfigMap 中的选择器:

apiVersion: v1
kind: ConfigMap
metadata:
  name: tekton-pruner-default-spec
  namespace: tekton-pipelines
  labels:
    app.kubernetes.io/part-of: tekton-pruner
    pruner.tekton.dev/config-type: global
data:
  global-config: |
    namespaces:
      dev:
        pipelineRuns:
          - selector:              # WILL FAIL VALIDATION
              - matchLabels:
                  app: myapp
        ttlSecondsAfterFinished: 1800

错误示例:

Invalid pruner configuration: global-config.namespaces.dev.pipelineRuns[0]: 
selectors are NOT supported in global ConfigMap. 
Use namespace-level ConfigMap (tekton-pruner-namespace-spec) instead

为什么有此限制?

  • 基于选择器的资源匹配需要在运行时访问资源的 labels/annotations
  • 全局 ConfigMap 的设计用途是集群级默认值,而不是面向资源的匹配
  • 命名空间 ConfigMap 提供了用于动态资源选择的正确作用域

另请参见: Resource Groups 中的选择器使用示例

3. 命名要求

全局配置:

  • 名称: 必须是 tekton-pruner-default-spec(固定)
  • 命名空间: 必须是 tekton-pipelines(或系统命名空间)
  • 标签: pruner.tekton.dev/config-type: global

命名空间配置:

  • 名称: 必须是 tekton-pruner-namespace-spec(固定)
  • 命名空间: 必须位于用户命名空间中(不能在系统或 tekton 命名空间中)
  • 标签: pruner.tekton.dev/config-type: namespace

错误示例:

Global config must be named 'tekton-pruner-default-spec', got: my-custom-name
Namespace config must be named 'tekton-pruner-namespace-spec', got: pruner-config

3. 命名空间限制

命名空间级配置禁止使用的命名空间:

  • 系统命名空间:kube-*
  • Tekton 命名空间:tekton-pipelines、tekton-*

尝试在这些位置创建命名空间级配置将被拒绝。

错误示例:

Invalid pruner ConfigMap configuration: wrong config-type label or namespace combination

4. 配置内容验证

webhook 会验证配置数据,包括:

  • 时间值:ttlSecondsAfterFinished 必须为非负数
  • 历史限制:historyLimit、successfulHistoryLimit 和 failedHistoryLimit 必须为非负数,并且如果启用了全局最大值限制,则不能超过该最大值
  • 选择器(仅限命名空间 ConfigMap):标签和注解选择器必须具有有效的键值对;名称选择器必须是有效的资源名称

注意: 选择器(pipelineRuns、taskRuns 数组中包含 matchLabels/matchAnnotations)仅在命名空间级 ConfigMap 中处理。它们在全局 ConfigMap 中会被忽略。

5. 删除保护

如果命名空间级配置仍然存在,webhook 会阻止删除全局配置。你必须先删除所有命名空间配置,然后才能删除全局配置。命名空间配置可以不受限制地删除。

6. 全局配置强制检查

在创建或更新命名空间级配置时,webhook 会获取全局配置,并验证命名空间值是否未超过已定义的全局最大值(例如 maxTTLSecondsAfterFinished、maxHistoryLimit)。

常见验证错误

缺少标签错误

ConfigMap must have labels

解决方案: 为你的 ConfigMap 添加所需标签:

labels:
  app.kubernetes.io/part-of: tekton-pruner
  pruner.tekton.dev/config-type: global  # or namespace

配置类型错误

label pruner.tekton.dev/config-type must be 'global' or 'namespace', got: local

解决方案: 仅使用 global 或 namespace 作为 config-type 值。

名称错误

Global config must be named 'tekton-pruner-default-spec', got: tekton-pruner-config

解决方案: 使用要求的准确名称:

  • 全局:tekton-pruner-default-spec
  • 命名空间:tekton-pruner-namespace-spec

超出全局限制错误

Invalid pruner configuration: namespace config ttlSecondsAfterFinished (172800) exceeds global maximum (86400)

解决方案: 将命名空间值调低到全局限制范围内,或请求管理员提高全局最大值。

删除被阻止错误

Cannot delete global config: 2 namespace config(s) still exist

解决方案: 先删除所有命名空间配置:

kubectl delete cm tekton-pruner-namespace-spec -n dev
kubectl delete cm tekton-pruner-namespace-spec -n staging
# 然后删除全局配置
kubectl delete cm tekton-pruner-default-spec -n tekton-pipelines

故障排查

验证 Webhook 状态

# Check webhook configuration
kubectl get validatingwebhookconfigurations tekton-pruner-validating-webhook

# Check webhook pod and service
kubectl get pods,svc -n tekton-pipelines -l app.kubernetes.io/component=webhook

# View webhook logs
kubectl logs -n tekton-pipelines -l app.kubernetes.io/component=webhook

测试验证

创建一个无效的 ConfigMap,以确认 webhook 正常工作:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: tekton-pruner-default-spec
  namespace: tekton-pipelines
data:
  global-config: |
    ttlSecondsAfterFinished: 300
EOF

预期错误:admission webhook denied the request: Invalid pruner ConfigMap labels

绕过验证(不推荐)

警告: 绕过验证可能导致 pruner 行为配置错误,仅应在紧急情况下这样做。

要临时绕过验证:

  1. 移除标识标签:

    kubectl label cm tekton-pruner-default-spec -n tekton-pipelines \
      app.kubernetes.io/part-of-
  2. 进行必要的更改

  3. 重新添加标签:

    kubectl label cm tekton-pruner-default-spec -n tekton-pipelines \
      app.kubernetes.io/part-of=tekton-pruner

注意: 如果没有正确的标签,pruner controller 将不会处理这些 ConfigMap。

最佳实践

  1. 始终从一开始就包含所需标签
  2. 为全局和命名空间配置使用准确的命名约定
  3. 先在非生产命名空间中测试配置
  4. 仔细检查验证错误 —— 它们会指出需要修复的内容
  5. 在发布新配置时监控 webhook 日志
  6. 在尝试删除全局配置之前先删除命名空间配置