Kubernetes(1) - operator 初体验

本章参考operator-sdk的tutorial编写一个memcache的operator

1 功能介绍

memcache operator创建成功后,可以通过如下yaml来创建进一个memcache 服务

apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
  name: memcached-sample
spec:
  size: 3

根据yaml创建memcached

kubectl create -f memcached.yaml

创建成功后,可以通过kubectl 查看memcached的状态信息

# 查看是否存在对应资源信息
tingshuai.yts@B-5BBCMD6M-2026 ~ % kubectl get memcached
NAME               AGE
memcached-sample   34m

# 查看memcached详细信息
tingshuai.yts@B-5BBCMD6M-2026 ~ % kubectl get memcached memcached-sample -o yaml
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
  creationTimestamp: "2022-02-24T07:16:33Z"
  generation: 2
  name: memcached-sample
  namespace: default
  resourceVersion: "3385066472"
  selfLink: /apis/cache.example.com/v1alpha1/namespaces/default/memcacheds/memcached-sample
  uid: 12f26a9f-fc34-492e-a30f-bc17266052aa
spec:
  size: 4
status:
  nodes:
  - memcached-sample-9b765dfc8-w6l26
  - memcached-sample-9b765dfc8-7cwpl
  - memcached-sample-9b765dfc8-kxnmd
  - memcached-sample-9b765dfc8-hsrqd

memcached operator主要工作是根据yaml中的描述spec来创建deployment,如下所示:

tingshuai.yts@B-5BBCMD6M-2026 ~ % kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
memcached-sample   4/4     4            4           37m

2 整体流程

编写一个operator一般分为如下几个步骤:

  • 开发环境搭建
  • 通过operator sdk创建operator project
  • 通过operator sdk创建API和controller 框架代码
  • 编写API和controller业务代码
  • 调试执行

3 环境搭建

开发controller依赖如下环境,由于篇幅有限,本文仅列举依赖的内容,安装方式读者自行百度即可

  • golang
  • operator-sdk
  • kubectl 和k8s对应的config

4 创建operator project

通过operator-sdk init命令创建controller的project

mkdir -p $HOME/projects/memcached-operator
cd $HOME/projects/memcached-operator

# we'll use a domain of example.com
# so all API groups will be <group>.example.com
operator-sdk init --domain example.com --repo github.com/example/memcached-operator

operator-sdk init的帮助文档信息如下:

% operator-sdk init --help
Initialize a new project including the following files:
  - a "go.mod" with project dependencies
  - a "PROJECT" file that stores project configuration
  - a "Makefile" with several useful make targets for the project
  - several YAML files for project deployment under the "config" directory
  - a "main.go" file that creates the manager that will run the project controllers

Usage:
  operator-sdk init [flags]

Examples:
  # Initialize a new project with your domain and name in copyright
  operator-sdk init --plugins go/v3 --domain example.org --owner "Your name"

  # Initialize a new project defining an specific project version
  operator-sdk init --plugins go/v3 --project-version 3


Flags:
      --component-config         create a versioned ComponentConfig file, may be 'true' or 'false'
      --domain string            domain for groups (default "my.domain")
      --fetch-deps               ensure dependencies are downloaded (default true)
  -h, --help                     help for init
      --license string           license to use to boilerplate, may be one of 'apache2', 'none' (default "apache2")
      --owner string             owner to add to the copyright
      --project-name string      name of this project
      --project-version string   project version (default "3")
      --repo string              name to use for go module (e.g., github.com/user/repo), defaults to the go package of the current working directory.
      --skip-go-version-check    if specified, skip checking the Go version

Global Flags:
      --plugins strings   plugin keys to be used for this subcommand execution
      --verbose           Enable verbose logging

5 创建API和controller框架代码

执行下面的命令会创建api和controller的框架代码,然后我们在框架代码的基础上按照需求填写业务逻辑代码即可:

  • api代码会在api/v1alpha1/memcached_types.go
  • controller代码会在controllers/memcached_controller.go
$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controller

6 编写API

6.1 api 定义

创建完api后代码,operator sdk生成的主要代码如下:

// MemcachedSpec defines the desired state of Memcached
type MemcachedSpec struct {
        // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
        // Important: Run "make" to regenerate code after modifying this file

        // Foo is an example field of Memcached. Edit memcached_types.go to remove/update
        Foo string `json:"foo,omitempty"`
}

