扩展 Kubernetes Controller 的三种方式
一、Operator 方式
1.1 Operator 简介
Operator 是 Kubernetes 中的一种高级扩展模式,结合了 CRD 和自定义控制器,扩展了 Kubernetes API 资源。用户可以通过 Operator 像管理 Kubernetes 内置资源一样创建、配置和管理应用程序。
Operator 是一个特定应用程序的控制器,通过扩展 Kubernetes API 资源来代表 Kubernetes 用户创建、配置和管理复杂应用程序的实例。通常,Operator 包含资源模型定义和控制器,用于实现某种特定软件(通常是有状态服务)的自动化运维。
1.2 Operator 的核心概念
- 自定义资源(CRD):通过 CRD,可以在 Kubernetes 中定义新的资源类型,这些资源可以表示任何你想要管理的对象(例如数据库、有状态应用等)。
- 自定义控制器:自定义控制器通过 watch Kubernetes API 服务器中的资源变化,根据这些变化触发相应的逻辑(例如创建、更新或删除 Pods、Services 等)。
1.3 Operator 的优势
- 领域特定知识:Operator 可以封装特定领域的知识,简化用户的使用。
- 自动化运维:通过 Operator,用户可以自动化部署、配置和管理复杂的应用。
- 声明式 API:提供声明式的接口,用户只需定义期望状态,Operator 负责实现。
1.4 Operator 的实现框架
- kubebuilder:一个用于快速开发 Operator 的工具链。
- Operator Framework:提供 Operator 开发的工具和库,支持 Go、Java 等多种语言。
1.5 Operator 的工作流程
-
定义 CRD:通过 kubectl 或 API 创建一个 CRD,定义新的资源类型。
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: example.com spec: group: example.com versions: - name: v1 served: true storage: true scope: Namespaced names: plural: examples singular: example kind: Example
-
实现 Operator 控制器:编写一个控制器,监听 CRD 的变化。当 CRD 被创建、更新或删除时,控制器会触发相应的逻辑。
package main import ( "fmt" "os" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" ) func main() { mgr, err := manager.New(cfg, manager.Options{}) if err != nil { fmt.Printf("无法创建管理器:%v", err) os.Exit(1) } err = mgr.AddController(&controller.Controller{ Name: "example-controller", Reconciler: &reconcile.Reconciler{ Reconcile: reconcileExample, }, Watchers: []source.Source{ &source.Kind{Type: &v1.Example{}}, }, Options: controller.Options{}, }) if err != nil { fmt.Printf("无法添加控制器:%v", err) os.Exit(1) } err = mgr.Start(ctrl.SetupSignalHandler()) if err != nil { fmt.Printf("无法启动管理器:%v", err) os.Exit(1) } }
-
部署 Operator:将 Operator 作为一个 Kubernetes 部署(Deployment)或守护进程集(DaemonSet)运行在集群中。
二、扩展 API Server
2.1 查询所有 API Resources
查看所有类型的 api-resources
,包括自己创建的 CR。
kubectl api-resources
2.2 API Service 详解
在 Kubernetes 中,API Service(APIService)是一个用于扩展 Kubernetes API 的机制。它允许你在 Kubernetes 集群中注册和发现自定义的 API 服务器(Custom API Server),从而扩展 Kubernetes 的功能。
2.2.1 APIService 的核心概念
- API 聚合层:Kubernetes 的 API 聚合层允许将多个 API 服务器聚合到一起,形成一个统一的 API 网关。
- APIService 资源:APIService 是 Kubernetes 的一个资源类型,用于定义如何访问一个外部的 API 服务器。
- 自定义 API 服务器:自定义 API 服务器是一个独立的组件,提供新的 API 资源类型。
2.2.2 查询 APIService
kubectl get apiservice
2.2.3 APIService 的结构
一个 APIService 的配置文件通常包含以下字段:
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: <api-service-name>
spec:
group: <api-group>
version: <api-version>
groupPriorityMinimum: <priority>
versionPriority: <version-priority>
service:
name: <service-name>
namespace: <service-namespace>
# 可选字段
insecureSkipTLSVerify: <bool>
caBundle: <base64-encoded-certificate>
2.3 API Server 详解
2.3.1 Kubernetes API Server(kube-apiserver)的作用
- 处理 API 请求:接收并处理来自客户端的所有 API 请求。
- 数据存储:维护集群的状态数据,通常使用 etcd 作为底层存储。
- 认证与授权:验证客户端的身份和权限。
- API 聚合:支持聚合多个 API 服务,形成一个统一的 API 网关。
2.3.2 kube-apiserver 与客户端的交互
- 请求方式:客户端通过 HTTP 协议与 kube-apiserver 进行交互。
- 请求格式:客户端发送的请求通常遵循 RESTful API 的规范。
- 认证与授权:客户端需要提供身份凭证,kube-apiserver 使用 RBAC 来验证权限。
- 示例请求:
kubectl get pods
2.3.3 kube-apiserver 与 Local APIService 的交互
- APIService 的概念:Local 类型的 APIService 表示这些 API 服务是由 kube-apiserver 本身提供的。
- 交互机制:kube-apiserver 的聚合层会将所有注册的 APIService 聚合到一起,形成一个统一的 API 网关。
- 数据流动:客户端发送请求,kube-apiserver 根据请求的路径和版本,确定对应的 APIService。
- 示例:
kubectl get deployment my-deployment
2.4 API 聚合层详解
API 聚合层(Aggregation Layer)是 Kubernetes 的一个高级功能,允许用户通过扩展 Kubernetes 的 API,添加新的 API 路径和功能。
2.4.1 API 聚合层的工作原理
要使用聚合层,用户需要创建一个 APIService 对象。APIService 是 Kubernetes 的一个资源对象,用于声明一个 API 的路径。
2.4.2 API 聚合层的运行
聚合层在 kube-apiserver 进程内运行。当一个 API 请求到达 kube-apiserver 时,聚合层会检查请求的路径。如果路径匹配某个已注册的 APIService 对象,聚合层会将请求转发到对应的外部 API 服务器。
2.4.3 API 聚合层与 CRD 的区别
- 编程需求:API 聚合层需要编程,CRD 无需编程。
- API 服务器:API 聚合层需要一个独立的 API 服务器,CRD 不需要。
- API 版本控制:API 聚合层支持多个 API 版本,CRD 的版本控制相对简单。
- 支持的操作:API 聚合层支持所有 CRUD 操作,CRD 仅支持基本的 CRUD 操作。
- 维护成本:API 聚合层维护成本较高,CRD 维护成本较低。
- 适用场景:API 聚合层适用于需要高度灵活性和自定义行为的场景,CRD 适用于需要快速扩展 Kubernetes 功能的场景。
2.5 扩展 API Server
扩展 API Server 是另一种扩展 Kubernetes 的方式,允许你在 Kubernetes 集群中添加新的 API 组(API Group),从而支持新的资源类型和操作。
2.5.1 扩展 API Server 的核心概念
- API 组:通过扩展 API Server,可以定义一个新的 API 组(如 example.com),并在其中添加新的资源类型。
- 资源实现:扩展 API Server 需要实现对新资源的 CRUD 操作(创建、读取、更新、删除)。
2.5.2 实现扩展 API Server 的步骤
-
定义 APIService:
apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: name: v1.example.com spec: group: example.com version: v1 groupPriorityMinimum: 100 versionPriority: 10 service: name: example-api-server namespace: default insecureSkipTLSVerify: true
-
创建 Service:
apiVersion: v1 kind: Service metadata: name: example-api-server spec: selector: app: example-api-server ports: - name: http port: 80 targetPort: 8080
-
实现 API Server:
package main import ( "context" "flag" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/routes" "k8s.io/client-go/rest" ) func main() { // 配置 API Server config := server.NewConfig() config.Version = "v1" config.Handler = newHandler() config.Authentication = authentication.NewConfig() config.Authorization = authorization.NewConfig() // 启动 API Server server, err := server.New(config) if err != nil { log.Error(err, "无法创建 API Server") os.Exit(1) } if err := server.Start(); err != nil { log.Error(err, "无法启动 API Server") os.Exit(1) } } func newHandler() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/example", handleExample) return mux } func handleExample(w http.ResponseWriter, r *http.Request) { // 实现 CRUD 逻辑 }
-
部署自定义 API 服务器:
apiVersion: apps/v1 kind: Deployment metadata: name: example-api-server spec: replicas: 1 selector: matchLabels: app: example-api-server template: metadata: labels: app: example-api-server spec: containers: - name: example-api-server image: your-custom-api-server:latest ports: - containerPort: 8080
-
应用配置:
kubectl apply -f apiservice.yaml kubectl apply -f service.yaml kubectl apply -f deployment.yaml
三、Admission Controller(准入控制器)
Admission Controller 是 Kubernetes 中一个强大的扩展机制,允许用户在 API 请求被处理之前对请求进行验证、修改或拒绝。Kubernetes 提供了两种主要的准入控制器实现方式:Server-Side Admission 和 Webhook Admission。
3.1 Server-Side Admission
- 开发语言:使用 Go 语言编写插件。
- 插件开发:开发者需要实现 Kubernetes 的准入控制器接口。
- 编译与部署:插件需要编译成共享库,并在 API Server 的配置文件中加载。
3.2 Webhook Admission
- 开发语言:允许使用任何语言编写 Webhook 服务。
- 服务暴露:开发者需要编写一个独立的 Web 服务。
- 配置与注册:在 Kubernetes API Server 的配置文件中注册 Webhook 服务。
3.3 准入控制器的工作流程
- 请求到达 API Server:客户端发送一个 API 请求到 Kubernetes API Server。
- 准入控制器拦截请求:API Server 调用所有已注册的准入控制器对请求进行处理。
- 准入控制器处理逻辑:
- Server-Side Admission:插件在 API Server 内部对请求进行处理。
- Webhook Admission:API Server 将请求转发到 Webhook 服务。
- 处理结果:
- 允许:API Server 继续处理请求。
- 拒绝:API Server 返回错误信息给客户端。
- 修改:准入控制器可以对请求进行修改。
- 响应客户端:API Server 将处理结果返回给客户端。
3.4 准入控制的优缺点
Server-Side Admission 的优缺点
- 优点:
- 性能:处理速度较快,延迟较低。
- 权限:插件可以访问 Kubernetes API Server 的所有内部功能。
- 稳定:插件的运行状态直接影响 API Server 的性能。
- 缺点:
- 耦合性:插件与 API Server 有较强的耦合性。
- 复杂性:开发和维护成本较高。
Webhook Admission 的优缺点
- 优点:
- 解耦:Webhook 服务独立于 Kubernetes API Server。
- 灵活性:可以使用任何语言开发 Webhook 服务。
- 易于扩展:可以根据需要动态扩展 Webhook 服务的处理能力。
- 缺点:
- 延迟:可能会增加请求的处理时间。
- 复杂性:需要管理 Webhook 服务的部署、可用性和安全性。
3.5 实际应用中的注意事项
- 性能考虑:对于高负载的集群,Server-Side Admission 通常比 Webhook Admission 更优。
- 安全性:确保 Webhook 服务的安全性,使用 TLS 加密通信。
- 可靠性:确保准入控制器的稳定性和可靠性。
- 监控与日志:配置监控工具,启用详细的日志记录。