Skip to content

kubebuilder 实战

完整项目开发流程

bash
# 1. 初始化项目
mkdir myapp-operator && cd myapp-operator
go mod init github.com/mycompany/myapp-operator
kubebuilder init --domain mycompany.io --repo github.com/mycompany/myapp-operator

# 2. 创建 API
kubebuilder create api \
  --group apps \
  --version v1alpha1 \
  --kind MyApp \
  --resource \
  --controller

# 3. 创建 Webhook
kubebuilder create webhook \
  --group apps \
  --version v1alpha1 \
  --kind MyApp \
  --defaulting \
  --validation

# 4. 编辑类型定义
vim api/v1alpha1/myapp_types.go

# 5. 生成代码
make generate    # 生成 DeepCopy 方法
make manifests   # 生成 CRD、RBAC、Webhook YAML

# 6. 本地测试
make install     # 安装 CRD 到集群
make run         # 本地运行 Controller

# 7. 构建镜像
make docker-build docker-push IMG=my-registry/myapp-operator:v0.1.0

# 8. 部署到集群
make deploy IMG=my-registry/myapp-operator:v0.1.0

main.go 结构

go
func main() {
    // 注册类型
    utilruntime.Must(appsv1alpha1.AddToScheme(scheme))

    // 创建 Manager
    mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme:                 scheme,
        Metrics:                metricsserver.Options{BindAddress: ":8080"},
        HealthProbeBindAddress: ":8081",
        LeaderElection:         true,
        LeaderElectionID:       "myapp-operator-leader",
    })

    // 注册 Reconciler
    if err = (&controller.MyAppReconciler{
        Client: mgr.GetClient(),
        Scheme: mgr.GetScheme(),
    }).SetupWithManager(mgr); err != nil {
        setupLog.Error(err, "无法创建 Controller")
        os.Exit(1)
    }

    // 注册 Webhook
    if err = (&appsv1alpha1.MyApp{}).SetupWebhookWithManager(mgr); err != nil {
        setupLog.Error(err, "无法创建 Webhook")
        os.Exit(1)
    }

    // 健康检查
    mgr.AddHealthzCheck("healthz", healthz.Ping)
    mgr.AddReadyzCheck("readyz", healthz.Ping)

    // 启动
    if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
        setupLog.Error(err, "启动失败")
        os.Exit(1)
    }
}

测试

go
// internal/controller/myapp_controller_test.go
var _ = Describe("MyApp Controller", func() {
    Context("创建 MyApp", func() {
        It("应该创建对应的 Deployment", func() {
            myApp := &appsv1alpha1.MyApp{
                ObjectMeta: metav1.ObjectMeta{
                    Name:      "test-app",
                    Namespace: "default",
                },
                Spec: appsv1alpha1.MyAppSpec{
                    Image:    "nginx:1.25",
                    Replicas: 2,
                },
            }
            Expect(k8sClient.Create(ctx, myApp)).Should(Succeed())

            // 等待 Deployment 创建
            deploy := &appsv1.Deployment{}
            Eventually(func() error {
                return k8sClient.Get(ctx, types.NamespacedName{
                    Name:      "test-app",
                    Namespace: "default",
                }, deploy)
            }, timeout, interval).Should(Succeed())

            Expect(*deploy.Spec.Replicas).Should(Equal(int32(2)))
            Expect(deploy.Spec.Template.Spec.Containers[0].Image).Should(Equal("nginx:1.25"))
        })
    })
})
bash
# 运行测试(需要 envtest)
make test

# 查看测试覆盖率
go tool cover -html=cover.out

常用 Makefile 目标

makefile
make generate    # 生成 DeepCopy 代码
make manifests   # 生成 CRD/RBAC/Webhook YAML
make install     # 安装 CRD 到集群
make uninstall   # 卸载 CRD
make run         # 本地运行
make test        # 运行测试
make build       # 构建二进制
make docker-build docker-push IMG=xxx  # 构建推送镜像
make deploy IMG=xxx    # 部署到集群
make undeploy          # 从集群卸载

本站内容由 褚成志 整理编写,仅供学习参考