k8s Mutating Admission Webhook 实现超卖

发布于:2025-07-11 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

1.什么是 Mutating Admission Webhook?

2.如何用 Mutating Admission Webhook 实现超卖? 

3.实现超卖

3.1 理解目标

3.2 前置准备

3.3 开发 Mutating Webhook

3.4 配置 Webhook Server TLS 认证

3.5 注册 MutatingWebhookConfiguration

3.6 部署 Webhook 到集群

3.7 测试功能 

3.8 监控与告警


1.什么是 Mutating Admission Webhook?

  • 定义:是一种拦截 Kubernetes API 请求的插件,在对象被持久化之前对其进行修改。
  • 典型用途:
  1. 注入默认资源请求/限制(如 CPU/Memory)
  2. 修改 Pod Spec(如注入 sidecar 容器)
  3. 实现多租户资源配额控制

2.如何用 Mutating Admission Webhook 实现超卖? 

场景目标

允许 requests.cpu 超出节点实际物理容量(如 64 核),但通过策略控制其不超过一定比例(如 110%)。

实现思路

1.拦截 Pod 创建请求

使用 Mutating Webhook 拦截所有 Pod 的创建或更新请求。

2.读取当前节点已分配资源

获取该 Pod 即将调度到的节点上已有的 requests.cpu 总和。
可以通过 kubelet 或 metrics-server 获取。

3.判断是否超出超卖上限

若总请求 + 当前 Pod 请求 > Allocatable * OvercommitRatio,则拒绝或自动调整请求值。

4.自动设置默认值(可选)

如果未设置 requests.cpu,可以自动注入一个合理默认值(例如 500m)。

5.返回修改后的 Pod Spec

在 Admission Response 中返回修改后的 Pod Spec。

3.实现超卖

3.1 理解目标


我们希望达到的效果是:

  • 允许 Pod 的 requests.cpu 超出节点实际可分配资源(如 Allocatable=64核)
  • 但限制其总和不超过一定比例(例如:110%)
  • 在 Pod 创建/更新时动态拦截并验证或修改请求内容

3.2 前置准备


环境要求

  • Kubernetes 集群(v1.20+)
  • 启用 MutatingAdmissionWebhook 控制器(默认启用)
  • 安装 kubebuilder 或使用 Go 开发
  • TLS 证书用于 webhook server(可通过 cert-manager 自动生成) 

3.3 开发 Mutating Webhook

1. 初始化项目(使用 kubebuilder)

kubebuilder init --domain example.com
kubebuilder create api --group admission --version v1 --kind OvercommitWebhook

2. 编写 Webhook 核心逻辑

a. 拦截 Pod 创建请求

func (r *PodWebhook) Default(ctx context.Context, obj runtime.Object) error {
    pod := obj.(*corev1.Pod)

    // 如果未设置 CPU request,则注入默认值
    if pod.Spec.Containers != nil {
        for i := range pod.Spec.Containers {
            if _, ok := pod.Spec.Containers[i].Resources.Requests[corev1.ResourceCPU]; !ok {
                pod.Spec.Containers[i].Resources.Requests = corev1.ResourceList{
                    corev1.ResourceCPU: resource.MustParse("500m"),
                }
            }
        }
    }

    return nil
}

b. 判断是否超出超卖限制

func checkOvercommit(pod *corev1.Pod, nodeName string) bool {
    nodeInfo, err := getNodeAllocatable(nodeName)
    if err != nil {
        log.Error(err, "无法获取节点信息")
        return false
    }

    totalRequestedCPU := getCurrentTotalCPURequests(nodeName)
    newRequestCPU := getResourceMilliCPU(pod)

    overcommitRatio := 1.1 // 110%
    maxAllowedCPU := nodeInfo.Allocatable.Cpu().MilliValue() * int64(overcommitRatio)

    return (totalRequestedCPU + newRequestCPU) <= maxAllowedCPU
}

// 获取当前 Pod 请求的 CPU 总量
func getResourceMilliCPU(pod *corev1.Pod) int64 {
    var total int64
    for _, container := range pod.Spec.Containers {
        cpuReq := container.Resources.Requests.Cpu()
        if cpuReq != nil {
            total += cpuReq.MilliValue()
        }
    }
    return total
}

c. 修改或拒绝请求

func mutatePod(pod *corev1.Pod) ([]byte, error) {
    // 示例:自动注入 sidecar 或修改 requests
    pod.Spec.Containers[0].Resources.Requests[corev1.ResourceCPU] = resource.MustParse("700m")

    return json.Marshal(pod)
}

3.4 配置 Webhook Server TLS 认证

1. 使用 cert-manager 自动生成证书(推荐)

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: webhook-cert
spec:
  secretName: webhook-server-cert
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
    - webhook-service.default.svc
    - webhook-service.default.svc.cluster.local

2. 配置 Webhook Server 使用证书

server := &webhook.Server{
    Host:    "0.0.0.0",
    Port:    443,
    CertDir: "/tmp/cert",
    TLSOpts: []func(*tls.Config){
        func(config *tls.Config) {
            config.ClientAuth = tls.NoClientCert
        },
    },
}

3.5 注册 MutatingWebhookConfiguration

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: overcommit-mutating-webhook
webhooks:
  - name: mutating.overcommit.example.com
    rules:
      - operations: ["CREATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    clientConfig:
      service:
        namespace: default
        name: webhook-service
      caBundle: <base64 encoded CA cert>
    admissionReviewVersions: ["v1"]
    sideEffects: None
    timeoutSeconds: 5

caBundle 是你的 CA 证书的 base64 编码。 

3.6 部署 Webhook 到集群

1. 构建镜像并推送到仓库

make docker-build docker-push IMG=myregistry/overcommit-webhook:latest

2. 部署 Deployment 和 Service

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webhook-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webhook
  template:
    metadata:
      labels:
        app: webhook
    spec:
      containers:
        - name: webhook
          image: myregistry/overcommit-webhook:latest
          ports:
            - containerPort: 443
---
apiVersion: v1
kind: Service
metadata:
  name: webhook-service
spec:
  ports:
    - port: 443
      targetPort: 443
  selector:
    app: webhook

3.7 测试功能 

1. 创建一个 Pod

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
    - name: nginx
      image: nginx
      resources:
        requests:
          cpu: 500m

2. 查看是否被拦截并修改

kubectl describe pod test-pod

查看是否注入了新的 CPU 请求或被拒绝创建。

3.8 监控与告警

建议结合 Prometheus + Grafana:

  • 监控指标:

container_cpu_usage_seconds_total
kube_node_allocatable_cpu_cores
kube_pod_container_resource_requests_cpu_cores

  • 告警规则示例:
groups:
  - name: cpu-overcommit
    rules:
      - alert: HighCpuRequestUsage
        expr: sum(kube_pod_container_resource_requests_cpu_cores) by (node) / kube_node_allocatable_cpu_cores > 1.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: Node {{ $labels.node }} CPU 请求已超过 110%

如果你正在构建一个支持 CPU 、内存资源超卖 的 Kubernetes 平台,建议将此 Mutating Webhook 与调度器插件(如 Kube-scheduler 插件或调度器扩展)配合使用,以实现更精细的资源管理策略。


网站公告

今日签到

点亮在社区的每一天
去签到