关于operator-sdk怎么安装,请参考官方文档:https://sdk.operatorframework.io/docs/installation/install-operator-sdk/

1. 创建operator新项目

1)初始化项目,注意,一定要初始化go mod,否则operator-sdk无法识别项目依赖,且以下命令均在空文件夹hello-world-operator下执行:

2)创建api和控制器,创建HelloWorldManager的自定义资源类型:

以上命令执行成功后,可观察到项目目录中创建出了api/v1和controllers文件夹,后面我们的开发主要基于这两个文件夹中的go文件:

2. 定义crd数据结构

1)在xxx_types中定义HelloWorldManager的数据结构,需要什么定义什么即可:

代码如下:

package v1import (appsv1 "k8s.io/api/apps/v1"corev1 "k8s.io/api/core/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.// HelloWorldManagerSpec defines the desired state of HelloWorldManager
type HelloWorldManagerSpec struct {// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster// Important: Run "make" to regenerate code after modifying this fileSize      *int32                      `json:"size"`Image     string                      `json:"image"`Resources corev1.ResourceRequirements `json:"resources,omitempty"`Envs      []corev1.EnvVar             `json:"envs,omitempty"`Ports     []corev1.ServicePort        `json:"ports,omitempty"`
}// HelloWorldManagerStatus defines the observed state of HelloWorldManager
type HelloWorldManagerStatus struct {// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster// Important: Run "make" to regenerate code after modifying this fileappsv1.DeploymentStatus `json:",inline"`
}// +kubebuilder:object:root=true
// +kubebuilder:subresource:status// HelloWorldManager is the Schema for the helloworldmanagers API
type HelloWorldManager struct {metav1.TypeMeta   `json:",inline"`metav1.ObjectMeta `json:"metadata,omitempty"`Spec   HelloWorldManagerSpec   `json:"spec,omitempty"`Status HelloWorldManagerStatus `json:"status,omitempty"`
}// +kubebuilder:object:root=true// HelloWorldManagerList contains a list of HelloWorldManager
type HelloWorldManagerList struct {metav1.TypeMeta `json:",inline"`metav1.ListMeta `json:"metadata,omitempty"`Items           []HelloWorldManager `json:"items"`
}func init() {SchemeBuilder.Register(&HelloWorldManager{}, &HelloWorldManagerList{})
}

2)定义完成后,执行make generate,该命令为更新api/v1/xxxdeepcopy.go文件,sdk会自动帮助我们生成实现了runtime.Object接口的代码。

3)执行make manifests生成crd清单,该清单用于在k8s集群中注册我们的自定义资源类型:

3. 编写controller,完成自己的业务逻辑

我们所有的业务逻辑在controllers下的xxx_controller.go下的Reconcile方法完成即可,该方法可以监听资源状态的变化。

下面代码的主要逻辑为判断资源是否存在,不存在则创建,存在则更新为最新的(并没有真正更新,而是输出了一段话,伙伴们可以填充自己的逻辑):

