关于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. 【并发编程】线程锁--Synchronized、ReentrantLock(可重入锁)
  2. 展望企业级移动设备的操作系统
  3. 天马行空W:在C++中调用DLL中的函数
  4. 数据库事务的四大特征
  5. oracle em 空白,Oracle em中出现按钮乱码的实际解决方案
  6. docker部署springboot_创建SpringBoot项目部署到docker全过程
  7. 配置exchange 2010高可用群集服务(dag)
  8. Oracle ODP.NET数据库访问连接字符串
  9. 系统学习深度学习(四十三)--GAN简单了解
  10. 12,mac phpstorm xdebug
  11. maven添加mirror_Maven配置setting.xml值Mirror与Repository区别(示例代码)
  12. 仿乐享微信源码分享,微信公众平台源码
  13. xampp修改mysql默认端口需要修改的地方
  14. IIS与CuteFTP进行网站发布
  15. 【PRD】倒推“Soul”APP产品需求文档
  16. 【实现】树莓派开机自动向微信发消息报告ip地址(无第三方代理)
  17. 用网络求t图的几篇论文框架图
  18. 群晖java安装失败_群晖NAS安装Jenkins
  19. 【MT7620】MT7620 WiFi驱动增加无线终端连接实时协商速率功能
  20. 802.11与802.3数据帧转换(即有线和无线数据帧转换)

热门文章

  1. Linux下载GEO数据,教你3种方法下载NCBI GEO数据
  2. 邬先生及时功成身退,是明哲保身的聪明做法 --- 我看电视剧《雍正王朝》
  3. 考研政治|马克思主义基本原理
  4. 利用Python进行数据分析(Ⅳ)
  5. 通过nginx代理实现内网访问百度地图方案
  6. 最快零基础上手——latex文档标题、一级标题、二级标题、内容搭建
  7. GNS3中配置直连交换端口的路由器端口IP地址
  8. Hulu面试(或许待更)
  9. 拍牌(沪牌)软件编写ideal(C#)------序
  10. 使用RMF报表设计器进行报表设计