Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

(Alpha)Server-Side Apply

--ssa 标志会脚手架生成带 Server-Side Apply 支持的 API,使多个参与者修改同一资源时字段管理更安全。

这将添加:

  • 用于生成 ApplyConfiguration 的 API 标记(+genclient、+kubebuilder:ac:generate=true)
  • Makefile 集成,在生成 CRD 与 RBAC 清单的同时生成类型安全的 ApplyConfiguration 类型

何时使用它

在以下情况使用 Server-Side Apply:

  • 多个控制器或用户管理同一资源
  • 用户用标签、注解或你的控制器不应覆盖的 spec 字段自定义 CR
  • 你需要声明式字段所有权跟踪
  • 其他 Operator 将管理你的 CR 实例(它们可导入你生成的 ApplyConfiguration 类型)

它是如何工作的

传统的 Update() 会覆盖整个对象。使用客户端 Apply 方法的 Server-Side Apply 只管理你指定的字段。

运行 make manifests 后,ApplyConfiguration 类型创建于:

api/<version>/applyconfiguration/api/<version>/          (single group)
api/<group>/<version>/applyconfiguration/<group>/<version>/  (multi-group)

导入方式如下(多 group 项目使用 example.com/myproject/api/<group>/v1/applyconfiguration/<group>/v1):

appsv1apply "example.com/myproject/api/v1/applyconfiguration/api/v1"

混合使用 SSA 与非 SSA API

groupversion_info.go 中的 +kubebuilder:ac:generate=true marker 是包级的:它为该 group/version 启用 ApplyConfiguration 生成。每个 kind 再用自己的 +kubebuilder:ac:generate marker 选择加入或排除:用 --ssa 脚手架的 kind 为 =true,未使用的为 =false。当你用 --ssa 创建 API 时,该 group/version 中此前脚手架且没有此 marker 的 kind 会自动获得它。

要更改生成哪些 kind:

  • 在 kind 上方设置 +kubebuilder:ac:generate=true 以包含它
  • 在 kind 上方设置 +kubebuilder:ac:generate=false 以排除它

Usage

使用 --ssa 标志创建 API:

kubebuilder create api --group apps --version v1 --kind Application --ssa

在控制器中实现 Server-Side Apply:

import (
    "context"

    metav1apply "k8s.io/client-go/applyconfigurations/meta/v1"
    ctrl "sigs.k8s.io/controller-runtime"
    "sigs.k8s.io/controller-runtime/pkg/client"

    appsv1apply "example.com/myproject/api/v1/applyconfiguration/api/v1"
)

func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    // Build desired state - specify only fields you manage
    app := appsv1apply.Application(req.Name, req.Namespace).
        WithStatus(appsv1apply.ApplicationStatus().
            WithConditions(metav1apply.Condition().
                WithType("Available").
                WithStatus("True").
                WithReason("Reconciled")))

    // Apply status, forcing ownership of the fields this controller manages
    if err := r.SubResource("status").Apply(ctx, app,
        client.FieldOwner("application-controller"), client.ForceOwnership); err != nil {
        return ctrl.Result{}, err
    }
    return ctrl.Result{}, nil
}

然后运行:

make generate manifests

最佳实践

  • 始终指定 client.FieldOwner("controller-name") 以标识你的控制器
  • Controller 应对所管理的字段传入 client.ForceOwnership;Kubernetes 建议 controller 始终强制解决冲突
  • 使用 builder 模式仅指定你的控制器所管理的字段

其他资源