Kubebuilder与Operator开发

Kubebuilder与Operator开发

【免费下载链接】kubebuilder Kubebuilder - SDK for building Kubernetes APIs using CRDs 【免费下载链接】kubebuilder 项目地址: https://gitcode.com/gh_mirrors/ku/kubebuilder

本文深入探讨了Kubebuilder作为Kubernetes Operator开发的官方SDK,详细介绍了Operator模式的核心概念、Kubebuilder在Operator开发中的关键角色,以及两者之间的紧密集成关系。文章涵盖了Operator架构设计、生产环境最佳实践、状态管理策略,以及与Operator SDK的对比分析,为开发者提供全面的Operator开发指导。

Operator模式与Kubebuilder的关系

Operator模式是Kubernetes生态系统中一种强大的自动化模式,它通过自定义控制器来扩展Kubernetes API,实现特定应用程序或服务的全生命周期管理。Kubebuilder作为构建Kubernetes Operator的官方SDK,为开发者提供了完整的工具链和最佳实践框架,极大地简化了Operator的开发过程。

Operator模式的核心概念

Operator模式基于Kubernetes的控制器模式,通过以下核心组件实现自动化管理:

mermaid

Operator的核心工作流程包括:

  1. 监控自定义资源:Operator通过watch机制监听特定CRD的变化
  2. 调和循环:当资源状态变化时,执行调和逻辑确保实际状态与期望状态一致
  3. 状态管理:维护资源的状态信息,提供可观测性
  4. 错误处理:实现健壮的错误处理和重试机制

Kubebuilder在Operator开发中的角色

Kubebuilder作为Operator开发的标准化框架,提供了以下关键能力:

功能模块描述在Operator中的作用
CRD脚手架自动生成Custom Resource Definition定义Operator管理的资源类型
控制器生成创建基础的控制器结构实现调和逻辑的核心组件
Webhook支持提供验证和变更webhook增强资源的验证和默认值设置
项目结构标准化的项目布局确保代码组织的一致性和可维护性
构建部署完整的CI/CD工具链简化Operator的构建和部署流程

Kubebuilder实现的Operator架构

Kubebuilder生成的Operator项目遵循清晰的架构模式:

// 典型的Kubebuilder控制器结构
type MyResourceReconciler struct {
    client.Client
    Scheme *runtime.Scheme
    Log    logr.Logger
}

// Reconcile方法是Operator的核心
func (r *MyResourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    // 1. 获取当前资源状态
    var resource mygroupv1.MyResource
    if err := r.Get(ctx, req.NamespacedName, &resource); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }
    
    // 2. 检查和管理依赖资源
    if err := r.manageDependencies(ctx, &resource); err != nil {
        return ctrl.Result{}, err
    }
    
    // 3. 更新资源状态
    if err := r.updateStatus(ctx, &resource); err != nil {
        return ctrl.Result{}, err
    }
    
    return ctrl.Result{}, nil
}

调和循环的详细实现

Kubebuilder通过controller-runtime库提供了强大的调和循环机制:

mermaid

最佳实践和设计模式

Kubebuilder鼓励开发者遵循以下Operator设计最佳实践:

  1. 声明式API设计:资源定义应该清晰表达用户的意图而非实现细节
  2. 幂等操作:确保调和逻辑可以安全地重复执行
  3. 状态管理:合理使用status字段记录操作进度和结果
  4. 错误处理:实现适当的重试机制和错误传播
  5. 资源清理:正确处理资源的删除和清理操作

与原生Kubernetes控制器的对比

Kubebuilder提供的Operator框架相比手动实现的控制器具有显著优势:

特性手动实现Kubebuilder
项目结构需要自行设计标准化模板
代码生成手动编写自动生成
测试框架需要搭建内置支持
部署配置手动配置自动生成
版本升级复杂简化

实际应用场景

Kubebuilder构建的Operator广泛应用于以下场景:

  • 数据库管理:MySQL、PostgreSQL等数据库的自动化部署和备份
  • 中间件运维:消息队列、缓存系统的生命周期管理
  • CI/CD工具:Jenkins、GitLab Runner的自动化配置
  • 监控告警:Prometheus、Grafana的动态配置管理
  • 自定义业务逻辑:特定业务需求的自动化处理

通过Kubebuilder,开发者可以专注于业务逻辑的实现,而不需要关心底层的基础设施代码,大大提高了Operator开发的效率和质量。这种紧密的集成关系使得Kubebuilder成为Kubernetes Operator开发的事实标准工具。

与Operator SDK的对比与集成