// MemcachedStatus defines the observed state of Memcached
type MemcachedStatus struct {
        // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
        // Important: Run "make" to regenerate code after modifying this file
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// Memcached is the Schema for the memcacheds API
type Memcached struct {
        metav1.TypeMeta   `json:",inline"`
        metav1.ObjectMeta `json:"metadata,omitempty"`

        Spec   MemcachedSpec   `json:"spec,omitempty"`
        Status MemcachedStatus `json:"status,omitempty"`
}

一般来说,我们需要修改spec和status的定义,来满足我们的业务需求。

spec更改如下:

  • 添加Size字段,用来定义memcache 副本的个数
  • +kubebuilder:validation:Minimum=0 是marker comments;operator-sdk会根据marker comments的描述来生成代码。本例中marker comments的作用是生成api定义的校验代码,如果spec的小于0,则validation检查会失败(下一节会对marker comments进一步介绍)
// 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"`
}

status定义如下:

  • status仅有一个Nodes的切片字段,用来存储memcached 对应的所有pod 名称
  • controller负责对status字段进行更改
// MemcachedStatus defines the observed state of Memcached
type MemcachedStatus struct {
	// Nodes are the names of the memcached pods
	Nodes []string `json:"nodes"`
}

6.2 marker comments

在编写operator时,可以使用controller-gen来帮助我们生成golang代码和yaml文件。生成的规则是通过maker comments来描述的。

maker comments格式描述为:

Markers are single-line comments that start with a plus, followed by a marker name, optionally followed by some marker specific configuration

一般来说maker comments可以分为三类:

  • empty类型: 是boolen类型的flag,表示是否开启某项沟通能力
// +kubebuilder:validation:Optional

  • Anonymous类型:接受单值类型的参数
// +kubebuilder:validation:MaxItems=2

  • Multi-option类型:接受多个参数,并通过逗号隔开
// +kubebuilder:printcolumn:JSONPath=".status.replicas",name=Replicas,type=string

参考:

6.3 controller-gen

controller-gen在operator sdk创建project的bin目录下。使用方式如下所示:

tingshuai.yts@B-5BBCMD6M-2026 memcached-operator % ./bin/controller-gen -hhh           
Usage:
  controller-gen [flags]

Examples:
        # Generate RBAC manifests and crds for all types under apis/,
        # outputting crds to /tmp/crds and everything else to stdout
        controller-gen rbac:roleName=<role name> crd paths=./apis/... output:crd:dir=/tmp/crds output:stdout

        # Generate deepcopy/runtime.Object implementations for a particular file
        controller-gen object paths=./apis/v1beta1/some_types.go

        # Generate OpenAPI v3 schemas for API packages and merge them into existing CRD manifests
        controller-gen schemapatch:manifests=./manifests output:dir=./manifests paths=./pkg/apis/... 

        # Run all the generators for a given project
        controller-gen paths=./apis/...

        # Explain the markers for generating CRDs, and their arguments
        controller-gen crd -ww


Flags:
  -h, --detailed-help count   print out more detailed help
                              (up to -hhh for the most detailed output, or -hhhh for json output)
      --help                  print out usage and a summary of options
      --version               show version
  -w, --which-markers count   print out all markers available with the requested generators
                              (up to -www for the most detailed output, or -wwww for json output)


Options


generators


+webhook package
        generates (partial) {Mutating,Validating}WebhookConfiguration objects.

+schemapatch package
        patches existing CRDs with new schemata. 
        It will generate output for each "CRD Version" (API version of the CRD type itself) , e.g. apiextensions/v1) available.

        [generateEmbeddedObjectMeta=<bool>]
                specifies if any embedded ObjectMeta in the CRD should be generated
        manifests=<string>
                contains the CustomResourceDefinition YAML files.
        [maxDescLen=<int>]
                specifies the maximum description length for fields in CRD's OpenAPI schema. 
                0 indicates drop the description for all fields completely. n indicates limit the description to at most n characters and truncate the description to closest sentence boundary if it exceeds n characters.


+rbac package
        generates ClusterRole objects.

        roleName=<string>
                sets the name of the generated ClusterRole.

+object package
        generates code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.

        [headerFile=<string>]
                specifies the header text (e.g. license) to prepend to generated files.
        [year=<string>]
                specifies the year to substitute for " YEAR" in the header file.

