k8s之Admission Controller

Admission Controller(准入控制器)

Admission Controller 是 Kubernetes 中一个强大的扩展机制,允许用户在 API 请求被处理之前对请求进行验证、修改或拒绝。通过准入控制器,用户可以实现各种自定义的业务逻辑,例如资源配额控制、安全策略检查、自动化配置注入等。

Kubernetes 提供了两种主要的准入控制器实现方式:Server-Side Admission 和 Webhook Admission。以下是这两种方式的详细介绍、实现细节、优缺点以及适用场景。

1. Server-Side Admission

1.1 实现细节

  • 开发语言:Server-Side Admission 要求使用 Go 语言编写插件,因为 Kubernetes API Server 是用 Go 语言实现的。
  • 插件开发:开发者需要实现 Kubernetes 的准入控制器接口,通常需要继承 admission.Interfaceadmission.MutationInterface 等接口。
  • 编译与部署:编写好的插件需要编译成共享库(.so 文件),然后将该共享库放置在 Kubernetes API Server 的插件目录中,并在 API Server 的配置文件中加载该插件。

1.2 优点

  • 高性能:由于插件直接运行在 API Server 的进程中,处理速度较快,延迟较低。
  • 权限:插件可以访问 Kubernetes API Server 的内部功能和数据结构,适合需要高度集成的场景。
  • 稳定性:插件与 API Server 有较强的耦合性,确保了插件的稳定性和可靠性。

1.3 缺点

  • 耦合性:插件的更新和维护需要重新编译和重启 API Server,增加了操作的复杂性。
  • 复杂性:需要深入了解 Kubernetes 的内部实现细节,开发和维护成本较高。

1.4 适用场景

  • 高性能要求:需要对 API 请求进行快速处理的场景。
  • 内部集成:需要与 Kubernetes API Server 的内部功能深度集成的场景。
  • 核心功能扩展:需要扩展 Kubernetes 核心功能的场景。

2. Webhook Admission

2.1 实现细节

  • 开发语言:Webhook Admission 允许使用任何语言(如 Python、Java、Go 等)编写 Webhook 服务。
  • 服务暴露:开发者需要编写一个独立的 Web 服务,该服务需要支持 Kubernetes 的准入控制器协议(如 mutatevalidate 接口)。
  • 配置与注册:在 Kubernetes API Server 的配置文件中注册 Webhook 服务,指定其处理的资源类型和动词(如 CREATEUPDATEDELETE)。

2.2 优点

  • 解耦:Webhook 服务独立于 Kubernetes API Server,不会影响 API Server 的性能和稳定性。
  • 灵活性:可以使用不同的编程语言和框架实现 Webhook 服务,适合多样化的需求。
  • 易于扩展:可以根据需要动态扩展 Webhook 服务的处理能力,支持高可用性部署。

2.3 缺点

  • 延迟:由于需要通过网络调用 Webhook 服务,可能会增加请求的处理时间。
  • 复杂性:需要管理 Webhook 服务的部署、可用性和安全性,增加了运维的复杂性。

2.4 适用场景

  • 灵活扩展:需要使用不同的编程语言或技术栈实现准入控制的场景。
  • 解耦需求:希望将准入控制逻辑与 Kubernetes API Server 解耦的场景。
  • 动态扩展:需要根据需求动态扩展准入控制能力的场景。

3. 深入理解准入控制器的工作流程

  1. 请求到达 API Server:客户端发送一个 API 请求(如创建一个 Pod)到 Kubernetes API Server。
  2. 准入控制器拦截请求:API Server 在处理请求之前,会调用所有已注册的准入控制器(包括 Server-Side 和 Webhook)对请求进行处理。
  3. 准入控制器处理逻辑
    • Server-Side Admission:插件在 API Server 内部对请求进行处理,可以验证、修改或拒绝请求。
    • Webhook Admission:API Server 将请求转发到 Webhook 服务,Webhook 服务根据业务逻辑返回允许、拒绝或修改后的请求。
  4. 处理结果
    • 允许:如果准入控制器允许请求,API Server 继续处理请求,将资源存储到 etcd。
    • 拒绝:如果准入控制器拒绝请求,API Server 返回错误信息给客户端。
    • 修改:准入控制器可以对请求进行修改,API Server 使用修改后的请求继续处理。
  5. 响应客户端:API Server 将处理结果返回给客户端。

