一、什么是DaemonSet?

在Kubernetes的世界里,DaemonSet就像是一个勤劳的小蜜蜂,它会在集群的每个节点上自动部署和维护一个Pod副本。不管你是新增节点还是删除节点,它都会默默地把工作做到位。这种特性特别适合那些需要在每个节点上运行的服务,比如日志收集、监控代理或者网络插件。

举个例子,想象一下你有一个10个节点的集群,需要在每个节点上部署一个日志收集器。如果手动操作,你得在每个节点上跑一遍部署命令,累不累?而用DaemonSet,只需要一个配置文件,Kubernetes就会帮你搞定所有节点。

二、为什么需要DaemonSet?

你可能要问,Deployment不也能部署应用吗?为啥还要DaemonSet?这里的关键区别在于部署的粒度。Deployment关注的是"我要跑多少个Pod",而DaemonSet关注的是"我要在每个节点上跑一个Pod"。

典型的应用场景包括:

  1. 日志收集:比如Fluentd或者Filebeat,需要在每个节点上收集容器日志
  2. 监控代理:比如Prometheus的node-exporter,需要采集每个节点的监控数据
  3. 网络插件:比如Calico或者Flannel的网络组件
  4. 存储插件:比如ceph或者glusterfs的客户端

三、DaemonSet实战示例

下面我们用一个完整的例子来演示如何部署一个日志收集Agent。这里我们选择Fluentd作为技术栈,因为它是最流行的日志收集工具之一。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.12-debian-elasticsearch7-1
        env:
          - name: FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch-logging"
          - name: FLUENT_ELASTICSEARCH_PORT
            value: "9200"
        resources:
          limits:
            memory: 500Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

这个配置做了几件重要的事情:

  1. 定义了一个DaemonSet,确保每个节点上都会运行一个Fluentd Pod
  2. 配置了Fluentd将日志发送到Elasticsearch
  3. 挂载了宿主机的/var/log和/var/lib/docker/containers目录,这样Fluentd就能访问到容器日志
  4. 设置了资源限制,避免Fluentd占用过多资源
  5. 添加了容忍度(toleration),让Fluentd也能在master节点上运行

四、DaemonSet的高级配置

除了基本配置,DaemonSet还有一些高级用法值得了解:

4.1 节点选择器

你可以通过nodeSelector限制DaemonSet只在特定节点上运行。比如,你有一些专门用于日志处理的节点,可以这样配置:

spec:
  template:
    spec:
      nodeSelector:
        logging: "true"

4.2 更新策略

DaemonSet支持两种更新策略:

  1. RollingUpdate(默认):逐步更新Pod,确保服务不中断
  2. OnDelete:只有手动删除旧Pod时才会创建新Pod

配置方法:

spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1

4.3 资源限制

给DaemonSet设置合理的资源限制很重要,特别是当它在每个节点上都运行时:

resources:
  limits:
    cpu: "1"
    memory: "500Mi"
  requests:
    cpu: "100m"
    memory: "200Mi"

五、DaemonSet的优缺点

5.1 优点

  1. 自动化部署:无需手动在每个节点上部署
  2. 自愈能力:如果Pod挂了,Kubernetes会自动重新创建
  3. 节点感知:新增节点时会自动部署,节点移除时会自动清理
  4. 配置统一:所有节点使用相同的配置

5.2 缺点

  1. 资源占用:每个节点都运行一个实例,可能占用较多资源
  2. 配置灵活性:所有实例配置相同,难以针对特定节点做定制
  3. 启动顺序:无法控制Pod的启动顺序

六、使用注意事项

  1. 资源监控:因为DaemonSet在每个节点都运行,要特别注意资源使用情况
  2. 版本升级:大规模集群中,DaemonSet的滚动更新可能需要较长时间
  3. 节点污点:如果节点有污点(taint),记得配置相应的容忍度(toleration)
  4. 存储卷:使用hostPath挂载宿主机目录时要注意权限问题
  5. 网络:如果Pod需要特殊网络配置,要确保节点网络环境支持

七、实际应用案例

让我们看一个更复杂的例子,部署一个监控Agent(使用Prometheus的node-exporter):

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    app: node-exporter
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '9100'
    spec:
      hostNetwork: true
      hostPID: true
      containers:
      - name: node-exporter
        image: prom/node-exporter:v1.3.1
        args:
        - --path.procfs=/host/proc
        - --path.sysfs=/host/sys
        - --collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($|/)
        ports:
        - containerPort: 9100
          hostPort: 9100
          name: scrape
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
          limits:
            cpu: 200m
            memory: 200Mi
        volumeMounts:
        - name: proc
          mountPath: /host/proc
        - name: sys
          mountPath: /host/sys
        - name: root
          mountPath: /host/root
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: sys
        hostPath:
          path: /sys
      - name: root
        hostPath:
          path: /
      tolerations:
      - effect: NoSchedule
        operator: Exists

这个配置有几个亮点:

  1. 使用hostNetwork让Pod共享节点网络命名空间
  2. 挂载了/proc和/sys等系统目录,让node-exporter能采集系统指标
  3. 添加了资源限制,避免占用过多资源
  4. 配置了容忍度,确保能在所有节点上运行
  5. 添加了Prometheus的注解,方便自动发现

八、常见问题排查

当DaemonSet不工作时,可以按照以下步骤排查:

  1. 检查DaemonSet状态:

    kubectl get daemonset -n <namespace>
    
  2. 查看未调度Pod:

    kubectl get pods -n <namespace> -o wide
    
  3. 检查Pod事件:

    kubectl describe pod <pod-name> -n <namespace>
    
  4. 查看Pod日志:

    kubectl logs <pod-name> -n <namespace>
    
  5. 检查节点资源:

    kubectl describe node <node-name>
    

常见问题包括:

  • 资源不足
  • 镜像拉取失败
  • 节点有污点但没配置容忍度
  • 挂载点权限问题
  • 网络策略限制

九、总结

DaemonSet是Kubernetes中一个非常实用的资源类型,特别适合那些需要在每个节点上运行的服务。通过本文的介绍,你应该已经掌握了:

  1. DaemonSet的基本概念和工作原理
  2. 如何编写DaemonSet的配置文件
  3. 实际应用场景和配置技巧
  4. 常见问题排查方法

记住,虽然DaemonSet很强大,但也要合理使用。不是所有场景都需要DaemonSet,对于不需要在每个节点上运行的服务,使用Deployment可能更合适。

最后,DaemonSet是Kubernetes生态中不可或缺的一部分,掌握它能让你的集群管理更加得心应手。希望这篇文章能帮助你在实际工作中更好地使用DaemonSet!