Kubernetes 怎样在 Pod 外面组合业务?
上一讲说了,Kubernetes 调度的最小单位是 Pod,不是容器。那是不是写个 Pod 就能上业务了?还不行。
一个 echo 跑完就退出的 Pod,会被反复拉起,最后变成 CrashLoopBackOff。Nginx 这类长期在线的服务没有这个问题;日志分析、转码这类“算完就退出”的任务则会踩中默认重启策略。另外,端口、密码如果写死在镜像里,改一次配置还得重新构建镜像。
所以先要把任务分成在线和离线。分清了,才知道什么该直接用 Pod 的默认行为,什么该用 Job / CronJob 包一层。配置再用 ConfigMap / Secret 从外面注入。
1. 在线任务、离线任务
课程里把集群里的应用先分成两类。名字容易误会:这里的「离线」不是没网,是算完就走,英文常叫 batch / offline job。
在线任务是长期运行的服务,Nginx、Node.js、MySQL、Redis 都属于这一类。启动之后不应停止,随时接收请求。进程退出会被视为故障,需要拉起。上一讲的 Nginx Pod 对应的就是这种模型,默认 restartPolicy 是 Always。
离线任务是一批计算,完成后退出。日志分析、数据建模、视频转码、数据库备份都很常见。它们往往不直接服务外部用户,主要对内有用。核心特点是一定会退出,不会无限期运行。因此还要处理超时、失败重试、获取结果。上一讲 busy-pod 执行完 echo 就退出,却被当成服务反复重启,就是用在线策略去管离线任务。
区分标准只有一条:正常情况下,这个进程应该持续运行,还是应该运行完毕后退出?
- 应该持续运行 → 在线。退出视为失败。
- 应该运行完毕后退出 → 离线。退出才算成功;一直不退出,反而可能是卡住了。
这和重要程度无关。MySQL 重要,夜间备份同样重要。差别在生命周期:一个常驻,一个有始有终。
离线任务还可以再分:
- 临时任务:按需执行一次。对应 Job。
- 定时任务:按周期执行。对应 CronJob。
2. 为什么不直接改 Pod
上一讲那个 busy-pod,容器本身没有异常,只是执行完 echo 正常退出。但 Pod 默认把其中的进程当作服务:退出就会重启。离线任务本身就需要退出,这个默认行为对不上。
那能不能给 Pod 增加字段,专门处理“完成后不要重启、超时杀掉、失败再试”?可以,但 Pod 会同时承担容器管理、作业策略和配置,职责过重。
课程里的思路是:Pod 继续只管理容器。作业如何运行,另建对象,把 Pod 嵌进去当模板。配置也不写进镜像,单独存放,Pod 使用时再引用。各对象只做自己的事。
3. Job:跑完就结束
临时跑一次的,用 Job。它的 apiVersion 是 batch/v1,不是普通 Pod 的 v1。
YAML 是嵌套结构:外层是 Job,spec.template 里放一份 Pod 规格。这份 Pod 没有自己的 apiVersion 和 kind,只描述容器如何运行。Job 依据这份模板创建真正的 Pod。

离线任务还要改重启策略。restartPolicy 写在模板里的 Pod 上:失败了原地重启容器,用 OnFailure;不重启、让 Job 再开一个新 Pod,用 Never。不要用 Always,否则又会变成那个死循环。
1 | apiVersion: batch/v1 |
kubectl apply 之后,要看两处:kubectl get job 看作业完没完,kubectl get pod 看具体那个 Pod。正常结束的状态是 Completed,不是 Running,Job 上会显示 1/1。Pod 名字一般是 Job 名后面跟一串随机字符,输出用 kubectl logs 看。
超时、重试、要跑几个、能不能并行,这些不写在 Pod 模板里,写在 Job 自己的 spec 下:
activeDeadlineSeconds:跑太久就超时backoffLimit:失败最多试几次completions:一共要成功几个 Pod,默认 1 个parallelism:同时最多跑几个,避免把集群占满
课程里有个 sleep-job:超时 15 秒,失败最多重试 2 次,总共要完成 4 个 Pod,同一时刻最多 2 个。kubectl get pod -w 可以观察排队、启动和完成。这些字段声明清楚后,并行度和完成数由控制器维护。
Job 完成后不会立刻删除,便于事后查看日志。保留过多会占用资源,可以用 ttlSecondsAfterFinished 到期自动清理。
4. CronJob:按点再跑一遍
Job 是按需执行一次。每天备份、每分钟扫描这类周期任务,用 CronJob,简称 cj。
它不直接管理 Pod,而是先嵌套一个 Job,再由 Job 嵌套 Pod。YAML 里可以看到三层 spec:最外层是定时规则 schedule,中间 jobTemplate 是 Job,最内层 template 才是 Pod。