4. 实现一个简单的准入控制器示例:限制 Pod 的资源使用

目标

在 Kubernetes 集群中,限制每个 Pod 的 CPU 和内存资源使用,确保不超过预设的配额。

使用 Server-Side Admission 实现

  1. 编写准入插件
package main

import (
    "errors"
    "fmt"
    "io"
    "os"
    "path/filepath"

    "k8s.io/api/admission/v1beta1"
    "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "k8s.io/apiserver/pkg/server"
    "k8s.io/apiserver/pkg/server/healthz"
    "k8s.io/klog"
)

const (
    DefaultCpuLimit = "2"
    DefaultMemoryLimit = "4Gi"
)

type PodResourceAdmission struct {
    // 可选的配置参数
}

func (p *PodResourceAdmission) Admit(ar v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
    // 获取请求的资源类型和动词
    req := ar.Request
    if req.Kind.Kind != "Pod" || req.Kind.Group != "" {
        // 只处理核心的 Pod 资源
        return &v1beta1.AdmissionResponse{
            Allowed: true,
        }
    }

    pod := &v1.Pod{}
    if err := runtime.DecodeInto(ar.Request.Object.Raw, pod); err != nil {
        return &v1beta1.AdmissionResponse{
            Allowed: false,
            Status:  metav1.Status{
                Message: err.Error(),
            },
        }
    }

    // 检查 CPU 请求和限制
    if pod.Spec.Containers[0].Resources.Requests.Cpu().Value() > DefaultCpuLimit {
        return &v1beta1.AdmissionResponse{
            Allowed: false,
            Status:  metav1.Status{
                Message: "CPU request exceeds allowed limit of " + DefaultCpuLimit,
            },
        }
    }

    // 检查内存请求和限制
    if pod.Spec.Containers[0].Resources.Requests.Memory().Value() > DefaultMemoryLimit {
        return &v1beta1.AdmissionResponse{
            Allowed: false,
            Status:  metav1.Status{
                Message: "Memory request exceeds allowed limit of " + DefaultMemoryLimit,
            },
        }
    }

    return &v1beta1.AdmissionResponse{
        Allowed: true,
    }
}

func main() {
    // 初始化日志
    klog.InitFlags(nil)
    defer klog.Flush()

    // 创建一个新的准入控制器
    plugin := &PodResourceAdmission{}

    // 注册准入控制器
    pluginName := "pod-resource-admission"
    handler := plugin.Admit

    // 创建 HTTP 服务器
    server := server.NewAPIServer(
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
        nil,
    )

    // 注册准入控制器到 API Server
    server.AddPlugin(pluginName, handler)

    // 启动 HTTP 服务器
    server.ServeHTTP()

    // 阻塞主线程
    select {}
}
  1. 编译插件
    将上述代码编译成共享库(shared library)。使用以下命令编译:
go build -buildmode=plugin -o pod-resource-admission.so main.go
  1. 配置 Kubernetes API Server
    将插件文件 pod-resource-admission.so 放置在 API Server 的插件目录中。
    修改 API Server 的配置文件,加载这个插件。
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
  kubeletExtraArgs:
    authentication-token-webhook: "true"
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
apiServer:
  extraArgs:
    admission-control-plugins: "NamespaceLifecycle,LimitRsrcAdmission,PodResourceAdmission"
    pod-resource-admission-path: "/path/to/pod-resource-admission.so"
  1. 重启 Kubernetes API Server
    应用新的配置并重启 API Server,使插件生效。

使用 Webhook Admission 实现

  1. 编写 Webhook 服务
