FAQ

How does the value informed via the domain flag (i.e. kubebuilder init --domain example.com) when we init a project?

创建项目后,通常您会希望扩展 Kubernetes API,并定义由您的项目拥有的新 API。因此,域值会被记录在 PROJECT 文件中,该文件定义了您的项目配置,并将作为域来创建您的 API 端点。请确保您了解 组、版本和种类,真是让人头大!

该域名用于组后缀,以明确显示资源组类别。例如,如果设置为 --domain=example.com

kubebuilder init --domain example.com --repo xxx --plugins=go/v4
kubebuilder create api --group mygroup --version v1beta1 --kind Mykind

那么结果资源组将是 mygroup.example.com

如果域字段未设置,默认值为 my.domain

我希望自定义我的项目,使用 klog 替代 controller-runtime 提供的 zap。我该如何使用 klog 或其他日志记录器作为项目的日志记录器?

main.go 中,你可以替换:

    opts := zap.Options{
    Development: true,
    }
    opts.BindFlags(flag.CommandLine)
    flag.Parse()

    ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

与:

    flag.Parse()
	ctrl.SetLogger(klog.NewKlogr())

在执行 make run 后,我看到类似“无法找到领导者选举命名空间:未在集群内运行…“的错误。

您可以启用领导者选举。不过,如果您使用 make run 目标在本地测试项目,这将使管理器在集群外部运行,那么您可能还需要设置领导者选举资源将要创建的命名空间,如下所示:

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:                  scheme,
		MetricsBindAddress:      metricsAddr,
		Port:                    9443,
		HealthProbeBindAddress:  probeAddr,
		LeaderElection:          enableLeaderElection,
		LeaderElectionID:        "14be1926.testproject.org",
		LeaderElectionNamespace: "<project-name>-system",

如果您在集群上运行项目并使用 make deploy 目标,那么您可能不想添加此选项。因此,您可以使用环境变量自定义此行为,仅在开发目的时添加此选项,例如:

    leaderElectionNS := ""
	if os.Getenv("ENABLE_LEADER_ELECTION_NAMESPACE") != "false" {
		leaderElectionNS = "<project-name>-system"
	}

	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:                  scheme,
		MetricsBindAddress:      metricsAddr,
		Port:                    9443,
		HealthProbeBindAddress:  probeAddr,
		LeaderElection:          enableLeaderElection,
		LeaderElectionNamespace: leaderElectionNS,
		LeaderElectionID:        "14be1926.testproject.org",
		...

当我在旧版本的 Kubernetes 上部署我的项目时,出现错误“open /var/run/secrets/kubernetes.io/serviceaccount/token: permission denied“。我该如何解决这个问题?

如果您遇到错误:

`当您在较旧版本的 Kubernetes 上运行项目(可能是 \<= 1.21)时,可能会遇到 [这个问题](https://github.com/kubernetes/kubernetes/issues/82573),其原因是挂载的令牌文件设置为 0600`,请查看 解决方案。然后,解决方法是:

在 manager.yaml 中添加 fsGroup

安全上下文:
        以非root用户身份运行: true
        fsGroup: 65532 # 添加此 fsGroup 以使令牌文件可读

不过,请注意,此问题已被修复,如果您在高版本(可能大于或等于1.22)中部署项目,则不会发生该问题。

当我运行 make install 来应用 CRD 清单时,出现错误 过长:必须最多为 262144 字节。如何解决这个问题?为什么会出现这个错误?

在尝试运行 make install 来应用 CRD 清单时,可能会遇到错误 Too long: must have at most 262144 bytes。这个错误是由于 Kubernetes API 强制执行的大小限制所导致。请注意,make install 目标将使用 kubectl apply -f - 来应用位于 config/crd 下的 CRD 清单。因此,当使用 apply 命令时,API 会用 last-applied-configuration 注解该对象,该注解包含整个之前的配置。如果这个配置太大,就会超过允许的字节大小。(更多信息

在理想情况下,客户端应用可能看起来是完美的解决方案,因为整个对象配置不必作为注解(last-applied-configuration)存储在服务器上。 However,值得注意的是,目前它并不被 controller-gen 或 kubebuilder 支持。有关更多信息,请参见:Controller-tool-discussion

因此,您有一些选项可以绕过此情况,例如:

通过从 CRD 中移除描述:

您的 CRD 是使用 controller-gen 生成的。通过使用选项 maxDescLen=0 来移除描述,您可以减少大小,从而解决问题。为此,您可以按照以下示例更新 Makefile,然后调用目标 make manifest 以重新生成没有描述的 CRD,具体如下:

通过重新设计您的 API:

您可以审查您的 API 设计,看看它是否有超过应有的规格,从而违反单一职责原则。例如,这样您可能需要重新设计它们。

How can I validate and parse fields in CRDs effectively?

为了提高用户体验,建议在编写 CRD 时使用 OpenAPI v3 schema 验证。然而,这种方法有时可能需要额外的解析步骤。例如,请考虑以下代码:

type StructName struct {
	// +kubebuilder:validation:Format=日期-时间
	TimeField string `json:"timeField,omitempty"`
}

在这种情况下会发生什么?

  • 如果用户尝试创建具有无效 timeField 值的 CRD,Kubernetes API 会向其发送错误通知。
  • 在开发者端,字符串值需要在使用之前手动解析。

有没有更好的方法?

为了提供更好的用户体验和简化开发人员体验,建议使用预定义类型,如 metav1.Time。例如,考虑以下代码:

type StructName struct {
	TimeField metav1.Time `json:"timeField,omitempty"`
}

在这种情况下会发生什么?

  • 用户仍然会收到来自 Kubernetes API 的错误通知,提示无效的 timeField 值。
  • 开发人员可以直接在代码中使用解析后的 TimeField,而无需额外的解析,从而减少错误并提高效率。