首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >把证书续期从 crontab 搬进 Kubernetes CronJob

把证书续期从 crontab 搬进 Kubernetes CronJob

原创
作者头像
东风微鸣
发布于 2026-11-09 10:01:34
发布于 2026-11-09 10:01:34
630
举报

📝Notes: 本文讲的是 Linux crontab → K8s CronJob 的迁移设计与验证策略。acme.sh + DNSPod 的签发流程、腾讯 CDN 与七牛的推送细节,在另一篇里已经写过,这里只做背景交代,一笔带过。

背景:续期跑在一台台式机上

书接上回,旧方案三句话就能说完:

  • 一台 Ubuntu 台式机、
  • 一个 ~/.acme.sh、
  • 一行 crontab。

能跑,但问题不少:

  1. 单点。机器休眠、换硬盘、重装系统,续期链路就断了。链路断了那证书就要过期了。
  2. 不可观察。crontab 跑没跑、失败没失败,只能翻日志。没有 Job 历史,没有失败计数,告警无从接起。
  3. 配置漂移。crontab 里那一行命令和实际脚本之间没有唯一事实来源,改过一次就再也说不清当时改了什么。

为什么是 CronJob

Kubernetes 的 CronJob 是这套环境里唯一同时具备「声明式」和「有历史记录」两个属性的定时器。

能拿到的是这些:

  • 写进 Git,走 GitOps 流程统一 review,配置漂移归零。
  • Job 历史保留,成功失败都能 kubectl get jobs 查到,不用登录某台机器翻日志。
  • 重试次数、并发策略、超时时间都是字段,不用自己写 shell 判断。
  • 日志进 Loki,指标进 Prometheus,告警接 Alertmanager,链路都是现成的。

CronJob 结构

骨架大致是这个样子,字段按实际环境调整。

代码语言:yaml
复制
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cert-renew
  namespace: certs
spec:
  schedule: "17 3 * * *"
  timeZone: "Asia/Shanghai"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 3600
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 1800
      template:
        spec:
          restartPolicy: Never
          serviceAccountName: cert-renew
          containers:
            - name: acme
              image: neilpang/acme.sh:latest
              command: ["/bin/sh", "-c"]
              args:
                - |
                  acme.sh --issue --dns dns_dp \
                    -d ewhisper.cn -d '*.ewhisper.cn'
              envFrom:
                - secretRef:
                    name: acme-dns-credential
              volumeMounts:
                - name: acme-home
                  mountPath: /acme.sh
          volumes:
            - name: acme-home
              persistentVolumeClaim:
                claimName: acme-home

详细说明如下:

  • concurrencyPolicy: Forbid 是必须的。两轮重叠时同时去写 DNS TXT 记录,会互相覆盖,签发直接失败。
  • startingDeadlineSeconds: 3600 给了一小时容错窗口。集群短暂不可用时不至于整轮丢失。
  • timeZone 字段要求 K8s 1.27 以上(我的昨天刚升级到 1.37,最新 stable 版本的 k3s),低于这个版本得靠容器内 TZ 环境变量兜底。
  • restartPolicy: Never 配合 backoffLimit: 2,失败两次就停,避免无限重试把 DNS API 打爆。

密钥管理:仓库里只有占位符

密钥管理一定一定要注意,避免泄露:

  • 仓库内只放占位符。
  • 密钥通过 External Secret Operator 单独管理

📌示例:占位符的作用是让 spec 可以提交、CI 可以跑、PR 可以 review,而 Secret 本体永远不进 Git 历史。

密钥挂载方案:CronJob 通过 Secret 挂载环境变量,readOnly,不落盘到镜像层,也不出现在 kubectl describe pod 的明文输出里。

上线检查清单

第一跑之前,一条一条过一遍:

  1. 确认 Pod 里挂载的是密钥的真实值,不是仓库里的占位符。
  2. ServiceAccount 只给必需的 verb,能读 Secret 就够,别给 *。
  3. concurrencyPolicy: Forbid 确认生效。
  4. startingDeadlineSeconds 不小于一轮执行时长。
  5. 第一轮手动触发,不要干等 schedule。
  6. 迁移前记录当前证书指纹,作为比对基准。
  7. crontab 保留至少一个完整周期再删。
  8. Job 失败告警接进 Alertmanager。

最终成功完成迁移。🎉🎉🎉

总结

Linux crontab 到 K8s CronJob 的迁移,YAML 部分照着官方文档就能写出来。难点是实践过程中的细节考量。

本文总结了我从 Linux crontab 迁移证书续期到 Kubernetes CronJob 的设计、密钥管理、与上线前检查等步骤。收益是:

  • 更可靠稳定
  • 有历史日志(Loki),有告警(AlertManager)
  • GitOps: git 是唯一事实来源。

相关代码已经打包成 helm chart,感兴趣的可以看看:https://github.com/east4ming/homelab2/tree/master/apps/acme-ewhisper

希望对你有所帮助。

🎉🎉🎉

📚️参考文档

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 背景:续期跑在一台台式机上
  • 为什么是 CronJob
  • CronJob 结构
  • 密钥管理:仓库里只有占位符
  • 上线检查清单
  • 总结
  • 📚️参考文档
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档