from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/mutate', methods=['POST'])
def mutate():
    request_json = json.loads(request.get_data())
    pod = request_json['request']['object']

    # 检查 CPU 请求
    if pod['spec']['containers'][0]['resources']['requests']['cpu'] > '2':
        return jsonify({
           'status': {
                'code': 403,
               'message': 'CPU request exceeds allowed limit of 2'
            },
            'allowed': False
        }), 403

    # 检查内存请求
    if pod['spec']['containers'][0]['resources']['requests']['memory'] > '4Gi':
        return jsonify({
           'status': {
                'code': 403,
               'message': 'Memory request exceeds allowed limit of 4Gi'
            },
            'allowed': False
        }), 403

    return jsonify({'allowed': True})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
  1. 部署 Webhook 服务
    将上述代码打包成一个 Docker 镜像并部署到 Kubernetes 集群中。
    创建一个 Kubernetes Service 和 Deployment 来暴露和管理这个 Webhook 服务。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-resource-webhook
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pod-resource-webhook
  template:
    metadata:
      labels:
        app: pod-resource-webhook
    spec:
      containers:
      - name: pod-resource-webhook
        image: your-dockerhub/pod-resource-webhook:1.0
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: pod-resource-webhook
  namespace: kube-system
spec:
  selector:
    app: pod-resource-webhook
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  type: ClusterIP
  1. 配置 Kubernetes API Server
    修改 API Server 的配置文件,注册这个 Webhook 服务。
apiServer:
  extraArgs:
    admission-control-config-file: /etc/kubernetes/admission-webhook.yaml

创建 admission-webhook.yaml 文件,定义 Webhook 的配置:

admissionWebhook:
  enabled: true
  configuration:
    apiVersion: admissionregistration.k8s.io/v1
    kind: WebhookConfiguration
    name: pod-resource-webhook
    webhooks:
    - name: pod-resource.mutating.k8s.io
      rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
      clientConfig:
        service:
          name: pod-resource-webhook
          namespace: kube-system
          path: /mutate
  1. 应用配置并重启 API Server
    应用新的配置并重启 API Server,使 Webhook 生效。

5. 深入理解准入控制的优缺点

Server-Side Admission 的优缺点

  • 优点
    • 性能:由于插件直接运行在 API Server 进程中,处理速度较快,延迟较低。
    • 权限:插件可以访问 Kubernetes API Server 的所有内部功能和数据结构。
    • 稳定:插件的运行状态直接影响 API Server 的性能,需要确保插件的稳定性和可靠性。
  • 缺点
    • 耦合性:插件与 API Server 有较强的耦合性,升级或维护插件需要重新编译和重启 API Server。
    • 复杂性:需要深入了解 Kubernetes 的内部实现细节,开发和维护成本较高。

Webhook Admission 的优缺点

  • 优点
    • 解耦:Webhook 服务独立于 Kubernetes API Server,不会影响 API Server 的性能和稳定性。
    • 灵活性:可以使用任何语言开发 Webhook 服务,不依赖于 Kubernetes 的内部实现。
    • 易于扩展:可以根据需要动态扩展 Webhook 服务的处理能力。
  • 缺点
    • 延迟:由于需要通过网络调用 Webhook 服务,可能会增加请求的处理时间。
    • 复杂性:需要管理 Webhook 服务的部署、可用性和安全性。

6. 实际应用中的注意事项

性能考虑

  • 对于高负载的集群,Server-Side Admission 通常比 Webhook Admission 更优,因为它减少了网络开销。
  • 如果选择 Webhook Admission,确保 Webhook 服务有足够的处理能力,避免成为性能瓶颈。

安全性

  • 确保 Webhook 服务的安全性,使用 TLS 加密通信,验证请求来源。
  • 在 API Server 配置中,限制 Webhook 服务的访问权限,避免未授权的访问。

可靠性

  • 确保准入控制器的稳定性和可靠性,避免因插件或 Webhook 服务的故障导致 API Server 无法正常工作。
  • 实现重试机制和熔断机制,提高系统的容错能力。

监控与日志

  • 配置监控工具(如 Prometheus 和 Grafana)监控准入控制器的性能和健康状态。
  • 启用详细的日志记录,便于排查和调试问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值