基于Kubebuilder开发Operator(入门使用)

原文地址:使用kubebuilder 理解k8s crd - 知乎

理解k8s的crd需要先理解k8s的controller模式

  • 比如kube-controller-manager中的deployment控制器,在初始化的时候就会传入要监听Deployments、ReplicaSet和pod的三个informer对象
  • 首先list一下对象到本地缓存,同时watch对象的变更,等于增量更新
func startDeploymentController(ctx ControllerContext) (controller.Interface, bool, error) {
    dc, err := deployment.NewDeploymentController(
        ctx.InformerFactory.Apps().V1().Deployments(),
        ctx.InformerFactory.Apps().V1().ReplicaSets(),
        ctx.InformerFactory.Core().V1().Pods(),
        ctx.ClientBuilder.ClientOrDie("deployment-controller"),
    )
    if err != nil {
        return nil, true, fmt.Errorf("error creating Deployment controller: %v", err)
    }
    go dc.Run(int(ctx.ComponentConfig.DeploymentController.ConcurrentDeploymentSyncs), ctx.Stop)
    return nil, true, nil
}
  • 然后内部会做sync其实就是Reconcile loop, 即调谐循环——说白了就是对比对象的actualState和expectState的差异,执行对应的增删操作 比如deployment中扩缩容操作

  • 计算差值,可以创建出的 pod 数减去所有活跃 rs的副本数之和
    • 如果差值为正,说明需要扩容,并且从ReplicaSetsBySizeNewer排序看是按照从新到旧扩容
    • 如果差值为负,说明需要缩容,并且从ReplicaSetsBySizeOlder排序看是按照从旧到新缩容
  • 算差值如下

deploymentReplicasToAdd := allowedSize - allRSsReplicas

var scalingOperation string
switch {
case deploymentReplicasToAdd > 0:
    sort.Sort(controller.ReplicaSetsBySizeNewer(allRSs))
    scalingOperation = "up"
case deploymentReplicasToAdd < 0:
    sort.Sort(controller.ReplicaSetsBySizeOlder(allRSs))
    scalingOperation = "down"
}

理解了k8s的controller模式后,crd就是你自己写的controller

  • 监听并处理你自己定义的资源,
  • 下面这张图很形象

安装 Kubebuilder

wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.1.0/kubebuilder_linux_amd64
mv kubebuilder_linux_amd64  /usr/local/bin/kubebuilder

创建脚手架工程

  • 创建一个目录,并且指定这个目录为代码仓库
mkdir -p ~/projects/guestbook
cd ~/projects/guestbook
kubebuilder init --domain my.domain --repo my.domain/guestbook
  • 查看这个目录下的文件结果
[root@k8s-node01 guestbook]# tree
.
├── config
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   └── rbac
│       ├── auth_proxy_client_clusterrole.yaml
│       ├── auth_proxy_role_binding.yaml
│       ├── auth_proxy_role.yaml
│       ├── auth_proxy_service.yaml
│       ├── kustomization.yaml
│       ├── leader_election_role_binding.yaml
│       ├── leader_election_role.yaml
│       ├── role_binding.yaml
│       └── service_account.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

6 directories, 24 files

创建api

  • 创建一个名为 webapp/v1的 API (group/version)
  • 创建新的类型 Guestbook
kubebuilder create api --group webapp --version v1 --kind Guestbook
  • 追踪结果,发现又多了很多文件 ,其中api/v1/guestbook_types.go代表定义API的地方 ,controllers/guestbook_controller.go代表调谐的逻辑
[root@k8s-master01 guestbook]# tree
.
├── api
│   └── v1
│       ├── groupversion_info.go
│       ├── guestbook_types.go
│       └── zz_generated.deepcopy.go
├── bin
│   └── controller-gen
├── config
│   ├── crd
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches
│   │       ├── cainjection_in_guestbooks.yaml
│   │       └── webhook_in_guestbooks.yaml
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   └── manager_config_patch.yaml
│   ├── manager
│   │   ├── controller_manager_config.yaml
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── prometheus
│   │   ├── kustomization.yaml
│   │   └── monitor.yaml
│   ├── rbac
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── guestbook_editor_role.yaml
│   │   ├── guestbook_viewer_role.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── role_binding.yaml
│   │   └── service_account.yaml
│   └── samples
│       └── webapp_v1_guestbook.yaml
├── controllers
│   ├── guestbook_controller.go
│   └── suite_test.go
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

13 directories, 37 files
  • 在调谐函数中添加打印日志,位于 controller/guestbook_controller.go
func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    _ = log.FromContext(ctx)

    // your logic here
    log.FromContext(ctx).Info("print_req", "req", req.String())
    return ctrl.Result{}, nil
}

部署到k8s集群中

  • 编译打镜像
make docker-build IMG=guestbook:v1.0     # 实际执行 docker build -t guestbook:v1.0 .
  • 一般我们需要修改项目里的 dockerfile,给 go 设置proxy代理,这样 go mod download时不至于超时连不上

  •  然后需要将镜像手动推送到本地仓库中,如果底层的runtime是ctr的话 需要docker save出来并导入
docker save guestbook:v1.0 > a.tar
ctr --namespace k8s.io images import a.tar
  • 因为项目中用到了 kube-rbac-proxy,这个镜像也可能出现下载不到的问题,需要自己手动处理一下,如下:

  •  现在部署crd
make deploy IMG=guestbook:v1.0 #实际执行 kustomize build config/default | kubectl apply -f -
  • 检查在guestbook-system ns 下部署的对象

  •  检查api-resources

  • 部署guestbook
kubectl apply -f config/samples/webapp_v1_guestbook.yaml
# guestbook.webapp.my.domain/guestbook-cxy created
  •  查看crd中的日志可以看到调谐函数中打印

猜你喜欢

转载自blog.csdn.net/chenxy02/article/details/124866691