package controllersimport ("context""encoding/json""fmt""github.com/go-logr/logr"appsv1 "k8s.io/api/apps/v1"corev1 "k8s.io/api/core/v1"v1 "k8s.io/api/rbac/v1""k8s.io/apimachinery/pkg/api/errors"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/runtime""k8s.io/apimachinery/pkg/runtime/schema""reflect"ctrl "sigs.k8s.io/controller-runtime""sigs.k8s.io/controller-runtime/pkg/client"csdnv1 "csdn.net/api/v1"
)// HelloWorldManagerReconciler reconciles a HelloWorldManager object
type HelloWorldManagerReconciler struct {client.ClientLog    logr.LoggerScheme *runtime.Scheme
}// +kubebuilder:rbac:groups=csdn.csdn.net,resources=helloworldmanagers,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=csdn.csdn.net,resources=helloworldmanagers/status,verbs=get;update;patchfunc (r *HelloWorldManagerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {_ = context.Background()_ = r.Log.WithValues("helloworldmanager", req.NamespacedName)// your logic herehelloWorldManagerInstance := &csdnv1.HelloWorldManager{}err := r.Client.Get(context.TODO(), req.NamespacedName, helloWorldManagerInstance)r.Log.WithValues("k8s client error:", err)if err != nil {if errors.IsNotFound(err) {return ctrl.Result{}, nil}return ctrl.Result{}, err}if helloWorldManagerInstance.DeletionTimestamp != nil {return ctrl.Result{}, err}deployment := &appsv1.Deployment{}if err := r.Client.Get(context.TODO(), req.NamespacedName, deployment); err != nil && errors.IsNotFound(err) {// 创建关联资源// 1. 创建 Deploydeploy := NewDeploy(helloWorldManagerInstance)if err := r.Client.Create(context.TODO(), deploy); err != nil {return ctrl.Result{}, err}// 2. 创建 Serviceservice := NewService(helloWorldManagerInstance)if err := r.Client.Create(context.TODO(), service); err != nil {return ctrl.Result{}, err}// 3. 关联 Annotationsdata, _ := json.Marshal(helloWorldManagerInstance.Spec)if helloWorldManagerInstance.Annotations != nil {helloWorldManagerInstance.Annotations["spec"] = string(data)} else {helloWorldManagerInstance.Annotations = map[string]string{"spec": string(data)}}if err := r.Client.Update(context.TODO(), helloWorldManagerInstance); err != nil {return ctrl.Result{}, nil}return ctrl.Result{}, nil}oldspec := &csdnv1.HelloWorldManagerSpec{}fmt.Printf("-----%v----\n", helloWorldManagerInstance.Annotations["spec"])if err := json.Unmarshal([]byte(helloWorldManagerInstance.Annotations["spec"]), oldspec); err != nil {return ctrl.Result{}, err}fmt.Printf("-----副本数量:%v----\n", *helloWorldManagerInstance.Spec.Size)if !reflect.DeepEqual(helloWorldManagerInstance.Spec, oldspec) {// 更新关联资源,update deployment和service,TODOfmt.Printf("-----%v----\n", "更新资源")return ctrl.Result{}, nil}return ctrl.Result{}, nil
}func (r *HelloWorldManagerReconciler) SetupWithManager(mgr ctrl.Manager) error {return ctrl.NewControllerManagedBy(mgr).For(&csdnv1.HelloWorldManager{}).Complete(r)
}func NewDeploy(app *csdnv1.HelloWorldManager) *appsv1.Deployment {labels := map[string]string{"app": app.Name}selector := &metav1.LabelSelector{MatchLabels: labels}return &appsv1.Deployment{TypeMeta: metav1.TypeMeta{APIVersion: "apps/v1",Kind:       "Deployment",},ObjectMeta: metav1.ObjectMeta{Name:      app.Name,Namespace: app.Namespace,OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(app, schema.GroupVersionKind{Group:   v1.SchemeGroupVersion.Group,Version: v1.SchemeGroupVersion.Version,Kind:    "HelloWorldManager",}),},},Spec: appsv1.DeploymentSpec{Replicas: app.Spec.Size,Template: corev1.PodTemplateSpec{ObjectMeta: metav1.ObjectMeta{Labels: labels,},Spec: corev1.PodSpec{Containers: newContainers(app),},},Selector: selector,},}
}func newContainers(app *csdnv1.HelloWorldManager) []corev1.Container {containerPorts := []corev1.ContainerPort{}for _, svcPort := range app.Spec.Ports {cport := corev1.ContainerPort{}cport.ContainerPort = svcPort.TargetPort.IntValcontainerPorts = append(containerPorts, cport)}return []corev1.Container{{Name:            app.Name,Image:           app.Spec.Image,Resources:       app.Spec.Resources,Ports:           containerPorts,ImagePullPolicy: corev1.PullIfNotPresent,Env:             app.Spec.Envs,},}
}func NewService(app *csdnv1.HelloWorldManager) *corev1.Service {return &corev1.Service{TypeMeta: metav1.TypeMeta{Kind:       "Service",APIVersion: "v1",},ObjectMeta: metav1.ObjectMeta{Name:      app.Name,Namespace: app.Namespace,OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(app, schema.GroupVersionKind{Group:   v1.SchemeGroupVersion.Group,Version: v1.SchemeGroupVersion.Version,Kind:    "HelloWorldManager",}),},},Spec: corev1.ServiceSpec{Type:  corev1.ServiceTypeNodePort,Ports: app.Spec.Ports,Selector: map[string]string{"app": app.Name,},},}
}

4. 本地调试

1)注册自定义资源,在2.3中我们生成了资源清单,该资源清单位于config/crd/bases/xxx.yaml,我们只需在k8s中创建该资源即可:

2)在编辑器中运行我们的operator:

3)接下来我们创建自定义资源并观察operator是否完成了我们的业务逻辑,编写自定义资源yaml,符合上面我们自己定义的数据结构即可,如下示例:

创建并查看自定义资源,发现operator成功帮我们将服务自动跑了起来:

同时我们也看到operator成功监听到了本次资源创建操作:

浏览器访问node公网ip+端口验证:

我们也可以更改下自定义资源的副本数量,查看operator是否监听到资源的变化:

operator成功监听到了资源的变化:

5. 部署

1)编译并推送镜像:


也可以使用operator官方已经写好的脚本命令,其实质上也是调用了docker:

make docker-build docker-push IMG=<some-registry>/<project-name>:<tag>

查看镜像推送成功:

2)为k8s安装crd资源

3)部署operator

4)创建crd资源
首先确认crd是否已经注册:

创建crd资源:

5)验证
发现我们的operator已经成功为我们创建了资源:


也可访问node公网ip+端口访问服务进行验证。

6. 删除operator及crd资源

1)删除自定义资源