+crd package
        generates CustomResourceDefinition objects.

        [allowDangerousTypes=<bool>]
                allows types which are usually omitted from CRD generation because they are not recommended. 
                Currently the following additional types are allowed when this is true: float32 float64 
                 Left unspecified, the default is false

        [crdVersions=<[]string>]
                specifies the target API versions of the CRD type itself to generate. Defaults to v1. 
                Currently, the only supported value is v1. 
                 The first version listed will be assumed to be the "default" version and will not get a version suffix in the output filename. 
                 You'll need to use "v1" to get support for features like defaulting, along with an API server that supports it (Kubernetes 1.16+).

        [generateEmbeddedObjectMeta=<bool>]
                specifies if any embedded ObjectMeta in the CRD should be generated
        [maxDescLen=<int>]
                specifies the maximum description length for fields in CRD's OpenAPI schema. 
                0 indicates drop the description for all fields completely. n indicates limit the description to at most n characters and truncate the description to closest sentence boundary if it exceeds n characters.


generic


+paths package
        =<[]string>  represents paths and go-style path patterns to use as package roots.

output rules (optionally as output:<generator>:...)


+output:artifacts package
        outputs artifacts to different locations, depending on whether they're package-associated or not. 
        Non-package associated artifacts are output to the Config directory, while package-associated ones are output to their package's source files' directory, unless an alternate path is specified in Code.

        [code=<string>]
                overrides the directory in which to write new code (defaults to where the existing code lives).
        config=<string>
                points to the directory to which to write configuration.

+output:dir package
        =<string>  outputs each artifact to the given directory, regardless of if it's package-associated or not.

+output:none package
        skips outputting anything.

+output:stdout package
        outputs everything to standard-out, with no separation. 
        Generally useful for single-artifact outputs.

operator sdk在创建工程时,已经为我们创建了make file文件,因此,我们使用make 命令即可以根据memcached type的定义来创建代码。

tingshuai.yts@B-5BBCMD6M-2026 memcached-operator % make generate
/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..." # 真实执行的命令

命令分析

  • paths描述resource type定义的位置。"./..." 是查看当前目录和所有子目录的含义。
  • object描述生成的代码中包含DeepCopy, DeepCopyInto, and DeepCopyObject method 的实现

执行完上述命令后,会在api/v1alpha1下面生成zz_generated.deepcopy.go 代码,代码内容如下所示:

//go:build !ignore_autogenerated
// +build !ignore_autogenerated

/*
Copyright 2022.

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

    http://www.apache.org/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.
*/

// Code generated by controller-gen. DO NOT EDIT.

package v1alpha1

import (
	runtime "k8s.io/apimachinery/pkg/runtime"
)

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Memcached) DeepCopyInto(out *Memcached) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
	out.Spec = in.Spec
	in.Status.DeepCopyInto(&out.Status)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Memcached.