schedule 与 Linux crontab 相同,*/1 * * * * 表示每分钟一次。表达式不好记时,可以用 crontab.guru 核对。
创建、查看和 Job 差不多:kubectl apply,然后 kubectl get cj、kubectl get pod。默认只留最近 3 次成功记录,改 successfulJobsHistoryLimit 可以调整。
连起来看就是:CronJob 决定什么时候开工,Job 决定跑几个、失败怎么办,Pod 决定容器长什么样。每一层只多管一件事。
5. 光会跑还不够,还得把配置拆出来
Job 套完,任务能跑完了。可进程启动时还要读端口、路径、密码。如果这些写在 Dockerfile 的 COPY 里,改个参数就得重新打镜像;如果靠 docker cp 或 -v 往里塞,集群里也不好自动管。
Kubernetes 的办法还是单独做对象,再让 Pod 去用。
配置都是字符串,差别在于是否适合明文存放:
- 端口、路径、普通参数:ConfigMap,简写
cm - 密码、密钥、证书:Secret
它们不是容器,没有 spec,数据放在 data 里,一组 Key-Value。
1 | kubectl create cm info --from-literal=count=10 --dry-run=client -o yaml |
apply 进去之后存在 etcd 里。kubectl describe 能直接看到 ConfigMap 的明文。
Secret 用法差不多,入门用这种就行:
1 | kubectl create secret generic user --from-literal=name=root --dry-run=client -o yaml |
看起来和 ConfigMap 几乎一样,只是 data 里是 Base64。这不是加密,只是避免明文直接出现在输出里。kubectl describe Secret 时通常只显示数据大小。自行转码时要加 echo -n,否则换行符也会被编码,值会出错:
1 | echo -n 'root' | base64 |
跟 Job 不一样:Job 是把 Pod 嵌在 YAML 里;ConfigMap / Secret 只是一堆字符串,不注入进 Pod,容器根本读不到。引用靠名字,一份配置可以给好几个 Pod、好几个 Job 用。
6. 两种注入:环境变量,或者挂成文件
短的值,做成环境变量最省事。Pod 的 env 不要写死 value,改成 valueFrom:明文走 configMapKeyRef,机密走 secretKeyRef。
这里有个容易混的地方:name 填的是 ConfigMap / Secret 对象的名字,真正取哪一条数据用 key。

大段配置,比如一份 nginx.conf,更适合挂成文件。先在 Pod 的 spec.volumes 里声明卷(和 containers 平级,卷属于整个 Pod),再在容器的 volumeMounts 里挂到某个目录。
多绕一步,是为了以后磁盘、网络盘也能用同一套 Volume 概念。

挂进去之后,目录里每个文件名就是原来的 Key,文件内容就是 Value。应用按读普通文件的方式读就行。
修改 ConfigMap / Secret 再 apply 之后,已经在运行的 Pod 会不会立刻生效,需要自己验证。环境变量尤其可能仍是旧值,往往要重建 Pod。
7. 对照
| 你想做的事 | 用谁 | 它和 Pod 的关系 |
|---|---|---|
| 长期在线的服务 | 在线任务 | 裸 Pod 默认按这个管,后面用 Deployment |
| 跑完就结束 | 离线任务 / Job | 里面嵌一份 Pod 模板 |
| 到点再跑 | 离线任务 / CronJob | 里面嵌 Job,Job 再嵌 Pod |
| 普通配置 | ConfigMap | 被 Pod 按名字引用 |
| 密码这类 | Secret | 一样引用,数据是 Base64 |
| 短配置 | env.valueFrom | 变成环境变量 |
| 长配置文件 | volumes + volumeMounts | 变成目录里的文件 |
写 YAML 前先想清楚:这个进程是常驻,还是跑完就结束?配置会不会改、能不能写进镜像?
持续运行的用在线模型,不要用 Job。会结束的用 Job / CronJob,不要直接创建裸 Pod。需要变更的配置放 ConfigMap 或 Secret,短配置用环境变量,长配置挂成文件。
图片来源:极客时间 《Kubernetes入门实战课》 第 13 讲《Job/CronJob:为什么不直接用Pod来处理业务?》、第 14 讲《ConfigMap/Secret:怎样配置、定制我的应用》,作者 Chrono。