Kubernetes 怎样用 Deployment 和 DaemonSet 管在线应用?
离线任务用 Job 包装一层,跑完即结束。在线任务如果只用裸 Pod,restartPolicy 默认是 Always,容器异常退出后会被拉起;但 Pod 被删除、节点宕机时,容器级策略无法补救,实例会直接消失。需要多副本时,数量、健康和更新也只能靠人工维护。
处理方式仍然是对象组合:Pod 只负责容器,在线业务再套一层控制器。这一层有两种,调度策略不同:
- Deployment:在集群中维持 N 个相同副本,不指定必须落在哪台机器。Nginx、WordPress 这类业务用它。
- DaemonSet:每个节点恰好运行一个 Pod,与节点绑定。kube-proxy、日志采集、监控代理用它。
多节点集群里,这两种差别才明显。
1. 为什么裸 Pod 不够管在线业务
容器退出,Pod 可以重启容器;Pod 本身没了,不会有对象再创建一份。误删或节点故障,服务就会中断。
多实例同样不适合手工 kubectl run。副本数量、健康检查、版本更新如果都靠人盯,等于回到手工运维。
Job 已经说明过:作业策略不要堆进 Pod,另建对象,把 Pod 当作模板嵌进去。在线业务同样再套一层,这一层就是 Deployment,简称 deploy,apiVersion 是 apps/v1。
2. Deployment:声明副本数,由集群维持
可以用命令生成样板:
1 | export out="--dry-run=client -o yaml" |
和 Job 一样有 template,里面是一份不带 apiVersion / kind 的 Pod 规格。另外多两个字段:
replicas:期望的副本数,也就是声明式的目标状态。当前为 0 时按模板创建;运行中少了一个就再补,直到数量一致。selector.matchLabels:按标签筛选要管理的 Pod,必须与template.metadata.labels相同,否则 API 校验失败。

标签写两遍看起来重复。Job 不需要这样做,是因为离线任务的 Pod 通常一次性,和该 Job 强绑定即可。在线 Pod 会长期运行,之后 Service 做负载均衡也要按标签找到它们。Deployment 并不持有 Pod,只保证带这组标签的副本数量足够。标签把组合从写死改成了弱引用。
kubectl apply 之后看两处:kubectl get deploy 看控制器,kubectl get pod 看实例。
Deployment 列表里几个数字含义不同:
- READY
2/2:当前数量 / 期望数量 - UP-TO-DATE:已更新到模板最新状态的数量
- AVAILABLE:已就绪、可对外提供服务的数量,这是更关键的指标
- AGE:对象已运行的时间
Pod 名称一般是 Deployment 名 + 模板 hash + 随机后缀。删除其中一个:
1 | kubectl delete pod ngx-dep-xxxx |
被删的 Pod 消失后,很快会再建一个,总数仍等于 YAML 中的 replicas。入门阶段所谓「永不宕机」,指的不是进程永不退出,而是副本数量会被控制器维持住。
扩容缩容可以用 kubectl scale --replicas=5 deploy ngx-dep。这是命令式操作,只改集群里正在运行的对象,YAML 文件不会同步。若要长期保持某个数量,应修改 YAML 再 apply,避免描述文件和实际状态分叉。
replicas 设为 0 也有用途:Pod 全部停止,Deployment 对象和配置仍保留,改回数字即可重新上线。下线服务时可以先缩到 0,观察一段时间再删除对象。
标签不限于 Deployment。kubectl get pod -l app=ngx-dep,或 -l 'app in (ngx, nginx, ngx-dep)',筛选规则与 selector 相同。
即使只运行一个实例,也应使用 Deployment,把 replicas 设为 1,不要再直接创建裸 Pod。滚动更新、回滚、自动伸缩放到高级篇。Deployment 默认把 Pod 视为可替换的相同副本;需要稳定身份和启动顺序的有状态应用,后面用 StatefulSet。
3. DaemonSet:每个节点运行一个 Pod
Nginx、MySQL 这类应用在哪台机器上跑通常没有差别,Deployment 就够用。它不关心 Pod 落在哪个节点,副本数是固定的,节点增减时数量不会跟着变,Pod 还可能在节点之间迁移。
另一类应用必须依附节点才有意义:
- 网络:kube-proxy,每个节点都要运行,否则无法加入集群网络
- 监控:Prometheus 一类,每个节点上报本机状态
- 日志:Fluentd,每个节点收集本机容器日志
- 安全:审计、扫描,同样需要每台一份
此时副本数应与节点数同步,而不是写死一个 N。对应对象是 DaemonSet,简称 ds,同样是 apps/v1。目标是在每个节点运行且仅运行一个 Pod,类似 Linux 的守护进程。
kubectl create 不能直接生成 DaemonSet 样板。可以先生成 Deployment,把 kind 改成 DaemonSet,再删除 replicas:
1 | kubectl create deploy redis-ds --image=redis:5-alpine $out |
YAML 结构几乎相同,关键差异是没有 replicas。selector 与 template 的标签仍需一致。