func (in *Memcached) DeepCopy() *Memcached {
	if in == nil {
		return nil
	}
	out := new(Memcached)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Memcached) DeepCopyObject() runtime.Object {
	if c := in.DeepCopy(); c != nil {
		return c
	}
	return nil
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MemcachedList) DeepCopyInto(out *MemcachedList) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ListMeta.DeepCopyInto(&out.ListMeta)
	if in.Items != nil {
		in, out := &in.Items, &out.Items
		*out = make([]Memcached, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemcachedList.
func (in *MemcachedList) DeepCopy() *MemcachedList {
	if in == nil {
		return nil
	}
	out := new(MemcachedList)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MemcachedList) DeepCopyObject() runtime.Object {
	if c := in.DeepCopy(); c != nil {
		return c
	}
	return nil
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MemcachedSpec) DeepCopyInto(out *MemcachedSpec) {
	*out = *in
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemcachedSpec.
func (in *MemcachedSpec) DeepCopy() *MemcachedSpec {
	if in == nil {
		return nil
	}
	out := new(MemcachedSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MemcachedStatus) DeepCopyInto(out *MemcachedStatus) {
	*out = *in
	if in.Nodes != nil {
		in, out := &in.Nodes, &out.Nodes
		*out = make([]string, len(*in))
		copy(*out, *in)
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemcachedStatus.
func (in *MemcachedStatus) DeepCopy() *MemcachedStatus {
	if in == nil {
		return nil
	}
	out := new(MemcachedStatus)
	in.DeepCopyInto(out)
	return out
}

再次执行make manifests来生成api定义对应的yaml文件

tingshuai.yts@B-5BBCMD6M-2026 memcached-operator % make manifests
./bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

会生成config/crd/bases/cache.example.com_memcacheds.yaml文件,文件中描述了crd的定义。文件内容如下:

---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.7.0
  creationTimestamp: null
  name: memcacheds.cache.example.com
spec:
  group: cache.example.com
  names:
    kind: Memcached
    listKind: MemcachedList
    plural: memcacheds
    singular: memcached
  scope: Namespaced
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: Memcached is the Schema for the memcacheds API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: MemcachedSpec defines the desired state of Memcached
            properties:
              size:
                description: Size is the size of the memcached deployment
                format: int32
                minimum: 0
                type: integer
            required:
            - size
            type: object
          status:
            description: MemcachedStatus defines the observed state of Memcached
            properties:
              nodes:
                description: Nodes are the names of the memcached pods
                items:
                  type: string
                type: array
            required:
            - nodes
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []

7 编写controller业务代码

7.1 controller框架代码解析

框架生成的controller代码位于controllers/memcached_controller.go ,初始内容如下:

package controllers

import (
        "context"

        "k8s.io/apimachinery/pkg/runtime"
        ctrl "sigs.k8s.io/controller-runtime"
        "sigs.k8s.io/controller-runtime/pkg/client"
        "sigs.k8s.io/controller-runtime/pkg/log"

        cachev1alpha1 "github.com/example/memcached-operator/api/v1alpha1"
)

// MemcachedReconciler reconciles a Memcached object
type MemcachedReconciler struct {
        client.Client
        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

// 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/controller-runtime@v0.10.0/pkg/reconcile
func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
        _ = log.FromContext(ctx)

        // your logic here

        return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
                For(&cachev1alpha1.Memcached{}).
                Complete(r)
}

框架代码中首先定义了MemcachedReconciler类型

  • client.Client为interface,定义了kubernetes object的CURD相关操作
  • runtime.Scheme 定义了序列化和反序列化api object的method
type MemcachedReconciler struct {
        client.Client
        Scheme *runtime.Scheme
}

框架代码中通过mark comment定义了operator对memcached的权限信息

  • 当前operator对memcacheds具有get;list;watch;create;update;patch;delete权限
  • 当前operator对memcacheds/status具有get;update;patch权限
  • 当前operator对memcacheds/finalizers具有update权限
//+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

框架代码为MemcachedReconciler生成了Reconcile function,该function是controller的主体

  • Reconcile的作用是保证memcached的status同spec中描述的保持一致;
  • 每当有memcached operator监控的resource发生变更时,Reconcile function就会被调用;
  • 参数含义:
    • context.Context: A Context carries a deadline, a cancellation signal, and other values across API boundaries;
    • ctrl.Request: 包含出发Reconcile的kubernetes object的name和namespace
func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
        _ = log.FromContext(ctx)

        // your logic here

        return ctrl.Result{}, nil
}

框架代码生成的SetUpWithManager function用来说明当前operator watch哪些resource:

  • NewControllerManagedBy()创建一个configuration,用来配置当前manager
  • For(&cachev1alpha1.Memcached{}) 设置operator 监听 Memcached的变更,所有Memcached的Add/Delete/Update都会
// SetupWithManager sets up the controller with the Manager.
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
    For(&cachev1alpha1.Memcached{}).
    Complete(r)
}

7.2 权限编写

根据memcached operator的业务逻辑,需要添加deployment和pod的操作权限

//+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;watch

7.3 Reconcile Loop编写

reconcile loop中主要为如下流程:

  • 获取event相关的memcached object;
  • 判断memcached相关联的deployment是否存在;若不存在则执行deployment的create
  • 判断deployment的size同memcached中spec的size是否相同,如果不同则执行deployment的update
  • 判断memcached的status字段pod内容是否符合预期,如果不符合预期则更新status字段内容

完整代码见:https://github.com/operator-framework/operator-sdk/blob/latest/testdata/go/v3/memcached-operator/controllers/memcached_controller.go

7.3.1 获取memcached object

通过req.NamespacedName来找到对应的memcached

	memcached := &cachev1alpha1.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
	}

7.3.2 判断deployment 存在性

通过memcache的name和namespace查找对应的deployment;若找不到则调用自定义的deploymentForMemcached来创建deployment

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
	}

7.3.3 判断memcached size

若size与spec中的不一致,则调用自定义的update接口进行更新

	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
		}
		// Ask to requeue after 1 minute in order to give enough time for the
		// pods be created on the cluster side and the operand be able
		// to do the next update step accurately.
		return ctrl.Result{RequeueAfter: time.Minute}, nil
	}

