第 11 章 Operator SDK
11.1. Operator SDK 入门
本指南将介绍 Operator SDK 的基础知识,指导可作为集群管理员访问基于 Kubernetes 的集群(如 OpenShift Container Platform)的 Operator 作者构建简单 Go-based Memcached Operator 的示例,并管理从安装到升级的整个生命周期。
通过以下两个 Operator Framework 核心组件便可实现这一目的:Operator SDK(operator-sdk
CLI 工具和 controller-runtime
库 API)以及 Operator Lifecycle Manager (OLM)。
OpenShift Container Platform 4 支持 Operator SDK v0.7.0 或更高版本。
11.1.1. Operator SDK 构架
Operator Framework 是一个开源工具包,用于以有效、自动化且可扩展的方式管理 Kubernetes 原生应用程序,即 Operator。Operator 利用 Kubernetes 的可扩展性来展现云服务的自动化优势,如置备、扩展以及备份和恢复,同时能够在 Kubernetes 可运行的任何地方运行。
Operator 有助于简化对 Kubernetes 上的复杂、有状态的应用程序的管理。然而,现在编写 Operator 并不容易,会面临一些挑战,如使用低级别 API、编写样板文件以及缺乏模块化功能(这会导致重复工作)。
Operator SDK 是一个框架,通过提供以下内容来降低 Operator 的编写难度:
- 高级 API 和抽象,用于更直观地编写操作逻辑
- 支架和代码生成工具,用于快速引导新项目
- 扩展项,覆盖常见的 Operator 用例
11.1.1.1. 工作流
Operator SDK 提供以下工作流来开发新的 Operator:
- 使用 Operator SDK 命令行界面 (CLI) 新建一个 Operator 项目。
- 通过添加自定义资源定义 (CRD) 来定义新的资源 API。
- 使用 Operator SDK API 来指定要监视的资源。
- 在指定的处理程序中定义 Operator 协调逻辑,并使用 Operator SDK API 与资源交互。
- 使用 Operator SDK CLI 来构建和生成 Operator 部署清单。
图 11.1. Operator SDK 工作流
在高级别上,使用了 Operator SDK 的 Operator 会在 Operator 作者定义的处理程序中处理与被监视资源相关的事件,并采取措施协调应用程序的状态。
11.1.1.2. 管理器文件
Operator 的主要程序为 cmd/manager/main.go
中的管理器文件。管理器会自动注册 pkg/apis/
下定义的所有自定义资源 (CR) 的方案,并运行 pkg/controller/
下的所有控制器。
管理器可限制所有控制器监视资源的命名空间:
mgr, err := manager.New(cfg, manager.Options{Namespace: namespace})
默认情况下,这是 Operator 运行时所处的命名空间。要监视所有命名空间,把命名空间选项设为空:
mgr, err := manager.New(cfg, manager.Options{Namespace: ""})
11.1.1.3. Prometheus Operator 支持
Prometheus 是一个开源系统监视和警报工具包。Prometheus Operator 会创建、配置和管理在基于 Kubernetes 的集群(如 OpenShift Container Platform)中运行的 Prometheus 集群。
默认情况下,Operator SDK 中包括帮助函数,用于在任何生成的 Go-based Operator 中自动设置指标,以便在部署了 Prometheus Operator 的集群上使用。
11.1.2. 安装 Operator SDK CLI
Operator SDK 配有一个 CLI 工具,可协助开发人员创建、构建和部署新的 Operator 项目。您可在工作站上安装 SDK CLI,为编写您自己的 Operator 做准备。
11.1.2.1. 从 GitHub 版本安装
您可从 GitHub 上的项目下载并安装 SDK CLI 的预构建发行版文件。
先决条件
-
docker
v17.03+ -
已安装 OpenShift CLI (
oc
) v4.1+ - 访问基于 Kubernetes v1.11.3+ 的集群
- 访问容器 registry
流程
设置发行版本变量:
RELEASE_VERSION=v0.8.0
下载发行版二进制文件。
Linux:
$ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
macOS:
$ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin
验证所下载的发行版本二进制文件。
下载所提供的 ASC 文件。
Linux:
$ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu.asc
macOS:
$ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin.asc
将二进制文件与对应的 ASC 文件放在同一个目录中,并运行以下命令来验证该二进制文件:
Linux:
$ gpg --verify operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu.asc
macOS:
$ gpg --verify operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin.asc
如果您的工作站上没有维护人员公钥,则会出现以下错误:
$ gpg --verify operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin.asc $ gpg: assuming signed data in 'operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin' $ gpg: Signature made Fri Apr 5 20:03:22 2019 CEST $ gpg: using RSA key <key_id> 1 $ gpg: Can't check signature: No public key
- 1
- RSA 密钥字符串。
要下载密钥,请运行以下命令,用上一条命令输出的 RSA 密钥字符串来替换
<key_id>
:$ gpg [--keyserver keys.gnupg.net] --recv-key "<key_id>" 1
- 1
- 如果您尚未配置密钥服务器,请使用
--keyserver
选项指定一个密钥服务器。
在您的
PATH
中安装发行版本二进制文件:Linux:
$ chmod +x operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu $ sudo cp operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu /usr/local/bin/operator-sdk $ rm operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
macOS:
$ chmod +x operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin $ sudo cp operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin /usr/local/bin/operator-sdk $ rm operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin
验证是否已正确安装 CLI 工具:
$ operator-sdk version
11.1.2.2. 通过 Homebrew 安装
可使用 Homebrew 来安装 SDK CLI。
先决条件
流程
使用
brew
命令安装 SDK CLI:$ brew install operator-sdk
验证是否已正确安装 CLI 工具:
$ operator-sdk version
11.1.2.3. 通过源代码编译并安装
可获取 Operator SDK 源代码来编译和安装 SDK CLI。
先决条件
流程
克隆
operator-sdk
存储库:$ mkdir -p $GOPATH/src/github.com/operator-framework $ cd $GOPATH/src/github.com/operator-framework $ git clone https://github.com/operator-framework/operator-sdk $ cd operator-sdk
检查所需的发行版本分支:
$ git checkout master
编译并安装 SDK CLI:
$ make dep $ make install
该操作会在 $GOPATH/bin 中安装 CLI 二进制
operator-sdk
。验证是否已正确安装 CLI 工具:
$ operator-sdk version
11.1.3. 使用 Operator SDK 来构建 Go-based Memcached Operator
Operator SDK 可简化 Kubernetes 原生应用程序的构建,构建该应用程序原本需要深入掌握特定于应用程序的操作知识。SDK 不仅降低了这一障碍,而且有助于减少许多常见管理功能(如计量或监控)所需的样板代码量。
本流程介绍了一个使用 SDK 提供的工具和库构建简单 Memcached Operator 的示例。
先决条件
- 开发工作站已安装 Operator SDK CLI
-
基于 Kubernetes 的集群(v1.8 或更高版本,支持
apps/v1beta2
API 组,如 OpenShift Container Platform 4.2)上已安装 Operator Lifecycle Manager (OLM) -
使用具有
cluster-admin
权限的账户访问该集群 -
已安装 OpenShift CLI (
oc
) v4.1+
流程
创建一个新项目。
使用 CLI 来新建
memcached-operator
项目:$ mkdir -p $GOPATH/src/github.com/example-inc/ $ cd $GOPATH/src/github.com/example-inc/ $ operator-sdk new memcached-operator --dep-manager dep $ cd memcached-operator
添加新的自定义资源定义 (CRD)。
使用 CLI 来添加名为
Memcached
的新 CRD API,将APIVersion
设置为cache.example.com/v1apha1
,将Kind
设置为Memcached
:$ operator-sdk add api \ --api-version=cache.example.com/v1alpha1 \ --kind=Memcached
这样会将 Memcached 资源 API 构建至
pkg/apis/cache/v1alpha1/
下。修改
pkg/apis/cache/v1alpha1/memcached_types.go
文件中Memcached
自定义资源 (CR) 的 spec 和状态:type MemcachedSpec struct { // Size is the size of the memcached deployment Size int32 `json:"size"` } type MemcachedStatus struct { // Nodes are the names of the memcached pods Nodes []string `json:"nodes"` }
修改好
*_types.go
文件后,务必要运行以下命令来更新该资源类型的生成代码:$ operator-sdk generate k8s
添加新控制器。
在项目中添加新控制器以观察和协调 Memcached 资源:
$ operator-sdk add controller \ --api-version=cache.example.com/v1alpha1 \ --kind=Memcached
这样会在
pkg/controller/memcached/
下构建新控制器实现。在本示例中,将所生成的控制器文件
pkg/controller/memcached/memcached_controller.go
替换成示例实现。示例控制器会对每个
Memcached
CR 执行以下协调逻辑:- 如果尚无 Memcached Deployment,请创建一个。
-
确保 Deployment 大小与
Memcached
CR spec 中指定的大小相同。 -
使用 Memcached Pod 的名称来更新
Memcached
CR 状态。
接下来的两个子步骤用于检查控制器如何监视资源以及协调循环会如何被触发。您可跳过这些步骤,直接构建和运行 Operator。
检查
pkg/controller/memcached/memcached_controller.go
文件中的控制器实现,了解控制器如何监视资源。首先要监视的是作为主要资源的 Memcached 类型。对于每个添加、更新或删除事件,协调循环均会针对该 Memcached 对象发送一个协调
Request
(<namespace>:<name>
键):err := c.Watch( &source.Kind{Type: &cachev1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
接下来监视 Deployment,但事件处理程序会将每个事件映射到 Deployment 所有者的协调
Request
中。即本例中为其创建 Deployment 的 Memcached 对象。这样可让控制器将 Deployment 视为辅助资源:err := c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ IsController: true, OwnerType: &cachev1alpha1.Memcached{}, })
每个控制器均有一个协调器对象,且该对象带有实现协调循环的
Reconcile()
方法。系统会将Request
参数传递到该协调循环,该参数是一个用于从缓存中查找主资源对象 Memcached 的<namespace>:<name>
键:func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) { // Lookup the Memcached instance for this reconcile request memcached := &cachev1alpha1.Memcached{} err := r.client.Get(context.TODO(), request.NamespacedName, memcached) ... }
根据
Reconcile()
的返回值,协调Request
可能会重新排队,且可能再次触发循环:// Reconcile successful - don't requeue return reconcile.Result{}, nil // Reconcile failed due to error - requeue return reconcile.Result{}, err // Requeue for any reason other than error return reconcile.Result{Requeue: true}, nil
构建并运行 Operator。
在运行 Operator 之前,必须使用 Kubernetes API 服务器来注册 CRD:
$ oc create \ -f deploy/crds/cache_v1alpha1_memcached_crd.yaml
注册 CRD 之后,运行 Operator 时有两个选项可供选择:
- 作为 Kubernetes 集群内的一个 Deployment 来运行
- 作为集群外的 Go 程序运行
选择以下任一方法。
选项 A:作为集群内的一个 Deployment 来运行。
构建
memcached-operator
镜像并将其推送至 registry:$ operator-sdk build quay.io/example/memcached-operator:v0.0.1
Deployment 清单在
deploy/operator.yaml
中生成。按如下方式更新 Deployment 镜像,因为默认值只是一个占位符:$ sed -i 's|REPLACE_IMAGE|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml
-
确保 Quay.io 上有一个可供下一步使用的账户,或者替换您的首选容器 registry。在 registry 中,创建一个名为
memcached-operator
的新公共镜像存储库。 将镜像推送至 registry:
$ docker push quay.io/example/memcached-operator:v0.0.1
设置 RBAC 并部署
memcached-operator
:$ oc create -f deploy/role.yaml $ oc create -f deploy/role_binding.yaml $ oc create -f deploy/service_account.yaml $ oc create -f deploy/operator.yaml
验证
memcached-operator
是否正在运行:$ oc get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE memcached-operator 1 1 1 1 1m
选项 B:在集群外本地运行。
这是开发循环中的首选方法,可加快部署和测试的速度。
使用
$HOME/.kube/config
中的默认 Kubernetes 配置文件在本地运行 Operator:$ operator-sdk up local --namespace=default
您可借助标记
--kubeconfig=<path/to/kubeconfig>
来使用特定的kubeconfig
。
通过创建 Memcached CR 来验证该 Operator 可否部署 Memcached 应用程序。
创建
deploy/crds/cache_v1alpha1_memcached_cr.yaml
中生成的Memcached
CR 示例:$ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml apiVersion: "cache.example.com/v1alpha1" kind: "Memcached" metadata: name: "example-memcached" spec: size: 3 $ oc apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml
确保
memcached-operator
为 CR 创建 Deployment:$ oc get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE memcached-operator 1 1 1 1 2m example-memcached 3 3 3 3 1m
检查 Pod 和 CR 状态,以确认其状态中是否更新了
memcached
Pod 名称:$ oc get pods NAME READY STATUS RESTARTS AGE example-memcached-6fd7c98d8-7dqdr 1/1 Running 0 1m example-memcached-6fd7c98d8-g5k7v 1/1 Running 0 1m example-memcached-6fd7c98d8-m7vn7 1/1 Running 0 1m memcached-operator-7cc7cfdf86-vvjqk 1/1 Running 0 2m $ oc get memcached/example-memcached -o yaml apiVersion: cache.example.com/v1alpha1 kind: Memcached metadata: clusterName: "" creationTimestamp: 2018-03-31T22:51:08Z generation: 0 name: example-memcached namespace: default resourceVersion: "245453" selfLink: /apis/cache.example.com/v1alpha1/namespaces/default/memcacheds/example-memcached uid: 0026cc97-3536-11e8-bd83-0800274106a1 spec: size: 3 status: nodes: - example-memcached-6fd7c98d8-7dqdr - example-memcached-6fd7c98d8-g5k7v - example-memcached-6fd7c98d8-m7vn7
通过更新部署的大小来验证 Operator 可否管理所部署的 Memcached 应用程序。
将
memcached
CR 中的spec.size
字段从3
改为4
:$ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml apiVersion: "cache.example.com/v1alpha1" kind: "Memcached" metadata: name: "example-memcached" spec: size: 4
应用更改:
$ oc apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml
确认 Operator 已更改 Deployment 大小:
$ oc get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE example-memcached 4 4 4 4 5m
清理资源:
$ oc delete -f deploy/crds/cache_v1alpha1_memcached_cr.yaml $ oc delete -f deploy/crds/cache_v1alpha1_memcached_crd.yaml $ oc delete -f deploy/operator.yaml $ oc delete -f deploy/role.yaml $ oc delete -f deploy/role_binding.yaml $ oc delete -f deploy/service_account.yaml
11.1.4. 使用 Operator Lifecycle Manager 来管理 Memcached Operator
上一节介绍了如何手动运行 Operator。下面我们将探索如何使用 Operator Lifecycle Manager (OLM),OLM 将为生产环境中运行的 Operator 启用更强大的部署模型。
OLM 可帮助您在 Kubernetes 集群中安装、更新所有 Operator(及其相关服务)并对其整个生命周期实施一般性管理。OLM 将作为 Kubernetes 的扩展程序运行,支持您使用 oc
实现所有生命周期管理功能,而无需额外工具。
先决条件
-
基于 Kubernetes 的集群(v1.8 或更高版本,支持
apps/v1beta2
API 组,如已启用预览 OLM 的 OpenShift Container Platform 4.2)上已安装 OLM - 已构建 Memcached Operator
流程
生成 Operator 清单。
Operator 清单描述了如何整体显示、创建和管理应用程序,即本例中的 Memcached。该清单由
ClusterServiceVersion
(CSV) 对象定义,是运行 OLM 的必要条件。您可使用以下命令来生成 CSV 清单:
$ operator-sdk olm-catalog gen-csv --csv-version 0.0.1
注意该命令通过您在构建 Memcached Operator 时创建的
memcached-operator/
目录运行。在本指南中,我们将继续使用该预定义清单文件来执行后续步骤。您可更改清单中的镜像字段,以反映通过前面的步骤构建的镜像,但这不是硬性要求。
注意更多有关手动定义清单文件的信息,请参阅构建用于 Operator Framework 的 CSV。
部署 Operator。
创建一个 OperatorGroup,指定 Operator 的目标命名空间。在要创建 CSV 的命名空间中创建以下 OperatorGroup。本例中使用了
default
命名空间:apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: memcached-operator-group namespace: default spec: targetNamespaces: - default
将 Operator 的 CSV 清单应用于集群中指定的命名空间:
$ curl -Lo memcachedoperator.0.0.1.csv.yaml https://raw.githubusercontent.com/operator-framework/getting-started/master/memcachedoperator.0.0.1.csv.yaml $ oc apply -f memcachedoperator.0.0.1.csv.yaml $ oc get csv memcachedoperator.v0.0.1 -n default -o json | jq '.status'
应用该清单时,集群不会立即更新,因为尚未满足清单中指定的要求。
创建角色、角色绑定和服务账户以便向 Operator 授予资源权限,创建自定义资源定义 (CRD) 以便创建受 Operator 管理的 Memcached 类型:
$ oc create -f deploy/crds/cache_v1alpha1_memcached_crd.yaml $ oc create -f deploy/service_account.yaml $ oc create -f deploy/role.yaml $ oc create -f deploy/role_binding.yaml
注意这些文件在您构建 Memcached Operator 时由 Operator SDK 生成并存储至
deploy/
目录中。因为在应用清单时,OLM 会在特定命名空间中创建 Operator,所以管理员可利用原生 Kubernetes RBAC 权限模型来限制哪些用户可以安装 Operator。
创建应用程序实例。
Memcached Operator 正在
default
命名空间中运行。用户通过CustomResource
实例与 Operator 交互;这种情况下,资源拥有类型Memcached
。原生 Kubernetes RBAC 也适用于CustomResource
,让管理员能够控制与每个 Operator 的交互。在该命名空间中创建 Memcached 实例将触发 Memcached Operator,以针对运行由 Operator 管理的 Memcached 服务器的 Pod 进行实例化。您创建的
CustomResource
越多,在此命名空间中运行的 Memcached Operator 管理的 Memcached 实例就越独特。$ cat <<EOF | oc apply -f - apiVersion: "cache.example.com/v1alpha1" kind: "Memcached" metadata: name: "memcached-for-wordpress" spec: size: 1 EOF $ cat <<EOF | oc apply -f - apiVersion: "cache.example.com/v1alpha1" kind: "Memcached" metadata: name: "memcached-for-drupal" spec: size: 1 EOF $ oc get Memcached NAME AGE memcached-for-drupal 22s memcached-for-wordpress 27s $ oc get pods NAME READY STATUS RESTARTS AGE memcached-app-operator-66b5777b79-pnsfj 1/1 Running 0 14m memcached-for-drupal-5476487c46-qbd66 1/1 Running 0 3s memcached-for-wordpress-65b75fd8c9-7b9x7 1/1 Running 0 8s
更新应用程序。
通过引用旧 Operator 清单的
replaces
字段来创建新 Operator 清单,以手动更新 Operator。OLM 可确保由旧 Operator 管理的所有资源的所有权均转移到至新 Operator,而不用担心任何程序停止执行。升级资源以便在新版 Operator 下运行所需的所有数据迁移均将由 Operator 直接执行。以下命令演示了如何使用新版 Operator 来应用新的 Operator 清单文件,并显示了 Pod 仍在执行:
$ curl -Lo memcachedoperator.0.0.2.csv.yaml https://raw.githubusercontent.com/operator-framework/getting-started/master/memcachedoperator.0.0.2.csv.yaml $ oc apply -f memcachedoperator.0.0.2.csv.yaml $ oc get pods NAME READY STATUS RESTARTS AGE memcached-app-operator-66b5777b79-pnsfj 1/1 Running 0 3s memcached-for-drupal-5476487c46-qbd66 1/1 Running 0 14m memcached-for-wordpress-65b75fd8c9-7b9x7 1/1 Running 0 14m
11.1.5. 其他资源
- 有关 Operator SDK 所创建的项目目录结构的信息,请参阅附录。
- 面向红帽合作伙伴的 Operator 开发指南