背景node
靜兒做爲美團容器化團隊HULK的一員,常常須要和Kubernetes(k8s)打交道。第一次登錄node(宿主機)的時候,發現連續登錄幾臺都看到了Prometheus-Node-Exporter字樣的docker進程。他們和普通的Pod(容器)同樣,佔用IP等資源,佔用宿主機容許的pod數上限。後來經過看書瞭解到這是DaemonSet控制管理的Pod.docker
DaemonSet官方文檔譯文api
一個DaemonSet確保了全部的node上僅有一個的Pod的一個實例。當node被添加到集羣中,Pod也被添加上去。當node被從集羣移除,這些Pod會被垃圾回收。刪除一個DaemonSet將會清理它建立的Pod。ruby
舉一些DaemonSet典型用法的例子:app
在每一個node上運行一個集羣存儲守護進程,例如glusterd、cephelasticsearch
在每一個node上運行一個日誌集合,例如fuentd或者logstash學習
在每一個node上運行一個node監控後臺線程,例如Prometheus Node Exporter,collectd,Dynatrace OneAgent,AppDynamics Agent,Datadog agent,New Relic agent,Ganglia gmod 或者Instana agent.測試
在一種簡單的場合下,一個DeamonSet會被使用在任意種後臺線程、覆蓋全部的node。在更復雜的安裝方式中,多個DaemonSet會被用於一種後臺線程。可是在不一樣的硬件類型會對應不一樣的標識或者不一樣的內存和CPU請求。ui
在YAML文件中生命一個DaemonSet。daemonset.yaml文件描述了一個運行着fluentd-elasticsearch的docker鏡像的DaemonSet。spa
controllers/daemonset.yaml
apiVersion: apps/v1kind: DaemonSetmetadata:spec: path: /var/lib/docker/containers
建立一個基於YAML文件的DaemonSet
kubectl create -f https://k8s.io/examples/controllers/daemonset.yaml
和其餘的Kubernetes配置文件同樣,一個DaemonSet須要apiVersion,kind和metadata字段。配置文件的通用信息,能夠看deploying application,configuring containers和object management using kubectl文檔。
一個DaemonSet也須要一個spec區
.spec.template是.spec的必需字段。
.spec.template是一個pod模板。除了是嵌套的而且沒有apiVersion或者kind以外,它的schema和pod是同樣的。
除了pod必需的字段,在DaemonSet中的pod模板必需指定合適的label(詳見pod selector)。
在DaemonSet中的pod模板必須要有一個Always的RestartPolicy。若是沒有明確指定,默認也是Aways。
.spec.selector字段是pod的選擇器。它的功能和job的.spec.selector同樣。
在Kubernetes1.8中,必需指定一個帶有.spec.template的pod選擇器。當pod選擇器爲空時將不會再是默認的選擇器。選擇器默認和kubectl apply是不兼容的。一旦DaemonSet被建立,.spec.selector就不能變了。一旦改變了pod選擇器,可能會致使意外將這個pod變成「孤島」。用戶會很迷惑。
.spec.selector是有兩個字段組成的對象:
matchLabels - 和ReplicationController的.spec.selector是同樣的
matchExpressions - 經過制定key、values列表、operatorl來定製更加精細的選擇器。
指定了兩個,它們的做用關係是and。
一旦.spec.selector被指定,就必須和.spec.template.metadata.labels匹配。不匹配的配置會被API拒掉。
同時,用戶平時也不該該建立匹配這些選擇器的標籤。包括直接建立、經過其餘的DaemonSet建立,或者經過其餘的像ReplicaSet這樣的控制器來建立。不然,DaemonSet控制器會認爲這些pod是本身建立的。可是若是說想手動建立一個值不一樣的pod放在node上作測試就另當別論了。
指定.spec.template.spec.nodeSelector,DaemonSet控制器會在node上建立一個匹配node選擇器的pod。同時,若是指定.spec.template.spec.affinity,這時候DaemonSet控制器會建立匹配node的affinity的pod。若是什麼二者都不指定,DaemonSet控制器將會在全部node上建立pod。
pod實際運行的設備一般是Kubernetes調度器來選擇的。可是DaemonSet控住器建立的pod是已經指定好了設備的(Pod在建立時.spec.nodeName已經被指定了,因此會被調度器忽略)。基於這個緣由:
node節點上的字段unschedulable會被DaemonSet控制器忽略。
DaemonSet控制器在調度還沒開始時就會建立Pod來幫助啓動集羣。
DaemonSet確保全部有資格的node運行一個pod的一個實例。通常來講,Kubernetes控制器決定了一個Pod選擇哪一個node。可是DaemonSet控制器卻負責建立和調度DaemonSet的pod。這引入了下面的問題:
不一致的Pod行爲:普通Pod會以Pending狀態建立出來等待調度。可是DaemonSet的Pod的初始狀態卻不是Pending。這讓用戶很疑惑。
默認調度器處理Pod優先權(Pod preemption)。當preemption被啓用,DaemonSet控制器在作調度決策時就不考慮pod優先權。
ScheduleDaemonSetPods容許你使用默認調度器而不是DaemonSet控制器來調度。這是經過添加NodeAffinity項而不是.spec.nodeName到DaemonSet的Pod來實現的。默認調度被應用於綁定pod到目標宿主機。DaemonSet Pod的node affinity已經存在時會被替換。DaemonSet控制器只在建立或者修改DaemonSet Pod時纔會這樣。不會修改DaemonSet的spec.template。
nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: operator: In values:
Daemon Pod支持污點和容忍。下面的容忍會根據相應的特性被自動添加到DaemonSet。
總結
初學一個技術若是感受沒法下手,學了也記不住的趕腳。不如先從一個問題出發:爲何會有這個Pod存在?這樣先進行感知再系統學習。
相關閱讀