7.3.4 判断memcached status

memcached的status字段描述了pod的name信息,因此每个loop都要判断status字段是否要更新:

  • 首先获取podlist,然后同memcached中记录的进行比较
  • 如果不同则更新status
	// 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
		}
	}

8 编译调试

调试operator一般有两种方式

  • in cluster:将operator发布到k8s集群中
  • out cluster:在k8s 环境外部启动一个golang的operator进程;本文采用这种方式

operator sdk中通过out cluster的方式的命令为make install run:

  • 首先、调用controller-gen创建rbac 、crd 、webhook的代码和yaml (注:这一步是冗余操作,其实可以不执行)
  • 然后、调用kustomize将crd创建
  • 最后、执行main.go
 memcached-operator % make install run
bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created
bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go run ./main.go
2022-02-24T15:13:19.997+0800    INFO    controller-runtime.metrics      metrics server is starting to listen    {"addr": ":8080"}
2022-02-24T15:13:19.997+0800    INFO    setup   starting manager
2022-02-24T15:13:19.998+0800    INFO    starting metrics server {"path": "/metrics"}
2022-02-24T15:13:19.998+0800    INFO    controller.memcached    Starting EventSource    {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "source": "kind source: /, Kind="}
2022-02-24T15:13:19.998+0800    INFO    controller.memcached    Starting Controller     {"reconciler group": "cache.example.com", "reconciler kind": "Memcached"}
2022-02-24T15:13:20.098+0800    INFO    controller.memcached    Starting workers        {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "worker count": 1}
2022-02-24T15:16:33.317+0800    INFO    controller.memcached    Creating a new Deployment       {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "name": "memcached-sample", "namespace": "default", "Deployment.Namespace": "default", "Deployment.Name": "memcached-sample"}

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论
k8s学习 介绍 序⾔ 课程介绍 Docker 基础 Docker 简介 镜像和容器的基本操作 Dockerfile 定制镜像 私有镜像仓库 数据共享与持久化 Docker 的⽹络模式 Docker 三架⻢⻋ Docker Compose Docker Machine Docker Swarm Docker 实践 图形化管理和监控 Docker 的多阶段构建 Dockerfile 最佳实践 Kubernetes 基础 Kubernetes 初体验 基本概念与组件 kubeadm 搭建集群 使⽤ kubeadm 搭建集群环境 安装 Dashboard 插件 17.1 7.2 7.3 7.4 7.5 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 8.10 9.1 9.2 9.3 10.1 10.2 10.3 11.1 11.2 11.3 深⼊理解 Pod YAML ⽂件 静态 Pod Pod Hook Pod 的健康检查 初始化容器 常⽤对象操作: Replication Controller 与 Replica Set Deployment HPA Job/CronJob Service ConfigMap Secret RBAC 部署Wordpress示例 DaemonSet 和 StatefulSet 持久化存储: PV PVC StorageClass 服务发现 kubedns ingress 安装配置 ingress tls 和 path 的使⽤ 包管理⼯具 Helm Helm 的安装使⽤ Helm 的基本使⽤ Helm 模板之内置函数和Values 211.4 11.5 11.6 11.7 11.8 12.1 12.2 13.1 13.2 13.3 13.4 13.5 13.6 13.7 13.8 13.9 14.1 14.2 15.1 15.2 15.3 15.4 15.5 15.6 15.7 Helm 模板之模板函数与管道 Helm 模板之控制流程 Helm 模板之命名模板 Helm 模板之其他注意事项 Helm Hooks 调度器 Kubernetes 调度器介绍 Kubernetes 亲和性调度 集群监控 ⼿动安装 Prometheus 监控 Kubernetes 集群应⽤ 监控 Kubernetes 集群节点 监控 Kubernetes 常⽤资源对象 Grafana 的安装使⽤ AlertManager 的使⽤ Prometheus Operator 的安装 ⾃定义Prometheus Operator 监控项 Prometheus Operator⾼级配置 ⽇志收集 ⽇志收集架构 搭建 EFK ⽇志系统 CI/CD: 动态 Jenkins Slave Jenkins Pipeline 部署 Kubernetes 应⽤ Jenkins BlueOcean Harbor Gitlab Gitlab CI Devops

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

颜挺帅

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值