Kubebuilder和Operator SDK都是Kubernetes生态系统中用于构建Operator的重要框架,它们虽然有着相似的目标,但在设计哲学、架构和使用场景上存在显著差异。了解这两者的对比关系以及它们如何集成协作,对于选择合适的技术栈和构建高效的Kubernetes Operator至关重要。

核心设计哲学对比

Kubebuilder和Operator SDK在设计理念上体现了不同的侧重点:

mermaid

Kubebuilder的设计原则

  • 库优先策略:强调使用高质量的库而不是代码生成,这使得代码更易于维护和更新
  • 渐进式抽象:提供从底层到高层的分层抽象,既满足新手用户的简单需求,也支持专家用户的深度定制
  • 自包含文档:每个库都有完整的文档和丰富的示例,减少对外部文档的依赖

Operator SDK的设计特点

  • 多语言支持:不仅支持Go语言,还支持Ansible和Helm等非编程语言的Operator开发
  • 完整生命周期管理:提供从创建、测试到部署的完整Operator开发流程
  • 生态系统集成:深度集成Operator Framework,包括Operator Lifecycle Manager (OLM)

技术架构差异分析

从技术架构角度来看,这两个框架采用了不同的实现策略:

特性维度KubebuilderOperator SDK
核心依赖controller-runtime, controller-tools基于Kubebuilder构建
代码生成策略最小化代码生成,强调库复用较多的代码生成和脚手架
插件架构原生插件系统支持扩展通过Kubebuilder插件集成
多语言支持专注于Go语言Go、Ansible、Helm多语言
测试框架内置ginkgo/gomega测试框架类似的测试框架,额外提供e2e测试工具
// Kubebuilder典型的Reconciler实现
type MyReconciler struct {
    client.Client
    Log    logr.Logger
    Scheme *runtime.Scheme
}

func (r *MyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    log := r.Log.WithValues("myresource", req.NamespacedName)
    
    // 获取资源实例
    var myResource v1alpha1.MyResource
    if err := r.Get(ctx, req.NamespacedName, &myResource); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }
    
    // 业务逻辑实现
    return r.reconcileLogic(ctx, &myResource, log)
}

集成协作模式

Kubebuilder和Operator SDK并非竞争关系,而是互补协作的生态系统:

mermaid

技术集成层次

  1. 基础库共享:Operator SDK的Go Operator功能完全基于Kubebuilder的controller-runtime和controller-tools构建
  2. 插件系统集成:Operator SDK利用Kubebuilder的插件架构来扩展其功能
  3. 代码上游贡献:Operator SDK团队将通用功能贡献到Kubebuilder上游项目

功能特性迁移与协同开发

在集成过程中,多个重要功能从Operator SDK迁移到了Kubebuilder核心:

迁移的功能描述受益范围
DynamicRESTMapper动态发现集群中新添加的CRD所有基于controller-runtime的项目
GenerationChangedPredicate基于generation变化的调和触发提供更精确的调和控制
增强的日志配置细粒度的zap日志器配置改善Operator的可观察性
# Operator SDK项目结构示例(基于Kubebuilder)
my-operator/
├── Dockerfile
├── Makefile
├── PROJECT
├── api/
│   └── v1alpha1/
│       ├── groupversion_info.go
│       ├── myresource_types.go
│       └── zz_generated.deepcopy.go
├── config/
│   ├── default/
│   ├── manager/
│   ├── manifests/
│   ├── prometheus/
│   ├── rbac/
│   └── scorecard/
├── controllers/
│   ├── myresource_controller.go
│   └── suite_test.go
├── go.mod
├── go.sum
├── hack/
└── main.go

选择建议与最佳实践

根据项目需求选择合适的框架:

选择Kubebuilder当

  • 需要最大程度的控制和定制能力
  • 项目主要使用Go语言开发
  • 希望深度理解底层机制
  • 需要构建可复用的库组件

选择Operator SDK当

  • 需要多语言支持(Ansible/Helm)
  • 要求完整的Operator生命周期管理
  • 需要与Operator Framework生态系统集成
  • 团队熟悉Red Hat的Operator开发模式

混合使用策略: 对于复杂的项目,可以采用混合策略:使用Kubebuilder构建核心逻辑库,然后使用Operator SDK进行项目脚手架和部署管理。

实际集成示例

以下示例展示了如何在Kubebuilder项目中使用Operator SDK迁移过来的功能:

// 使用DynamicRESTMapper
import (
    "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)

func setupDynamicRESTMapper(mgr ctrl.Manager) {
    // 创建动态REST mapper
    dynamicMapper, err := apiutil.NewDynamicRESTMapper(mgr.GetConfig())
    if err != nil {
        panic(err)
    }
    
    // 配置Manager使用动态mapper
    mgr.GetClientOptions().Mapper = dynamicMapper
}

// 使用GenerationChangedPredicate
import (
    "sigs.k8s.io/controller-runtime/pkg/event"
    "sigs.k8s.io/controller-runtime/pkg/predicate"
)

func getGenerationPredicate() predicate.Predicate {
    return predicate.Funcs{
        UpdateFunc: func(e event.UpdateEvent) bool {
            // 只在generation变化时调和
            return e.ObjectOld.GetGeneration() != e.ObjectNew.GetGeneration()
        },
    }
}

这种集成模式使得开发者可以享受到两个项目的最佳特性,既能够使用Kubebuilder提供的强大库抽象,又能够利用Operator SDK的便捷开发工具和多语言支持。

通过这种深度集成,Kubernetes Operator开发社区避免了重复造轮子,使得开发者能够更加专注于业务逻辑的实现,而不是底层框架的选择和集成问题。

生产环境Operator开发实践

在Kubernetes生态系统中,Operator模式已经成为管理复杂有状态应用的标准方式。Kubebuilder作为构建Kubernetes Operator的官方SDK,为开发者提供了一套完整的工具链和最佳实践。本文将深入探讨在生产环境中使用Kubebuilder开发Operator的关键实践和注意事项。

Operator架构设计与最佳实践

控制器设计模式

在生产环境中,Operator的设计应该遵循以下核心原则:

mermaid

资源定义规范

生产环境的CRD定义应该包含完整的验证和版本管理:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: myapps.example.com
spec:
  group: example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
                image:
                  type: string
                  pattern: "^[a-zA-Z0-9./_-]+:[a-zA-Z0-9._-]+$"
            status:
              type: object
              properties:
                conditions:
                  type: array
                  items:
                    type: object
                    properties:
                      type: { type: string }
                      status: { type: string }
                      lastTransitionTime: { type: string }

生产环境配置管理

多环境部署策略

使用Kustomize实现多环境配置管理:

config/
├── base/
│   ├── kustomization.yaml
│   ├── manager/
│   └── rbac/
├── overlays/
│   ├── development/
│   ├── staging/
│   └── production/

生产环境Kustomize配置示例:

# config/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../base

patches:
- target:
    kind: Deployment
    name: manager
  patch: |-
    - op: replace
      path: /spec/replicas
      value: 3
    - op: replace
      path: /spec/template/spec/containers/0/resources/limits/memory
      value: 512Mi
    - op: add
      path: /spec/template/spec/affinity
      value:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - my-operator
              topologyKey: kubernetes.io/hostname

高可用性与容错设计

控制器并发配置
func SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&myappv1.MyApp{}).
        WithOptions(controller.Options{
            MaxConcurrentReconciles: 3,      // 并发协调数
            RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(
                5*time.Millisecond, 
                1000*time.Second,
            ),
        }).
        Complete(r)
}
优雅终止处理
func main() {
    // 设置信号处理
    ctx := ctrl.SetupSignalHandler()
    
    if err := mgr.Start(ctx); err != nil {
        setupLog.Error(err, "problem running manager")
        os.Exit(1)
    }
}

// 在Reconcile中处理终止信号
func (r *MyAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    select {
    case <-ctx.Done():
        return ctrl.Result{}, nil
    default:
        // 正常处理逻辑
    }
}

监控与可观测性

Prometheus指标集成
import (
    "sigs.k8s.io/controller-runtime/pkg/metrics"
    "github.com/prometheus/client_golang/prometheus"
)

var (
    reconcileTotal = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "myapp_reconcile_total",
            Help: "Total number of reconcile operations",
        },
        []string{"namespace", "name", "result"},
    )
    reconcileDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "myapp_reconcile_duration_seconds",
            Help:    "Duration of reconcile operations",
            Buckets: prometheus.ExponentialBuckets(0.1, 2, 10),
        },
        []string{"namespace", "name"},
    )
)

func init() {
    metrics.Registry.MustRegister(reconcileTotal, reconcileDuration)
}

func (r *MyAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    start := time.Now()
    defer func() {
        duration := time.Since(start).Seconds()
        reconcileDuration.WithLabelValues(req.Namespace, req.Name).Observe(duration)
    }()
    
    // 协调逻辑...
    
    reconcileTotal.WithLabelValues(req.Namespace, req.Name, "success").Inc()
    return ctrl.Result{}, nil
}

安全最佳实践

