直接调用 clientset.BatchV1().CronJobs(ns).Create() 创建 CronJob,需显式指定 namespace、合法 cron 表达式、OnFailure/ Never 重启策略及非空容器;更新 schedule 推荐删重建;查失败日志需沿 CronJob→Job→Pod 链路获取;未触发常因 controller 异常、UTC 时区误解或 startingDeadlineSeconds 过小。
直接调用 clientset.BatchV1().CronJobs() 的 Create() 方法即可,但必须确保命名空间、RBAC 权限和字段合法性。Kubernetes 不接受空 spec.schedule 或缺失 spec.jobTemplate.spec.template.spec.containers 的对象。
metadata.namespace 必须显式指定,不能留空(默认 namespace 不生效)spec.schedule 必须是合法 cron 表达式,如 "0 * * * *";"@hourly" 等别名不被 client-go 或 API Server 接受spec.jobTemplate.spec.template.spec.restartPolicy 只能是 "OnFailure" 或 "Never";设为 "Always" 会返回 422 错误imagePullSecrets
job := &batchv1.CronJob{
ObjectMeta: metav1.ObjectMeta{
Name: "hello-cron",
Namespace: "default",
},
Spec: batchv1.CronJobSpec{
Schedule: "*/5 * * * *",
JobTemplate: batchv1.JobTemplateSpec{
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
RestartPolicy: "OnFailure",
Containers: []corev1.Container{{
Name: "hello",
Image: "busybox:1.35",
Command: []string{"/bin/sh", "-c"},
Args: []string{"echo 'Hello from CronJob' && date"},
}},
},
},
},
},
},
}
_, err := clientset.BatchV1().CronJobs("default").Create(context.TODO(), job, metav1.CreateOptions{})不能直接 PATC

spec.schedule —— Kubernetes 默认拒绝对已存在 CronJob 的 schedule 字段进行变更(除非启用 CronJobV2 特性门控且集群版本 ≥ v1.25)。实际中更稳妥的做法是删除后重建,或改用 Replace() 全量更新。
spec.schedule 会返回 Forbidden: field is immutable
CronJobV2:可用 StrategicMergePatchType 更新,但需确认 kube-apiserver 启动参数含 --feature-gates=CronJobV2=true
Delete() + Create() 组合,避免状态残留CronJob 本身不存日志,它只触发 Job;真正运行的是由 CronJob 创建的 Job 对象,而 Job 控制器再创建 Pod。所以要查失败原因,得顺着 CronJob → 最新 Job → 最新 Pod 的链路查。
List() 查 ownerReferences 匹配该 CronJob 的 Job 列表,按 creationTimestamp 降序取第一个corev1.Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{}) 获取日志ttlSecondsAfterFinished,日志可能不可读不是代码写错,而是控制器层面被拦住。最常被忽略的三个点:
cronjob-controller 组件是否正常运行?可通过 kubectl get pods -n kube-system | grep cronjob 确认spec.startingDeadlineSeconds 是否过小?若上次调度错过(比如 controller 宕机),且该值设为 60,那么超过 1 分钟未执行就会跳过,不会补作业调试时优先检查 kubectl describe cronjob 输出中的 Events 和 Last Schedule 字段,比翻 Go 日志更快。