扩展 Kubernetes API





5.00/5 (2投票s)
Kubernetes 中的最佳实践
Kubernetes 已经拥有丰富的资源集,从作为构建块的 Pod 到更高级别的资源,如有状态集和部署。现代云原生应用程序可以以 Kubernetes 资源及其高级配置选项的形式进行部署。然而,当需要人工专业知识和操作时,它们就显得不足了。
本文摘自 Packt Publishing 出版、Onur Yılmaz 撰写的书籍《Kubernetes 设计模式与扩展》。本书涵盖了 Kubernetes 的最佳实践、设计模式、Kubernetes 扩展点的基础知识、Kubernetes 中的网络模型等等。
在本文中,您将学习扩展 Kubernetes API、创建和部署自定义资源定义、自定义控制器等等。
Kubernetes 允许通过新资源扩展其自身的 API,并以 Kubernetes 原生对象的方式操作它们,具有以下特性:
- RESTful API:新资源直接包含在 RESTful API 中,因此它们可以通过其特殊端点访问。
- 身份验证和授权:所有新资源的请求都像原生请求一样,经过身份验证和授权步骤。
- OpenAPI 发现:新资源可以被发现并集成到 OpenAPI 规范中。
- 客户端库:可以使用 kubectl 或 client-go 等客户端库与新资源进行交互。
扩展 Kubernetes API 涉及两个主要步骤:
- 创建新的 Kubernetes 资源以引入新的 API 类型
- 控制和自动化操作以实现自定义逻辑作为附加的 API 控制器
自定义资源定义
在 Kubernetes 中,所有资源都在 Kubernetes API 服务器中拥有其 REST 端点。REST 端点通过使用 /api/v1/namespaces/default/pods 等路径,启用对特定对象(如 Pod)的操作。自定义资源是 Kubernetes API 的扩展,可以在运行时动态添加或删除。它们使集群用户能够操作扩展资源。
自定义资源在自定义资源定义(CRD)对象中定义。使用内置的 Kubernetes 资源(即 CRD),可以通过 Kubernetes API 本身添加新的 Kubernetes API 端点。
创建和部署自定义资源定义
假设客户端希望以可扩展的云原生方式在 Kubernetes 中查看天气报告。我们期望扩展 Kubernetes API,以便客户端和未来的应用程序能够原生使用天气报告资源。我们希望创建 CustomResourceDefinitions
并将其部署到集群以检查其效果,并使用新定义的资源来创建扩展对象。
让我们从执行以下步骤开始:
- 使用以下命令通过
kubectl
部署自定义资源定义:kubectl apply -f k8s-operator-example/deploy/crd.yaml
自定义资源定义是 Kubernetes 资源,可以动态注册新的自定义资源。一个
WeatherReport
的自定义资源示例可以在 k8s-operator-example/deploy/crd.yaml 文件中定义,如下所示:apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: weatherreports.k8s.packt.com spec: group: k8s.packt.com names: kind: WeatherReport listKind: WeatherReportList plural: weatherreports singular: weatherreport scope: Namespaced version: v1
与其他所有 Kubernetes 资源一样,CRD 具有 API 版本、种类、元数据和规范组。此外,CRD 的规范还包括新自定义资源的定义。对于
WeatherReport
,将在 k8s.packt.com 下创建一个 REST 端点,版本为 v1,并且其复数和单数形式将在客户端中使用。 - 使用以下命令检查部署到集群的自定义资源:
kubectl get crd
您将获得以下输出:
如上图所示,天气报告 CRD 已使用复数名称和组名称定义。
- 检查 API 服务器中新自定义资源的 REST 端点:
kubectl proxy & curl -s localhost:8001 |grep packt
您将获得以下输出:
创建了新的端点,这表明 Kubernetes API 服务器已经扩展,可以与我们的新自定义资源
weatherreports
一起工作。 - 从 Kubernetes 客户端(如
kubectl
)检查天气报告实例:kubectl get weatherreports
您将获得以下输出:
尽管“未找到资源”的输出看起来像是错误指示,但它向我们表明,正如预期,没有
weatherreports
资源的活动实例。它告诉我们,除了创建CustomResourceDefinition
之外,无需任何进一步配置,Kubernetes API 服务器已通过新端点进行扩展,并且客户端已准备好使用新自定义资源。定义自定义资源后,现在可以使用
WeatherReport
创建、更新和删除资源。一个WeatherReport
的示例可以定义,如 k8s-operator-example/deploy/cr.yaml 文件所示:apiVersion: "k8s.packt.com/v1" kind: WeatherReport metadata: name: amsterdam-daily spec: city: Amsterdam days: 1
WeatherReport
资源与内置资源具有相同的结构,由 API 版本、种类、元数据和规范组成。在此示例中,规范表示此资源是阿姆斯特丹市过去 1 天的天气报告。 - 使用以下命令部署天气报告示例:
kubectl apply -f k8s-operator-example/deploy/cr.yaml
- 使用以下命令检查新创建的天气报告:
kubectl get weatherreports
您将看到以下输出:
- 使用以下命令进行清理:
kubectl delete -f k8s-operator-example/deploy/cr.yaml kubectl delete -f k8s-operator-example/deploy/crd.yaml
自定义控制器
自定义控制器,也称为操作符(Operator),是将领域知识和人类专业知识转换为代码的应用程序。操作符与自定义资源协同工作,并在创建、更新或删除自定义资源时采取必要的行动。操作符的主要任务可以分为三个部分:观察、分析和行动,如下图所示:
这些阶段解释如下:
- 观察:监控自定义资源和相关内置资源(如 Pod)的变化。
- 分析:对观察到的变化进行分析,并决定采取哪些行动。
- 行动:根据分析和要求采取行动,并继续观察变化。
对于天气报告示例,操作符模式预计将按以下方式工作:
- 观察:等待天气报告资源的创建、更新和删除。
- 分析:
- 如果请求新的报告,则创建一个 Pod 来收集天气报告结果并更新天气报告资源。
- 如果天气报告更新,则更新 Pod 以收集新的天气报告结果。
- 如果天气报告被删除,则删除相应的 Pod。
- 行动:在集群上执行分析步骤中的行动,并继续使用观察进行监控。
操作符已经应用于 Kubernetes 环境,因为它们使复杂的应用程序能够以最少的人工交互在云上运行。存储提供商(Rook)、数据库应用程序(MySQL、CouchDB、PostgreSQL)、大数据解决方案(Spark)、分布式键/值存储(Consul、etcd)以及许多其他现代云原生应用程序都通过其官方操作符安装在 Kubernetes 上。
操作员开发
操作符是原生的 Kubernetes 应用程序,它们与 Kubernetes API 进行广泛交互。因此,与 Kubernetes API 兼容并以直接的方法将领域专业知识转化为软件对于操作符开发至关重要。考虑到这些因素,开发操作符有两种途径,如下面各节所述。
Kubernetes 示例控制器
在官方 Kubernetes 存储库中,维护着一个实现监视自定义资源的示例控制器。该存储库演示了如何注册新的自定义资源以及如何对新资源执行基本操作,例如创建、更新或列出。此外,还实现了控制器逻辑以展示如何采取行动。该存储库和与 Kubernetes API 的交互是一种完整的方法,向您展示了如何创建类似 Kubernetes 的自定义控制器。
操作员框架
操作符框架在 KubeCon 2018 上发布,作为一个管理 Kubernetes 原生应用程序的开源工具包。操作符 SDK 是该框架的一部分,它通过提供更高级别的 API 抽象和代码生成来简化操作符开发。操作符框架及其环境工具集是开源的,并由 CoreOS 控制下的社区维护。
操作符开发的完整生命周期涵盖以下主要步骤:
- 创建操作符项目:对于
WeatherReport
自定义资源,使用操作符框架 SDK CLI 创建一个 Go 语言的操作符项目。 - 定义自定义资源规范:
WeatherReport
自定义资源的规范以 Go 语言定义。 - 实现处理程序逻辑:天气报告收集所需的手动操作以 Go 语言实现。
- 构建操作符:使用操作符框架 SDK CLI 构建操作符项目。
- 部署操作符:将操作符部署到集群,并通过创建自定义资源进行测试。
创建和部署 Kubernetes 操作符
客户端希望自动化天气报告收集的操作。他们目前正在连接第三方数据提供商并检索结果。此外,他们希望在集群中使用云原生 Kubernetes 解决方案。我们期望通过实现 Kubernetes 操作符来自动化天气报告数据收集的操作。我们将使用操作符框架 SDK 创建一个 Kubernetes 操作符,并通过创建自定义资源、自定义控制器逻辑,最后部署到集群来利用它。让我们从执行以下步骤开始:
- 使用操作符框架 SDK 工具,通过以下命令创建操作符项目:
operator-sdk new k8s-operator-example --api-version=k8s. packt.com/v1 --kind=WeatherReport
此命令创建一个名为 k8s-operator-example 的全新 Kubernetes 操作符项目,并监视 k8s.packt.com/v1 下定义的
WeatherReport
自定义资源的变化。生成的 Operator 项目位于 k8s-operator-example 文件夹下。 - 在 deploy/crd.yaml 文件中已经生成了自定义资源定义。但是,自定义资源的规范留空,以便开发人员可以填充。自定义资源的规范和状态在 Go 中编码,如 pkg/apis/k8s/v1/types.go 所示:
type WeatherReport struct { metav1.TypeMeta 'json:",inline"' metav1.ObjectMeta 'json:"metadata"' Spec WeatherReportSpec 'json:"spec"' Status WeatherReportStatus 'json:"status,omitempty"' } type WeatherReportSpec struct { City string 'json:"city"' Days int 'json:"days"' }
在上述代码片段中,
WeatherReport
由元数据、spec 和 status 组成,就像任何内置的 Kubernetes 资源一样。WeatherReportSpec
包含配置,在我们的示例中是 City 和 Days。WeatherReportStatus
包含 State 和 Pod,用于跟踪状态以及为天气报告收集创建的 Pod。注意:您可以在 Github 上查看完整代码。
- 在此示例中,当创建新的
WeatherReport
对象时,我们将发布一个查询天气服务并将结果写入控制台输出的 Pod。所有这些步骤都在 pkg/stub/handler.go 文件中编码,如下所示:func (h *Handler) Handle(ctx types.Context, event types.Event) error { switch o := event.Object.(type) { case *apiv1.WeatherReport: if o.Status.State == "" { weatherPod := weatherReportPod(o) err := action.Create(weatherPod) if err != nil && !errors.IsAlreadyExists(err) { logrus.Errorf("Failed to create weather report pod : %v", err)
注意:您可以在 Github 上查看完整代码。
- 使用 Operator SDK 和工具集将完整的项目构建为 Docker 容器:
operator-sdk build <DOCKER_IMAGE:DOCKER_TAG>
生成的 Docker 容器被推送到 Docker Hub,作为 onuryilmaz/k8s-operator-example,以供集群中进一步使用。
- 使用以下命令将操作符部署到集群中:
kubectl create -f deploy/crd.yaml kubectl create -f deploy/operator.yaml
操作符成功部署后,可以按如下方式检查日志:
kubectl logs -l name=k8s-operator-example
输出如下
- 部署自定义资源定义和自定义控制器后,是时候创建一些资源并收集结果了。如下所示创建新的
WeatherReport
实例:kubectl create -f deploy/cr.yaml
成功创建后,可以检查
WeatherReport
的状态:kubectl describe weatherreport amsterdam-daily
您将看到以下输出:
- 由于操作符为新的天气报告创建了一个 Pod,我们应该会看到它正在运行并收集结果:
kubectl get pods
您将看到以下结果:
- 使用以下命令获取天气报告结果:
kubectl logs $(kubectl get weatherreport amsterdam-daily -o jsonpath={.status.pod})
您将看到以下输出:
- 使用以下命令进行清理:
kubectl delete -f deploy/cr.yaml kubectl delete -f deploy/operator.yaml kubectl delete -f deploy/crd.yaml
摘要
总而言之,在本文中,我们学习了扩展 Kubernetes API、创建和部署自定义资源定义、自定义控制器等等。要了解更多关于 Kubernetes 设计模式并理解 Kubernetes 扩展点的基础知识,请阅读 Packt Publishing 出版的书籍《Kubernetes 设计模式与扩展》。
历史
- 2019年12月3日:初始版本