RBAC配置
# config/rbac/role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: manager-role
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["example.com"]
  resources: ["myapps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["example.com"]
  resources: ["myapps/status"]
  verbs: ["get", "update", "patch"]
- apiGroups: ["example.com"]
  resources: ["myapps/finalizers"]
  verbs: ["update"]
安全上下文配置
# 在Deployment中配置安全上下文
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000
  capabilities:
    drop:
    - ALL
  seccompProfile:
    type: RuntimeDefault

持续集成与部署

GitLab CI/CD流水线示例
stages:
  - test
  - build
  - deploy

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

.test-template: &test-template
  stage: test
  image: golang:1.22
  script:
    - make manifests generate fmt vet
    - make test

.build-template: &build-template
  stage: build
  image: docker:24.0
  services:
    - docker:24.0-dind
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

unit-tests:
  <<: *test-template

e2e-tests:
  <<: *test-template
  script:
    - make test-e2e

build-production:
  <<: *build-template
  only:
    - tags

deploy-production:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config set-cluster production --server=$K8S_SERVER --certificate-authority=/tmp/ca.crt
    - kubectl config set-credentials ci-user --token=$K8S_TOKEN
    - kubectl config set-context production --cluster=production --user=ci-user
    - kubectl config use-context production
    - sed -i "s|controller:latest|$IMAGE_TAG|g" config/manager/kustomization.yaml
    - make deploy

性能优化策略

缓存优化配置
func main() {
    mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme:                 scheme,
        Metrics:                metricsserver.Options{BindAddress: "0"},
        HealthProbeBindAddress: probeAddress,
        LeaderElection:         enableLeaderElection,
        LeaderElectionID:       "12345678.myapp.example.com",
        // 优化客户端缓存
        Client: client.Options{
            Cache: &client.CacheOptions{
                // 只缓存必要的资源类型
                DisableFor: []client.Object{
                    &corev1.Event{},
                },
            },
        },
        // 控制器缓存配置
        Cache: cache.Options{
            SyncPeriod: &syncPeriod,
            DefaultNamespaces: map[string]cache.Config{
                "default": {},
            },
        },
    })
}
批量处理优化
// 批量处理多个资源更新
func (r *MyAppReconciler) reconcileResources(ctx context.Context, myapp *myappv1.MyApp) error {
    resources := []client.Object{
        r.createDeployment(myapp),
        r.createService(myapp),
        r.createConfigMap(myapp),
    }
    
    for _, obj := range resources {
        if err := r.CreateOrUpdate(ctx, obj); err != nil {
            return err
        }
    }
    return nil
}

// 使用补丁操作减少API调用
func (r *MyAppReconciler) patchStatus(ctx context.Context, myapp *myappv1.MyApp, patch client.Patch) error {
    return r.Status().Patch(ctx, myapp, patch)
}

通过遵循这些生产环境最佳实践,开发者可以构建出稳定、高效且易于维护的Kubernetes Operator,确保在生产环境中能够可靠地运行和管理复杂的应用工作负载。

集群操作与状态管理策略

在Kubernetes Operator开发中,集群操作与状态管理是核心功能。Kubebuilder提供了强大的框架来帮助开发者构建高效的控制器,实现复杂的集群操作和状态管理逻辑。

状态管理机制

Kubernetes中的状态管理遵循声明式API设计原则,通过Spec和Status字段分离期望状态和实际状态。Kubebuilder自动生成的CRD结构包含完整的Status字段定义:

// MemcachedStatus定义了Memcached的观察状态
type MemcachedStatus struct {
    // conditions表示Memcached资源的当前状态
    // 每个条件都有唯一的类型,反映资源特定方面的状态
    //
    // 标准条件类型包括:
    // - "Available": 资源完全功能正常
    // - "Progressing": 资源正在创建或更新
    // - "Degraded": 资源未能达到或维持其期望状态
    //
    // 每个条件的状态为True、False或Unknown
    // +listType=map
    // +listMapKey=type
    // +optional
    Conditions []metav1.Condition `json:"conditions,omitempty"`
}

状态管理的关键在于使用Conditions数组来跟踪资源的不同方面状态。这种设计模式允许Operator清晰地表达复杂的状态信息。

协调循环(Reconcile Loop)

Kubebuilder的核心是协调循环机制,它持续监控集群状态并确保实际状态与期望状态一致:

mermaid

协调器的主要职责包括:

  1. 状态比较:对比Spec中定义的期望状态和Status中记录的实际状态
  2. 操作执行:根据需要创建、更新或删除Kubernetes资源
  3. 状态更新:根据操作结果更新Status字段
  4. 错误处理:处理协调过程中可能出现的各种错误情况

条件状态管理策略

