$ mkdir -p $HOME/projects/memcached-operator
Operator 开发人员可以利用 Operator SDK 中对 Go 编程语言的支持来构建一个基于 Go 的 Memcached(一个分布式键值存储)Operator 示例,并管理其生命周期。
Red Hat 支持的 Operator SDK CLI 工具版本(包括相关的脚手架和 Operator 项目测试工具)已弃用,并计划在未来版本的 OpenShift Container Platform 中删除。Red Hat 将在此版本的生命周期内为该功能提供错误修复和支持,但此功能将不再接收增强功能,并将从未来的 OpenShift Container Platform 版本中删除。 不建议使用 Red Hat 支持的 Operator SDK 版本创建新的 Operator 项目。拥有现有 Operator 项目的 Operator 作者可以使用 OpenShift Container Platform 4.17 版本中发布的 Operator SDK CLI 工具版本来维护其项目并创建针对较新版本的 OpenShift Container Platform 的 Operator 版本。 以下与 Operator 项目相关的基础镜像未被弃用。这些基础镜像的运行时功能和配置 API 仍受支持,用于错误修复和解决 CVE。
有关 OpenShift Container Platform 中已弃用或删除的主要功能的最新列表,请参阅 OpenShift Container Platform 发行说明中的“已弃用和删除的功能”部分。 有关不受支持的社区维护的 Operator SDK 版本的信息,请参见Operator SDK (Operator Framework)。 |
此过程使用 Operator Framework 的两个核心组件来完成
operator-sdk
CLI 工具和controller-runtime
库 API
在集群上安装、升级和基于角色的访问控制 (RBAC) Operator
已安装 Operator SDK CLI
已安装 OpenShift CLI (oc
) 4.17+
Go 1.21+
使用具有cluster-admin
权限的帐户通过oc
登录到 OpenShift Container Platform 4.17 集群
要允许集群拉取镜像,您推送镜像的仓库必须设置为公开,或者您必须配置镜像拉取密钥
使用 Operator SDK CLI 创建名为memcached-operator
的项目。
为项目创建一个目录
$ mkdir -p $HOME/projects/memcached-operator
切换到该目录
$ cd $HOME/projects/memcached-operator
激活对 Go 模块的支持
$ export GO111MODULE=on
运行operator-sdk init
命令初始化项目
$ operator-sdk init \
--domain=example.com \
--repo=github.com/example-inc/memcached-operator
|
operator-sdk init
命令生成一个go.mod
文件,用于与Go 模块一起使用。在$GOPATH/src/
之外创建项目时,需要使用--repo
标志,因为生成的文 件需要有效的模块路径。
operator-sdk init
命令生成的文 件中包含一个 Kubebuilder PROJECT
文件。从项目根目录运行的后续operator-sdk
命令以及help
输出都会读取此文件,并知道项目类型是 Go。例如
domain: example.com
layout:
- go.kubebuilder.io/v3
projectName: memcached-operator
repo: github.com/example-inc/memcached-operator
version: "3"
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
sdk.x-openshift.io/v1: {}
Operator 的主程序是main.go
文件,它初始化并运行Manager。Manager 自动为所有自定义资源 (CR) API 定义注册 Scheme,并设置和运行控制器和 Webhook。
Manager 可以限制所有控制器监视资源的命名空间
mgr, err := ctrl.NewManager(cfg, manager.Options{Namespace: namespace})
默认情况下,Manager 监视 Operator 运行的命名空间。要监视所有命名空间,可以将namespace
选项留空
mgr, err := ctrl.NewManager(cfg, manager.Options{Namespace: ""})
您还可以使用MultiNamespacedCacheBuilder
函数来监视特定的一组命名空间
var namespaces []string (1)
mgr, err := ctrl.NewManager(cfg, manager.Options{ (2)
NewCache: cache.MultiNamespacedCacheBuilder(namespaces),
})
1 | 命名空间列表。 |
2 | 创建一个Cmd 结构体,以提供共享的依赖项并启动组件。 |
在创建 API 和控制器之前,请考虑您的 Operator 是否需要多个 API 组。本教程涵盖了单个组 API 的默认情况,但要更改项目的布局以支持多组 API,您可以运行以下命令
$ operator-sdk edit --multigroup=true
此命令会更新PROJECT
文件,它应该如下例所示
domain: example.com
layout: go.kubebuilder.io/v3
multigroup: true
...
对于多组项目,API Go 类型文件在apis/<group>/<version>/
目录中创建,控制器在controllers/<group>/
目录中创建。然后相应地更新 Dockerfile。
有关迁移到多组项目的更多详细信息,请参阅Kubebuilder 文档。
使用 Operator SDK CLI 创建自定义资源定义 (CRD) API 和控制器。
运行以下命令以创建具有组cache
、版本v1
和种类Memcached
的 API
$ operator-sdk create api \
--group=cache \
--version=v1 \
--kind=Memcached
出现提示时,输入y
以创建资源和控制器。
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing scaffold for you to edit...
api/v1/memcached_types.go
controllers/memcached_controller.go
...
此过程会在api/v1/memcached_types.go
处生成Memcached
资源 API,并在controllers/memcached_controller.go
处生成控制器。
定义Memcached
自定义资源 (CR) 的 API。
修改api/v1/memcached_types.go
处的 Go 类型定义,使其具有以下spec
和status
// MemcachedSpec defines the desired state of Memcached
type MemcachedSpec struct {
// +kubebuilder:validation:Minimum=0
// Size is the size of the memcached deployment
Size int32 `json:"size"`
}
// MemcachedStatus defines the observed state of Memcached
type MemcachedStatus struct {
// Nodes are the names of the memcached pods
Nodes []string `json:"nodes"`
}
更新资源类型的生成代码
$ make generate
修改 |
上述 Makefile 目标调用 `controller-gen` 实用程序来更新 `api/v1/zz_generated.deepcopy.go` 文件。这确保您的 API Go 类型定义实现了所有 Kind 类型都必须实现的 `runtime.Object` 接口。
在使用 `spec` 和 `status` 字段以及自定义资源定义 (CRD) 验证标记定义 API 后,您可以生成 CRD 清单。
运行以下命令来生成和更新 CRD 清单:
$ make manifests
此 Makefile 目标调用 `controller-gen` 实用程序,以在 `config/crd/bases/cache.example.com_memcacheds.yaml` 文件中生成 CRD 清单。
在生成清单时,OpenAPIv3 模式将添加到 `spec.validation` 块中的 CRD 清单中。此验证块允许 Kubernetes 在创建或更新 Memcached 自定义资源 (CR) 时验证其属性。
可以使用标记(或注释)来配置 API 的验证。这些标记始终具有 `+kubebuilder:validation` 前缀。
有关在 API 代码中使用标记的更多详细信息,请参阅以下 Kubebuilder 文档:
有关 CRD 中 OpenAPIv3 验证模式的更多详细信息,请参阅 Kubernetes 文档。
创建新的 API 和控制器后,您可以实现控制器逻辑。
对于此示例,请将生成的控制器文件 `controllers/memcached_controller.go` 替换为以下示例实现:
/*
Copyright 2020.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://apache.ac.cn/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"reflect"
"context"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
cachev1 "github.com/example-inc/memcached-operator/api/v1"
)
// MemcachedReconciler reconciles a Memcached object
type MemcachedReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
}
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/finalizers,verbs=update
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Memcached object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
//log := r.Log.WithValues("memcached", req.NamespacedName)
log := ctrllog.FromContext(ctx)
// Fetch the Memcached instance
memcached := &cachev1.Memcached{}
err := r.Get(ctx, req.NamespacedName, memcached)
if err != nil {
if errors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
log.Info("Memcached resource not found. Ignoring since object must be deleted")
return ctrl.Result{}, nil
}
// Error reading the object - requeue the request.
log.Error(err, "Failed to get Memcached")
return ctrl.Result{}, err
}
// Check if the deployment already exists, if not create a new one
found := &appsv1.Deployment{}
err = r.Get(ctx, types.NamespacedName{Name: memcached.Name, Namespace: memcached.Namespace}, found)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.deploymentForMemcached(memcached)
log.Info("Creating a new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
return ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return ctrl.Result{Requeue: true}, nil
} else if err != nil {
log.Error(err, "Failed to get Deployment")
return ctrl.Result{}, err
}
// Ensure the deployment size is the same as the spec
size := memcached.Spec.Size
if *found.Spec.Replicas != size {
found.Spec.Replicas = &size
err = r.Update(ctx, found)
if err != nil {
log.Error(err, "Failed to update Deployment", "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name)
return ctrl.Result{}, err
}
// Spec updated - return and requeue
return ctrl.Result{Requeue: true}, nil
}
// Update the Memcached status with the pod names
// List the pods for this memcached's deployment
podList := &corev1.PodList{}
listOpts := []client.ListOption{
client.InNamespace(memcached.Namespace),
client.MatchingLabels(labelsForMemcached(memcached.Name)),
}
if err = r.List(ctx, podList, listOpts...); err != nil {
log.Error(err, "Failed to list pods", "Memcached.Namespace", memcached.Namespace, "Memcached.Name", memcached.Name)
return ctrl.Result{}, err
}
podNames := getPodNames(podList.Items)
// Update status.Nodes if needed
if !reflect.DeepEqual(podNames, memcached.Status.Nodes) {
memcached.Status.Nodes = podNames
err := r.Status().Update(ctx, memcached)
if err != nil {
log.Error(err, "Failed to update Memcached status")
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}
// deploymentForMemcached returns a memcached Deployment object
func (r *MemcachedReconciler) deploymentForMemcached(m *cachev1.Memcached) *appsv1.Deployment {
ls := labelsForMemcached(m.Name)
replicas := m.Spec.Size
dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name,
Namespace: m.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: ls,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: ls,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: "memcached:1.4.36-alpine",
Name: "memcached",
Command: []string{"memcached", "-m=64", "-o", "modern", "-v"},
Ports: []corev1.ContainerPort{{
ContainerPort: 11211,
Name: "memcached",
}},
}},
},
},
},
}
// Set Memcached instance as the owner and controller
ctrl.SetControllerReference(m, dep, r.Scheme)
return dep
}
// labelsForMemcached returns the labels for selecting the resources
// belonging to the given memcached CR name.
func labelsForMemcached(name string) map[string]string {
return map[string]string{"app": "memcached", "memcached_cr": name}
}
// getPodNames returns the pod names of the array of pods passed in
func getPodNames(pods []corev1.Pod) []string {
var podNames []string
for _, pod := range pods {
podNames = append(podNames, pod.Name)
}
return podNames
}
// SetupWithManager sets up the controller with the Manager.
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&cachev1.Memcached{}).
Owns(&appsv1.Deployment{}).
Complete(r)
}
示例控制器为每个 `Memcached` 自定义资源 (CR) 运行以下协调逻辑:
如果 Memcached 部署不存在,则创建它。
确保部署大小与 `Memcached` CR规范中指定的大小相同。
使用 `memcached` Pod 的名称更新 `Memcached` CR 状态。
接下来的部分解释了示例实现中的控制器如何监视资源以及如何触发协调循环。您可以跳过这些部分,直接转到 运行 Operator。
`controllers/memcached_controller.go` 中的 `SetupWithManager()` 函数指定了如何构建控制器以监视 CR 和该控制器拥有和管理的其他资源。
import (
...
appsv1 "k8s.io/api/apps/v1"
...
)
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&cachev1.Memcached{}).
Owns(&appsv1.Deployment{}).
Complete(r)
}
`NewControllerManagedBy()` 提供了一个控制器构建器,允许各种控制器配置。
`For(&cachev1.Memcached{})` 将 `Memcached` 类型指定为要监视的主要资源。对于 `Memcached` 类型的每个添加、更新或删除事件,协调循环都会收到一个协调 `Request` 参数,该参数包含该 `Memcached` 对象的命名空间和名称键。
`Owns(&appsv1.Deployment{})` 将 `Deployment` 类型指定为要监视的次要资源。对于每个 `Deployment` 类型的添加、更新或删除事件,事件处理程序会将每个事件映射到对部署所有者的协调请求。在本例中,所有者是为其创建部署的 `Memcached` 对象。
您可以使用许多其他有用的配置来初始化控制器。例如:
使用 `MaxConcurrentReconciles` 选项设置控制器的最大并发协调次数,默认为 `1`。
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&cachev1.Memcached{}).
Owns(&appsv1.Deployment{}).
WithOptions(controller.Options{
MaxConcurrentReconciles: 2,
}).
Complete(r)
}
使用谓词过滤监视事件。
选择 EventHandler 的类型以更改监视事件如何转换为协调循环的协调请求。对于比主要资源和次要资源更复杂的 Operator 关系,您可以使用 `EnqueueRequestsFromMapFunc` 处理程序将监视事件转换为任意一组协调请求。
有关这些和其他配置的更多详细信息,请参阅上游 Builder 和 Controller GoDocs。
每个控制器都有一个带有 `Reconcile()` 方法的协调器对象,该方法实现了协调循环。协调循环传递 `Request` 参数,这是一个命名空间和名称键,用于从缓存中查找主要资源对象 `Memcached`。
import (
ctrl "sigs.k8s.io/controller-runtime"
cachev1 "github.com/example-inc/memcached-operator/api/v1"
...
)
func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// Lookup the Memcached instance for this reconcile request
memcached := &cachev1.Memcached{}
err := r.Get(ctx, req.NamespacedName, memcached)
...
}
根据返回值、结果和错误,请求可能会重新排队,并且协调循环可能会再次触发。
// Reconcile successful - don't requeue
return ctrl.Result{}, nil
// Reconcile failed due to error - requeue
return ctrl.Result{}, err
// Requeue for any reason other than an error
return ctrl.Result{Requeue: true}, nil
您也可以设置 `Result.RequeueAfter` 以在宽限期后重新排队请求。
import "time"
// Reconcile for any reason other than an error after 5 seconds
return ctrl.Result{RequeueAfter: time.Second*5}, nil
您可以返回设置了 `RequeueAfter` 的 `Result` 来定期协调 CR。 |
有关协调器、客户端以及与资源事件交互的更多信息,请参阅 Controller Runtime Client API 文档。
控制器需要某些 RBAC 权限才能与它管理的资源交互。这些权限使用 RBAC 标记指定,例如:
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/finalizers,verbs=update
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;
func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
...
}
`config/rbac/role.yaml` 中的 `ClusterRole` 对象清单是从之前的标记生成的,每次运行 `make manifests` 命令时都会使用 `controller-gen` 实用程序生成。
Operator 作者可以开发支持网络代理的 Operator。集群管理员为 Operator Lifecycle Manager (OLM) 处理的环境变量配置代理支持。要支持代理集群,您的 Operator 必须检查环境中是否存在以下标准代理变量,并将值传递给操作数:
HTTP_PROXY
HTTPS_PROXY
NO_PROXY
本教程使用 `HTTP_PROXY` 作为示例环境变量。 |
启用了集群范围出口代理的集群。
编辑 `controllers/memcached_controller.go` 文件以包含以下内容:
从 operator-lib
库导入 `proxy` 包。
import (
...
"github.com/operator-framework/operator-lib/proxy"
)
将 `proxy.ReadProxyVarsFromEnv` 辅助函数添加到协调循环中,并将结果附加到操作数环境。
for i, container := range dep.Spec.Template.Spec.Containers {
dep.Spec.Template.Spec.Containers[i].Env = append(container.Env, proxy.ReadProxyVarsFromEnv()...)
}
...
通过将以下内容添加到 `config/manager/manager.yaml` 文件中,在 Operator 部署中设置环境变量:
containers:
- args:
- --leader-elect
- --leader-election-id=ansible-proxy-demo
image: controller:latest
name: manager
env:
- name: "HTTP_PROXY"
value: "http_proxy_test"
您可以使用 Operator SDK CLI 以三种方式构建和运行您的 Operator:
作为 Go 程序在集群外部本地运行。
作为部署在集群上运行。
捆绑您的 Operator 并使用 Operator Lifecycle Manager (OLM) 部署到集群。
在将基于 Go 的 Operator 作为 OpenShift Container Platform 上的部署运行或作为使用 OLM 的捆绑包运行之前,请确保您的项目已更新为使用受支持的镜像。 |
您可以在集群外部将 Operator 项目作为 Go 程序运行。这对于开发目的很有用,可以加快部署和测试速度。
运行以下命令以在 `~/.kube/config` 文件中配置的集群中安装自定义资源定义 (CRD) 并本地运行 Operator:
$ make install run
...
2021-01-10T21:09:29.016-0700 INFO controller-runtime.metrics metrics server is starting to listen {"addr": ":8080"}
2021-01-10T21:09:29.017-0700 INFO setup starting manager
2021-01-10T21:09:29.017-0700 INFO controller-runtime.manager starting metrics server {"path": "/metrics"}
2021-01-10T21:09:29.018-0700 INFO controller-runtime.manager.controller.memcached Starting EventSource {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "source": "kind source: /, Kind="}
2021-01-10T21:09:29.218-0700 INFO controller-runtime.manager.controller.memcached Starting Controller {"reconciler group": "cache.example.com", "reconciler kind": "Memcached"}
2021-01-10T21:09:29.218-0700 INFO controller-runtime.manager.controller.memcached Starting workers {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "worker count": 1}
您可以在集群上将 Operator 项目作为部署运行。
通过更新项目以使用受支持的镜像,准备基于 Go 的 Operator 在 OpenShift Container Platform 上运行。
运行以下make
命令来构建和推送 Operator 镜像。修改以下步骤中的IMG
参数以引用您有访问权限的仓库。您可以在 Quay.io 等仓库站点获取用于存储容器的帐户。
构建镜像
$ make docker-build IMG=<registry>/<user>/<image_name>:<tag>
Operator SDK 为 Operator 生成的 Dockerfile 显式地引用了 |
将镜像推送到仓库
$ make docker-push IMG=<registry>/<user>/<image_name>:<tag>
镜像的名称和标签,例如 |
运行以下命令来部署 Operator
$ make deploy IMG=<registry>/<user>/<image_name>:<tag>
默认情况下,此命令创建一个名称为 Operator 项目名称的命名空间,格式为<project_name>-system
,并用于部署。此命令还安装来自config/rbac
的 RBAC 清单。
运行以下命令以验证 Operator 是否正在运行
$ oc get deployment -n <project_name>-system
NAME READY UP-TO-DATE AVAILABLE AGE
<project_name>-controller-manager 1/1 1 1 8m
Operator 包格式是 Operator SDK 和 Operator Lifecycle Manager (OLM) 的默认打包方法。您可以使用 Operator SDK 将您的 Operator 项目构建并推送为包镜像,使其准备好用于 OLM。
在开发工作站上安装了 Operator SDK CLI
安装了 OpenShift CLI (oc
) v4.17+
使用 Operator SDK 初始化了 Operator 项目
如果您的 Operator 基于 Go,则必须更新您的项目以使用受支持的镜像在 OpenShift Container Platform 上运行
在您的 Operator 项目目录中运行以下make
命令来构建和推送您的 Operator 镜像。修改以下步骤中的IMG
参数以引用您有访问权限的仓库。您可以在 Quay.io 等仓库站点获取用于存储容器的帐户。
构建镜像
$ make docker-build IMG=<registry>/<user>/<operator_image_name>:<tag>
Operator SDK 为 Operator 生成的 Dockerfile 显式地引用了 |
将镜像推送到仓库
$ make docker-push IMG=<registry>/<user>/<operator_image_name>:<tag>
通过运行make bundle
命令创建您的 Operator 包清单,该命令将调用多个命令,包括 Operator SDK 的generate bundle
和bundle validate
子命令
$ make bundle IMG=<registry>/<user>/<operator_image_name>:<tag>
Operator 的包清单描述了如何显示、创建和管理应用程序。make bundle
命令会在您的 Operator 项目中创建以下文件和目录
一个名为bundle/manifests
的包清单目录,其中包含一个ClusterServiceVersion
对象
一个名为bundle/metadata
的包元数据目录
config/crd
目录中的所有自定义资源定义 (CRD)
一个 Dockerfile bundle.Dockerfile
然后,这些文件将使用operator-sdk bundle validate
自动验证,以确保磁盘上的包表示正确。
通过运行以下命令来构建和推送您的包镜像。OLM 使用索引镜像来使用 Operator 包,该索引镜像引用一个或多个包镜像。
构建包镜像。使用注册表、用户命名空间和镜像标签的详细信息设置BUNDLE_IMG
,您打算将镜像推送到这些位置
$ make bundle-build BUNDLE_IMG=<registry>/<user>/<bundle_image_name>:<tag>
推送包镜像
$ docker push <registry>/<user>/<bundle_image_name>:<tag>
Operator Lifecycle Manager (OLM) 帮助您在 Kubernetes 集群上安装、更新和管理 Operator 及其关联服务的生命周期。OLM 在 OpenShift Container Platform 上默认安装,并作为 Kubernetes 扩展运行,因此您可以使用 Web 控制台和 OpenShift CLI (oc
) 执行所有 Operator 生命周期管理功能,无需任何其他工具。
Operator 包格式是 Operator SDK 和 OLM 的默认打包方法。您可以使用 Operator SDK 快速在 OLM 上运行包镜像,以确保其正常运行。
在开发工作站上安装了 Operator SDK CLI
已构建并推送到注册表的 Operator 包镜像
在基于 Kubernetes 的集群上安装了 OLM(如果使用apiextensions.k8s.io/v1
CRD,则为 v1.16.0 或更高版本,例如 OpenShift Container Platform 4.17)
使用具有cluster-admin
权限的帐户使用oc
登录到集群
如果您的 Operator 基于 Go,则必须更新您的项目以使用受支持的镜像在 OpenShift Container Platform 上运行
输入以下命令在集群上运行 Operator
$ operator-sdk run bundle \(1)
-n <namespace> \(2)
<registry>/<user>/<bundle_image_name>:<tag> (3)
1 | run bundle 命令创建一个有效的基于文件的目录,并使用 OLM 在您的集群上安装 Operator 包。 |
2 | 可选:默认情况下,该命令将 Operator 安装在您~/.kube/config 文件中的当前活动项目中。您可以添加-n 标志来设置安装的不同命名空间范围。 |
3 | 如果您没有指定镜像,则该命令使用quay.io/operator-framework/opm:latest 作为默认索引镜像。如果您指定了镜像,则该命令将使用包镜像本身作为索引镜像。 |
从 OpenShift Container Platform 4.11 开始, |
此命令执行以下操作
创建一个引用您的包镜像的索引镜像。索引镜像是不透明且短暂的,但准确地反映了在生产环境中如何将包添加到目录。
创建一个指向您的新索引镜像的目录源,这使 OperatorHub 能够发现您的 Operator。
通过创建OperatorGroup
、Subscription
、InstallPlan
和所有其他必需的资源(包括 RBAC)将您的 Operator 部署到您的集群。
安装 Operator 后,您可以通过创建自定义资源 (CR) 来测试它,该资源现在由 Operator 在集群上提供。
示例 Memcached Operator,它提供在集群上安装的Memcached
CR。
更改到安装 Operator 的命名空间。例如,如果您使用make deploy
命令部署了 Operator
$ oc project memcached-operator-system
编辑config/samples/cache_v1_memcached.yaml
处的示例Memcached
CR 清单,使其包含以下规范
apiVersion: cache.example.com/v1
kind: Memcached
metadata:
name: memcached-sample
...
spec:
...
size: 3
创建 CR
$ oc apply -f config/samples/cache_v1_memcached.yaml
确保Memcached
Operator 使用正确的规模为示例 CR 创建部署。
$ oc get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
memcached-operator-controller-manager 1/1 1 1 8m
memcached-sample 3/3 3 3 1m
检查 Pod 和 CR 状态以确认状态已更新为 Memcached Pod 名称。
检查 Pod
$ oc get pods
NAME READY STATUS RESTARTS AGE
memcached-sample-6fd7c98d8-7dqdr 1/1 Running 0 1m
memcached-sample-6fd7c98d8-g5k7v 1/1 Running 0 1m
memcached-sample-6fd7c98d8-m7vn7 1/1 Running 0 1m
检查 CR 状态
$ oc get memcached/memcached-sample -o yaml
apiVersion: cache.example.com/v1
kind: Memcached
metadata:
...
name: memcached-sample
...
spec:
size: 3
status:
nodes:
- memcached-sample-6fd7c98d8-7dqdr
- memcached-sample-6fd7c98d8-g5k7v
- memcached-sample-6fd7c98d8-m7vn7
更新部署规模。
更新config/samples/cache_v1_memcached.yaml
文件,将Memcached
CR 中的spec.size
字段从3
更改为5
$ oc patch memcached memcached-sample \
-p '{"spec":{"size": 5}}' \
--type=merge
确认 Operator 更改了部署规模
$ oc get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
memcached-operator-controller-manager 1/1 1 1 10m
memcached-sample 5/5 5 5 3m
运行以下命令删除 CR
$ oc delete -f config/samples/cache_v1_memcached.yaml
清理本教程中创建的资源。
如果您使用make deploy
命令测试了 Operator,请运行以下命令
$ make undeploy
如果您使用operator-sdk run bundle
命令测试了 Operator,请运行以下命令
$ operator-sdk cleanup <project_name>
请参阅基于 Go 的 Operator 的项目布局,了解 Operator SDK 创建的目录结构。
如果配置了集群范围的出口代理,集群管理员可以覆盖代理设置或为在 Operator Lifecycle Manager (OLM) 上运行的特定 Operator 注入自定义 CA 证书。