一文带你深入Kubernetes中的DeamonSet
写在前面学习k8s遇到整理笔记感觉不管是dev还是ops,离不开生命周期,钩子,守护进程这些,还是要看看底层的东西。DeamonSet可以理解为特殊的ReplicaSet,即确保每个节点只运行一个pod副本的podSet生命周期与集群中node节点的周期相同类似系统中的守护进程systemd等
人生真难,但不配让我认输沃金(知乎)daemonset
DaemonSet确保全部节点上运行一个Pod的副本。当有节点加入集群时,也会为他们新增一个Pod。当有节点从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。即单实例,每个节点只跑一个podDaemonSet应用场景
DaemonSet的一些典型用法:在每个Node上运行一个GlusterFS存储或者Ceph存储的Daemon进程在每个Node上运行一个日志采集程序,例如Fluentd或者Logstach。在每个Node上运行一个性能监控程序,采集该Node的运行性能数据,例如PrometheusNodeExporter,collectd,NewRelicagent或者Gangliagmond等。
一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个DaemonSet。一个稍微复杂的用法是为同一种守护进程部署多个DaemonSet;每个具有不同的标志,并且对不同硬件类型具有不同的内存、CPU要求。这句话不太懂,以后再研究下
DaemonSet的Pod调度策略与RC类似,除了使用系统内置的算法在每台Node上进行调度,也可以在Pod的定义中使用NodeSelector或NodeAffinity来指定满足条件的Node范围进行调度。
学习环境准备〔rootvms81。liruilongs。github。io〕〔ansible〕dirk8sdaemonsetcreate;mkdirdir;cddir〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlconfigcurrentcontextkubernetesadminkubernetes〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlcreatensliruilongdameonsetcreatenamespaceliruilongdameonsetcreatecreated〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlconfigsetcontext(kubectlconfigcurrentcontext)namespaceliruilongdaemonsetcreateContextkubernetesadminkubernetesmodified。kubeadm中的deamonset
使用kubeadm安装的k8s环境中是使用的DaemonSet,calico是网路相关,所有节点都需要有,kubeproxy是代理相关,用于负载均衡等操作〔rootvms81。liruilongs。github。io〕〔ansiblek8sReplicationController〕kubectlgetdsANAMESPACENAMEDESIREDCURRENTREADYUPTODATEAVAILABLENODESELECTORAGEkubesystemcaliconode33333kubernetes。iooslinux4d23hkubesystemkubeproxy33333kubernetes。iooslinux4d23h〔rootvms81。liruilongs。github。io〕〔ansiblek8sReplicationController〕Demonset的创建
这里要说明的是DaemonSet和deployment只有在kind的位置不同,可以拷贝deployment的模板进行修改apiVersion:appsv1kind:DaemonSetmetadata:creationTimestamp:nulllabels:app:myds1name:myds1spec:replicas:1selector:matchLabels:app:myds1strategy:{}template:metadata:creationTimestamp:nulllabels:app:myds1spec:containers:image:nginxname:nginxresources:{}status:{}〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlcreatedeploymentmyds1imagenginxdryrunclientoyamldeamonset。yaml〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕vimdeamonset。yaml
我们创建一个deamonset,当前只有master节点和一个node节点正常工作
因为master节点有污点,所以会发现这里只允许一个deamonset〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlapplyfdeamonset。yamldaemonset。appsmyds1created〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlgetnodesNAMESTATUSROLESAGEVERSIONvms81。liruilongs。github。ioReadycontrolplane,master4d22hv1。22。2vms82。liruilongs。github。ioReadynone4d22hv1。22。2vms83。liruilongs。github。ioNotReadynone4d22hv1。22。2〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlgetpodsNAMEREADYSTATUSRESTARTSAGEmyds1fbmhp11Running035s〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕节点加入集群自动新增节点pod
我们在启动一台机器,会发现,新加入的vms83。liruilongs。github。io节点自动运行一个deamonset〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlgetnodesNAMESTATUSROLESAGEVERSIONvms81。liruilongs。github。ioReadycontrolplane,master4d22hv1。22。2vms82。liruilongs。github。ioReadynone4d22hv1。22。2vms83。liruilongs。github。ioReadynone4d22hv1。22。2〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlgetpodsNAMEREADYSTATUSRESTARTSAGEmyds1prldj11Running06m13smyds1pvwm411Running010mDeamonset污点节点加入pod
下面我们从新修改deamonset资源文件,容忍有污点的节点apiVersion:appsv1kind:DaemonSetmetadata:creationTimestamp:nulllabels:app:myds1name:myds1spec:replicas:1selector:matchLabels:app:myds1strategy:{}template:metadata:creationTimestamp:nulllabels:app:myds1spec:terminationGracePeriodSeconds:0tolerations:operator:Existscontainers:image:nginxname:nginxresources:{}status:{}〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlapplyfdeamonsettaint。yamldaemonset。appsmyds1created〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlgetpodsNAMEREADYSTATUSRESTARTSAGEmyds18tsnz01ContainerCreating03smyds19l6d901ContainerCreating03smyds1wz44b01ContainerCreating03s
会发现每个节点都运行一个deamontset相关的pod〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectldescribenodesvms81。liruilongs。github。iogrepTaintTaints:noderole。kubernetes。iomaster:NoSchedule〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlrunpod1imagenginxdryrunserveroyamlgrepA6terminationGracePeriodSecondsterminationGracePeriodSeconds:30tolerations:effect:NoExecutekey:node。kubernetes。ionotreadyoperator:ExiststolerationSeconds:300effect:NoExecute
当然,如果我们不想所以有污点的节点都运行deamonset相关pod,那么我们可以使用另一种指定kye的方式apiVersion:appsv1kind:DaemonSetmetadata:creationTimestamp:nulllabels:app:myds1name:myds1spec:selector:matchLabels:app:myds1template:metadata:creationTimestamp:nulllabels:app:myds1spec:terminationGracePeriodSeconds:0tolerations:operator:Existskey:noderole。kubernetes。iomastereffect:NoSchedulecontainers:image:nginxname:nginxresources:{}
会发现deamonset可以运行在master和node节点〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlapplyfdeamonsetaint。yamldaemonset。appsmyds1created〔rootvms81。liruilongs。github。io〕〔ansiblek8sdaemonsetcreate〕kubectlgetpodsNAMEREADYSTATUSRESTARTSAGEmyds1f7hbb01ContainerCreating04smyds1hksp901ContainerCreating04smyds1nnmzp01ContainerCreating04sDaemonPods是如何被调度的
DaemonSet确保所有符合条件的节点都运行该Pod的一个副本。通常,运行Pod的节点由Kubernetes调度器选择。不过,DaemonSetPods由DaemonSet控制器创建和调度。这就带来了以下问题:
Pod行为的不一致性:正常Pod在被创建后等待调度时处于Pending状态,DaemonSetPods创建后不会处于Pending状态下。
Pod抢占由默认调度器处理。启用抢占后,DaemonSet控制器将在不考虑Pod优先级和抢占的情况下制定调度决策。这里的默认调度器即k8s中调度器。
ScheduleDaemonSetPods允许您使用默认调度器而不是DaemonSet控制器来调度DaemonSets,方法是将NodeAffinity条件而不是。spec。nodeName条件添加到DaemonSetPods。默认调度器接下来将Pod绑定到目标主机。
如果DaemonSetPod的节点亲和性配置已存在,则被替换(原始的节点亲和性配置在选择目标主机之前被考虑)。DaemonSet控制器仅在创建或修改DaemonSetPod时执行这些操作,并且不会更改DaemonSet的spec。template。nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:matchFields:key:metadata。nameoperator:Invalues:targethostname与DaemonPods通信
DaemonSet中的Pod进行通信的几种可能模式如下:
推送(Push):配置DaemonSet中的Pod,将更新发送到另一个服务,例如统计数据库。这些服务没有客户端。
NodeIP和已知端口:DaemonSet中的Pod可以使用hostPort,从而可以通过节点IP访问到Pod。客户端能通过某种方法获取节点IP列表,并且基于此也可以获取到相应的端口。
DNS:创建具有相同Pod选择算符的无头服务,通过使用endpoints资源或从DNS中检索到多个A记录来发现DaemonSet。
Service:创建具有相同Pod选择算符的服务,并使用该服务随机访问到某个节点上的守护进程(没有办法访问到特定节点)。更新DaemonSet
如果节点的标签被修改,DaemonSet将立刻向新匹配上的节点添加Pod,同时删除不匹配的节点上的Pod。你可以修改DaemonSet创建的Pod。不过并非Pod的所有字段都可更新。下次当某节点(即使具有相同的名称)被创建时,DaemonSet控制器还会使用最初的模板。
你可以修改DaemonSet创建的Pod。不过并非Pod的所有字段都可更新。下次当某节点(即使具有相同的名称)被创建时,DaemonSet控制器还会使用最初的模板。
您可以删除一个DaemonSet。如果使用kubectl并指定cascadeorphan选项,则Pod将被保留在节点上。接下来如果创建使用相同选择算符的新DaemonSet,新的DaemonSet会收养已有的Pod。如果有Pod需要被替换,DaemonSet会根据其updateStrategy来替换。DaemonSet的替代方案init脚本
直接在节点上启动守护进程(例如使用init、upstartd或systemd)的做法当然是可行的。不过,基于DaemonSet来运行这些进程有如下一些好处:像所运行的其他应用一样,DaemonSet具备为守护进程提供监控和日志管理的能力。为守护进程和应用所使用的配置语言和工具(如Pod模板、kubectl)是相同的。在资源受限的容器中运行守护进程能够增加守护进程和应用容器的隔离性。然而,这一点也可以通过在容器中运行守护进程但却不在Pod中运行之来实现。例如,直接基于Docker启动。裸Pod
直接创建Pod并指定其运行在特定的节点上也是可以的。然而,DaemonSet能够替换由于任何原因(例如节点失败、例行节点维护、内核升级)而被删除或终止的Pod。由于这个原因,你应该使用DaemonSet而不是单独创建Pod。静态Pod
通过在一个指定的、受kubelet监视的目录下编写文件来创建Pod也是可行的。这类Pod被称为静态Pod。不像DaemonSet,静态Pod不受kubectl和其它KubernetesAPI客户端管理。静态Pod不依赖于API服务器,这使得它们在启动引导新集群的情况下非常有用。此外,静态Pod在将来可能会被废弃。Deployments
DaemonSet与Deployments非常类似,它们都能创建Pod,并且Pod中的进程都不希望被终止(例如,Web服务器、存储服务器)。建议为无状态的服务使用Deployments,比如前端服务。对这些服务而言,对副本的数量进行扩缩容、平滑升级,比精确控制Pod运行在某个主机上要重要得多。当需要Pod副本总是运行在全部或特定主机上,并且当该DaemonSet提供了节点级别的功能(允许其他Pod在该特定节点上正确运行)时,应该使用DaemonSet。
例如,网络插件通常包含一个以DaemonSet运行的组件。这个DaemonSet组件确保它所在的节点的集群网络正常工作〔rootvms81。liruilongs。github。io〕〔ansiblek8sReplicationController〕kubectlgetdsANAMESPACENAMEDESIREDCURRENTREADYUPTODATEAVAILABLENODESELECTORAGEkubesystemcaliconode33333kubernetes。iooslinux4d23hkubesystemkubeproxy33333kubernetes。iooslinux4d23h〔rootvms81。liruilongs。github。io〕〔ansiblek8sReplicationController〕