有效的状态管理需要使用标准化的条件类型和状态值:

条件类型状态值含义使用场景
AvailableTrue资源可用所有副本正常运行
AvailableFalse资源不可用副本数不足或服务不可达
ProgressingTrue正在处理创建、更新或扩容操作中
ProgressingFalse处理完成操作已完成或无需操作
DegradedTrue降级状态部分功能异常但仍在运行
DegradedFalse正常运行所有功能正常

事件驱动架构

Kubebuilder基于控制器运行时(controller-runtime)构建事件驱动的架构:

mermaid

这种架构确保了:

  • 最终一致性:即使出现临时故障,系统最终会达到一致状态
  • 水平扩展:多个协调器实例可以同时处理不同资源
  • 错误恢复:失败的任务会自动重试

优雅的错误处理策略

在集群操作中,优雅的错误处理至关重要:

func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    // 获取Memcached实例
    memcached := &cachev1alpha1.Memcached{}
    if err := r.Get(ctx, req.NamespacedName, memcached); err != nil {
        if apierrors.IsNotFound(err) {
            // 资源已被删除,执行清理操作
            return ctrl.Result{}, nil
        }
        return ctrl.Result{}, err
    }

    // 检查资源是否正在删除
    if !memcached.ObjectMeta.DeletionTimestamp.IsZero() {
        // 执行finalizer清理逻辑
        return r.finalizeMemcached(ctx, memcached)
    }

    // 添加finalizer(如果尚未添加)
    if !controllerutil.ContainsFinalizer(memcached, memcachedFinalizer) {
        controllerutil.AddFinalizer(memcached, memcachedFinalizer)
        if err := r.Update(ctx, memcached); err != nil {
            return ctrl.Result{}, err
        }
    }

    // 执行实际的协调逻辑
    result, err := r.reconcileMemcached(ctx, memcached)
    if err != nil {
        // 更新状态为Degraded
        if updateErr := r.updateStatus(ctx, memcached, metav1.ConditionFalse, "ReconcileFailed", err.Error()); updateErr != nil {
            log.Error(updateErr, "Failed to update status")
        }
        return result, err
    }

    // 更新状态为Available
    if updateErr := r.updateStatus(ctx, memcached, metav1.ConditionTrue, "ReconcileSuccess", "Successfully reconciled"); updateErr != nil {
        return ctrl.Result{}, updateErr
    }

    return result, nil
}

状态更新最佳实践

  1. 原子性操作:状态更新应该是原子性的,避免部分更新
  2. 条件顺序:按照标准条件类型顺序排列状态信息
  3. 时间戳管理:正确设置LastTransitionTime字段
  4. 原因和消息:提供清晰的错误原因和人类可读的消息
  5. 避免频繁更新:只在状态真正变化时更新Status字段

性能优化策略

对于大规模集群操作,需要实施性能优化策略:

// 使用指数退避重试机制
reconcile.Result{RequeueAfter: time.Second * 5}

// 批量处理相关资源
func (r *MemcachedReconciler) reconcileDeployments(ctx context.Context, memcached *cachev1alpha1.Memcached) error {
    // 批量创建或更新Deployment
    for i := 0; i < int(*memcached.Spec.Size); i++ {
        deployment := constructDeployment(memcached, i)
        if err := controllerutil.SetControllerReference(memcached, deployment, r.Scheme); err != nil {
            return err
        }
        // 创建或更新操作
        if err := r.Create(ctx, deployment); err != nil {
            if !apierrors.IsAlreadyExists(err) {
                return err
            }
            // 已存在则更新
            if err := r.Update(ctx, deployment); err != nil {
                return err
            }
        }
    }
    return nil
}

通过合理的状态管理策略和优化技术,Kubebuilder Operator能够高效地管理复杂的集群操作,确保应用程序的稳定性和可靠性。

总结

Kubebuilder作为Kubernetes Operator开发的强大框架,通过提供完整的工具链和最佳实践,极大地简化了Operator的开发过程。文章详细探讨了Operator模式的核心概念、Kubebuilder的架构设计、生产环境实践、状态管理策略,以及与Operator SDK的集成关系。通过合理的状态管理、错误处理和性能优化策略,开发者可以构建出稳定高效的Kubernetes Operator,有效管理复杂的集群操作和应用程序生命周期。Kubebuilder已成为Kubernetes生态系统中Operator开发的事实标准工具。

【免费下载链接】kubebuilder Kubebuilder - SDK for building Kubernetes APIs using CRDs 【免费下载链接】kubebuilder 项目地址: https://gitcode.com/gh_mirrors/ku/kubebuilder

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值