apply 之后,DaemonSet 会查询节点并在节点上创建 Pod。两节点实验里,经常只在 Worker 上看到一个实例,Master 被排除在外。按定义每个节点都应当有一份,这里对不上,原因不在 YAML 写错,而在节点上的污点。
4. 污点和容忍度
污点(taint)是 Node 的属性,用来给节点做标记,有意不和 labels 混用。容忍度(toleration)写在 Pod 上,表示可以接受哪些污点。
默认 Pod 不容忍任何污点。节点带有 NoSchedule 污点时,这类 Pod 不会被调度上去。
1 | kubectl describe node master |
这就是 Master 默认不跑业务负载的原因。kubeadm 初始化的控制面节点会带上该污点。较新版本常见 node-role.kubernetes.io/control-plane:NoSchedule,有的环境两个都在。以 kubectl describe 的实际输出为准。
若希望 DaemonSet 也在 Master 上运行,有两种做法。
修改节点:去掉污点。 影响面较大,其他原本不该上 Master 的 Pod 也可能被调度过来。
1 | kubectl taint node master node-role.kubernetes.io/master:NoSchedule- |
DaemonSet 会持续观察节点。污点去掉后,Master 上很快会多一个 Pod。
修改 Pod:增加容忍度。 节点污点保留,只允许指定 Pod 调度上去,范围更可控。
1 | tolerations: |
tolerations 属于 Pod,写在模板的 spec 里,不是 DaemonSet 独有。Job、Deployment 管理的 Pod 也可以添加,用来做更精细的调度。
NoSchedule 只阻止新的调度。节点事后才加上污点,已经在运行的 Pod 不会被驱逐;删除之后才不会再调度回来。若要驱逐已有 Pod,需要另一种效果 NoExecute。
5. 静态 Pod:由 kubelet 直接管理
DaemonSet 是集群里实现「每节点一份」最常用的方式,但不是唯一方式。静态 Pod 不经过 apiserver 和 scheduler,只由本机 kubelet 管理。YAML 默认放在节点的 /etc/kubernetes/manifests/。

kubeadm 部署的 apiserver、etcd、scheduler、controller-manager,就是这个目录里的几份 YAML。因此它们能先于集群启动:当时还没有调度器,kubelet 扫描目录后直接调用容器运行时。
kubelet 会定期检查该目录,文件增删改就会创建或删除对应容器。有特殊需求时可以使用静态 Pod,但部署完全手工、各节点各自维护,集群里没有统一的控制器。能用 DaemonSet 时不必用静态 Pod。
Flannel 本身也是 DaemonSet。有的清单不在 kube-system,而在 kube-flannel 这类命名空间,需要 kubectl get ds -A 才能看到。
6. 对照
| 需求 | 对象 | 副本如何确定 |
|---|---|---|
| 无状态在线服务,需要 N 份 | Deployment | replicas,删除后会补齐 |
| 每个节点必须有一份 | DaemonSet | 随节点数变化,没有 replicas |
| 单实例也要能自愈 | Deployment,replicas: 1 |
不要用裸 Pod |
| 临时停服务、保留配置 | Deployment,replicas: 0 |
对象仍在 |
| 允许调度到 Master | Pod 添加 tolerations | 尽量少改节点污点 |
| 控制面组件如何启动 | 静态 Pod | kubelet 读取 manifests 目录 |
写 YAML 前先分清:这份应用是「集群里要几个」,还是「每台机器都要有」。前者用 Deployment,后者用 DaemonSet。两者都嵌一套 Pod 模板,用标签选中实例。Deployment 维持的是副本数量,DaemonSet 维持的是节点覆盖。
图片来源:极客时间 《Kubernetes入门实战课》 第 18 讲《Deployment:让应用永不宕机》、第 19 讲《Daemonset:忠实可靠的看门狗》,作者 Chrono。