直接创建 Pod 无法实现自愈、扩缩容、滚动更新等生产级需求。Kubernetes 通过控制器(Controller)来管理 Pod 的生命周期。本文深入讲解三种最常用的控制器:Deployment(无状态应用)、StatefulSet(有状态应用)和 DaemonSet(节点守护进程),并通过 YAML 示例和实操命令展示它们的典型用法。

一、为什么需要控制器?
裸 Pod 的局限性:

节点故障时不会自动重新调度。

不会维持副本数量(意外删除即丢失)。

无法实现滚动更新和回滚。

难以水平伸缩。

控制器通过控制循环持续监听实际状态与期望状态,并进行调谐(Reconcile)。你只需声明期望的 Pod 数量、更新策略等,控制器就会帮你达成。

二、Deployment:无状态应用的首选
Deployment 用于管理无状态应用,提供副本管理、滚动更新、回滚、扩容缩容等能力。它通过 ReplicaSet 来管理 Pod。

2.1 典型 YAML 示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

关键字段:

replicas:期望的 Pod 副本数。

selector:Deployment 管理的 Pod 标签选择器(必须与 template.metadata.labels 匹配)。

template:Pod 模板,定义 Pod 的具体规格。

strategy:更新策略(RollingUpdate 或 Recreate)。

2.2 常用操作

# 创建 Deployment
kubectl apply -f nginx-deploy.yaml

# 查看 Deployment 和 ReplicaSet 状态
kubectl get deploy,rs,po -l app=nginx

# 滚动更新镜像
kubectl set image deployment/nginx-deploy nginx=nginx:1.26

# 查看滚动更新状态
kubectl rollout status deployment/nginx-deploy

# 查看历史版本
kubectl rollout history deployment/nginx-deploy

# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deploy

# 回滚到指定版本
kubectl rollout undo deployment/nginx-deploy --to-revision=2

# 扩容到 5 个副本
kubectl scale deployment/nginx-deploy --replicas=5

# 暂停更新(便于多次修改后一次性触发)
kubectl rollout pause deployment/nginx-deploy

# 恢复更新
kubectl rollout resume deployment/nginx-deploy

2.3 滚动更新策略解析
maxSurge:滚动更新期间,最多可以超出期望副本数的 Pod 数量(可以是绝对值或百分比)。

maxUnavailable:最多可以有多少个 Pod 处于不可用状态(绝对值或百分比)。

例:replicas=3, maxSurge=1, maxUnavailable=0 表示更新时最多有 4 个 Pod(3+1),且至少有 3 个可用。会先启动一个新 Pod,等新 Pod Ready 后再删除一个旧 Pod,循环直至全部更新。

三、StatefulSet:有状态应用的守护者
StatefulSet 用于管理有状态应用(如数据库、消息队列、分布式存储)。它提供:

稳定的网络标识:Pod 名称固定(如 mysql-0, mysql-1),顺序启动、倒序终止。

稳定的持久化存储:每个 Pod 关联独立的 PVC(卷声明),删除 Pod 后卷保留。

有序部署与扩展:从 0 到 N-1 依次创建,缩容时从大到小删除。

3.1 典型 YAML 示例(MySQL 主从简化版)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-svc        # 必须引用一个 Headless Service
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "123456"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

关键点:

serviceName:必须引用一个 Headless Service(clusterIP: None),用于提供稳定的 DNS 名称:...svc.cluster.local。

volumeClaimTemplates:每个 Pod 自动创建独立的 PVC(如 data-mysql-0, data-mysql-1),删除 StatefulSet 时 PVC 默认保留,需要手动清理。

3.2 常用操作

# 创建 StatefulSet 及关联 Service
kubectl apply -f mysql-sts.yaml

# 查看 Pod 创建顺序(依次启动)
kubectl get pods -w -l app=mysql

# 删除 StatefulSet(保留 PVC)
kubectl delete statefulset mysql --cascade=orphan

# 重新创建 StatefulSet 会复用原 PVC

3.3 适用场景
数据库:MySQL、PostgreSQL、MongoDB(需配合 Operator 更佳)。

消息队列:Kafka、RabbitMQ。

分布式存储:Elasticsearch、ZooKeeper、etcd。

注意:StatefulSet 并不解决数据备份、自动故障转移等数据库自身问题,这些需要借助 Operator 或应用自身能力。

四、DaemonSet:每个节点一个 Pod
DaemonSet 确保在集群的每个(或部分)节点上运行一个 Pod 副本。节点加入时自动添加 Pod,节点删除时 Pod 被回收。常用于:

日志收集(Fluentd、Filebeat)

监控代理(Prometheus Node Exporter、Datadog agent)

网络插件(Calico、Flannel 的 agent 部分)

存储插件(CSI 节点服务)

4.1 典型 YAML 示例(Node Exporter)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      hostNetwork: true          # 使用宿主机网络
      hostPID: true              # 使用宿主机 PID 命名空间
      containers:
      - name: node-exporter
        image: prom/node-exporter:latest
        args:
        - --path.procfs=/host/proc
        - --path.sysfs=/host/sys
        volumeMounts:
        - name: proc
          mountPath: /host/proc
          readOnly: true
        - name: sys
          mountPath: /host/sys
          readOnly: true
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: sys
        hostPath:
          path: /sys

4.2 控制 DaemonSet 仅在部分节点运行
通过 nodeSelector 或亲和性限制:

spec:
  template:
    spec:
      nodeSelector:
        disktype: ssd            # 只调度到标记为 ssd 的节点

4.3 常用操作

# 查看 DaemonSet 和其管理的 Pod
kubectl get ds,po -l app=node-exporter

# 更新 DaemonSet(镜像升级)
kubectl set image ds/node-exporter node-exporter=prom/node-exporter:v1.5.0

# 回滚
kubectl rollout undo ds/node-exporter

五、三种控制器的对比总结
特性	Deployment	StatefulSet	DaemonSet
Pod 名称	随机哈希	有序号(-0, -1, ...)	随机哈希
存储	可共享卷	每个 Pod 独立 PVC	通常使用 hostPath 或临时卷
网络标识	无状态,通过 Service 访问	每个 Pod 有稳定 DNS 名称	通过节点 IP + hostPort 访问
更新策略	滚动更新、Recreate	滚动更新(按序号逆序)	RollingUpdate、OnDelete
扩缩容	任意数量	有序扩缩容	跟随节点数自动变化
典型应用	Web、API、微服务	数据库、消息队列	日志、监控、网络插件

六、最佳实践
无状态应用优先使用 Deployment,简单且功能完善。

有状态应用评估是否真的需要 StatefulSet:如果不需要稳定的网络标识和独立存储,Deployment 也可挂载共享存储(但一般不推荐)。

DaemonSet 的更新策略:通常使用 RollingUpdate,避免日志收集中断。

资源限制:为所有容器设置 requests/limits,特别是 DaemonSet,防止耗尽节点资源。

避免在 StatefulSet 中直接存储大量数据:建议使用外部数据库服务或云存储。

七、小结
Deployment、StatefulSet、DaemonSet 覆盖了大多数工作负载类型。掌握它们的特性,可以合理选择控制器,构建高可用的应用。实际生产中,Deployment 使用最频繁,StatefulSet 用于核心有状态服务,DaemonSet 用于节点级基础设施。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