2)卸载operator

可视化操作或执行make uninstall即可。

参考文献:

  1. https://sdk.operatorframework.io/docs/building-operators/golang/tutorial/
  2. https://www.jianshu.com/p/628aac3e6758

【k8s】kubernetes编写自己的operator(operator-sdk:v1.xxx)相关推荐

  1. 从零开始入门 K8s | Kubernetes API 编程利器:Operator 和 Operator Framework

    作者  |  夙兴  阿里巴巴高级工程师 本文整理自<CNCF x Alibaba 云原生技术公开课>第 24 讲,点击"阅读原文"直达课程页面. 关注"阿里 ...

  2. 从零开始入门 K8s | Kubernetes API 编程利器:Operator 和 Operat

    导读:本文将从实践出发,结合案例来说明,如何借助 Operator 开发框架来扩展 Kubernetes API.内容主要分为三个部分:首先会简单介绍一下 Operator 相关的知识:然后会介绍 O ...

  3. Kubernetes 有状态应用程序控制器 Operator

    目录 一.概述 二.Operator Lifecycle Manager(OLM) 三.Operator 的三种类型 四.Operator 项目目录结构 1)公共目录/文件 2)Operator An ...

  4. 【云原生】Kubernetes 有状态应用程序控制器 Operator

    文章目录 一.概述 二.Operator Lifecycle Manager(OLM) 三.Operator 的三种类型 四.Operator 项目目录结构 1)公共目录/文件 2)Operator ...

  5. k8s部署Kube Prometheus(Prometheus Operator)

    摘要 本文通过Prometheus-operator框架一键化安装prometheus.alertmanage.granfana,并配置企业微信api以及告警推送,搭建 prometheus 的前提环 ...

  6. Kubernetes 编写自定义 controller

    原文链接:Kubernetes编写自定义controller 来自kubernetes官方github的一张图: 如图所示,图中的组件分为client-go和custom controller两部分: ...

  7. k8s服务器修改ip,[转载][K8S] Kubernetes 集群变更IP地址

    [K8S] Kubernetes 集群变更IP地址 原文:https://blog.csdn.net/whywhy0716/article/details/92658111 本文基于单节点K8S. 碎 ...

  8. 错误解析 error:unable to find numeric literal operator ‘operator““a/b/c/...‘

    当出现 error:unable to find numeric literal operator 'operator""c'或者 'b8'/ 'xx' was not decla ...

  9. k8s(Kubernetes)实战(一)之部署etcd与flannel

    k8s合集:(前两章为k8s二进制安装方法,十分复杂,推荐从第三章开始) k8s(Kubernetes)实战(一)之部署etcd与flannel k8s(Kubernetes)实战(二)之部署api- ...

  10. K8s(Kubernetes)虚拟机安装

    K8s(Kubernetes) 虚拟机安装 系统设置 1.关闭防火墙 2.关闭Selinux 3.关闭Swap分区 4.时间同步 服务器架构 1.服务器架构图 2.设置主机名 3.桥接设置 4.Mas ...

最新文章

  1. 机器学习入门(18)— 卷积网络中的池化层实现
  2. github访问太慢解决方案
  3. 第四章 菜单、工具栏和状态栏(第8课)
  4. 第二阶段冲刺第十天,6月9日。
  5. 北京关于领取2021年上半年合格证书的通知
  6. 厉害了!不用一行代码,手把手教你制作漂亮词云!
  7. 斯坦福的著名小兔子模型的点云数据_传统方法的点云分割以及PCL中分割模块
  8. Android quot;QR二维码扫描quot;
  9. C++11 tuple的使用
  10. 如何迁移outlook邮件到另一个硬盘_如何注册Yahoo邮箱?
  11. 开发好能重构的代码,都是这么干的
  12. 车牌号专用键盘设计和正则验证
  13. 又一次寻找bug的经历...这次是 openlayers + chrome + win7
  14. MySQL行级锁和表级锁
  15. android最强播放器,MX Player安卓史上最强大的播放器
  16. vdbench的作用_vdbench
  17. 计算机二级知识汇总手抄报,计算机二级vb_全国计算机二级vb真题
  18. WinForm BackgroundWorker笔记
  19. Android查看应用签名方法
  20. 不同IP网段连接网络打印机

热门文章

  1. 使用pip配置谷歌Colab Pytorch环境
  2. 必须精力充沛,才扛得住世事艰难
  3. 站在22岁的边上--我的2007
  4. 大数据Hadoop之——任务调度器Azkaban(Azkaban环境部署)
  5. U盘启动制作 + xp镜像
  6. 内容安全策略(content-security-policy)
  7. JAVA导出EXCEL——POI(转)
  8. performSelector延时调用导致的内存泄露
  9. Android苹方圆三合一字体,橘色主题-圆形图标 内置苹方+googlesans字体 透明文件夹...
  10. Windows XP SP3版本美化成Vista界面详解