k8s DaemonSet 介紹與例項
我們之前說k8s中使用deployment、statefulset工作負載資源來分別維護無狀態和有狀態應用。這篇小作文我們會學習如何使用DaemonSet
來維護一個守護程序(應用)。
一、DaemonSet是什麼?
DaemonSet 是一個確保全部或者某些節點上必須執行一個 Pod的工作負載資源(守護程序),當有節點加入叢集時, 也會為他們新增一個 Pod。
下面是常用的使用案例:
- 叢集守護程序,如
Kured
、node-problem-detector
- 日誌收集守護程序,如
fluentd
、logstash
- 監控守護程序,如promethues
node-exporter
通過建立DaemonSet
二、DaemonSet 如何工作?
DaemonSet 是由控制器(controller manager)管理的 Kubernetes 工作資源物件。我們通過宣告一個想要的daemonset狀態,表明每個節點上都需要有一個特定的 Pod。協調控制迴路會比較期望狀態和當前觀察到的狀態。如果觀察到的節點沒有匹配的 Pod,DaemonSet controller將自動建立一個。可以參考之前《k8s工作流程詳解》
在這個過程包括現有節點和所有新建立的節點。不過DaemonSet 控制器建立的 Pod 會被Kubernetes 排程器忽略,即DaemonSet Pods 由 DaemonSet 控制器建立和排程。這樣帶來的兩個微妙的問題:
- Pod 行為的不一致性:正常 Pod 在被建立後等待排程時處於
Pending
狀態, DaemonSet Pods 建立後不會處於Pending
狀態下。 - Pod 搶佔行為由預設排程器處理。啟用搶佔後,DaemonSet 控制器將在不考慮 Pod 優先順序和搶佔 的情況下制定排程決策。
所以在k8s v1.12以後DaemonSet Controller 將會向 DaemonSet 的 Pod 新增 .spec.nodeAffinity
欄位,而不是 .spec.nodeName
欄位,並進一步由 kubernetes 排程器將 Pod 繫結到目標節點。如果 DaemonSet 的 Pod 已經存在了 nodeAffinity
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
daemonset pod的預設容忍規則如下:
DaemonSet 預設在每個節點上建立一個 Pod。當然也可以使用節點選擇器來限制可接受節點的數量。DaemonSet 控制器將僅在與 YAML 檔案中預定義的nodeSelector欄位匹配的節點上建立Pod。我們在下面會使用到。
三、DaemonSet例項
建立DaemonSet
我們只需要將前面deployment中的kind
調整為DaemonSet 就可以創建出一個DaemonSet守護程序
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
spec:
selector:
matchLabels:
app: my-daemon
template:
metadata:
labels:
app: my-daemon
spec:
containers:
- name: daemonset-container
image: httpd
ports:
- containerPort : 80
通過apply應用後檢視資源狀態
$ kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
my-daemonset 1 1 1 1 1 <none> 10m
由於我們minikube只有一個node 所以只建立了一個副本,在節點通過get檢視到已創建出這個daemonset pod
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
my-daemonset-97z2g 1/1 Running 0 10m
在daemonset資源狀態中可以看到NODE SELECTOR
的值為none
,顯然我們可以通過在pod模板中新增nodeSelector
使DaemonSet 控制器僅在與Node 選擇算符匹配的節點上創建出pod,接下來我們新增一個nodeSelector
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
spec:
selector:
matchLabels:
app: my-daemon
template:
metadata:
labels:
app: my-daemon
spec:
containers:
- name: daemonset-container
image: httpd
ports:
- containerPort : 80
nodeSelector:
kubernetes.io/hostname: minikube
這樣我們的pod只會在hostname為minikube的Node上建立DaemonSet守護程序的pod
$ kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
my-daemonset 1 1 1 1 1 kubernetes.io/hostname=minikube 30m
除了通過nodeSelector
來控制節點排程外,還可以通過上面提到的容忍策略即tolerations
使daemonset pod 排程到“非正常“Node。
我們可以來看一個fluentd
的官方elasticsearch daemonset
原始檔地址:fluentd-daemonset-elasticsearch.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-system
labels:
k8s-app: fluentd-logging
version: v1
spec:
selector:
matchLabels:
k8s-app: fluentd-logging
version: v1
template:
metadata:
labels:
k8s-app: fluentd-logging
version: v1
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch-logging"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SCHEME
value: "http"
# Option to configure elasticsearch plugin with self signed certs
# ================================================================
- name: FLUENT_ELASTICSEARCH_SSL_VERIFY
value: "true"
# Option to configure elasticsearch plugin with tls
# ================================================================
- name: FLUENT_ELASTICSEARCH_SSL_VERSION
value: "TLSv1_2"
# X-Pack Authentication
# =====================
- name: FLUENT_ELASTICSEARCH_USER
value: "elastic"
- name: FLUENT_ELASTICSEARCH_PASSWORD
value: "changeme"
# Logz.io Authentication
# ======================
- name: LOGZIO_TOKEN
value: "ThisIsASuperLongToken"
- name: LOGZIO_LOGTYPE
value: "kubernetes"
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
# When actual pod logs in /var/lib/docker/containers, the following lines should be used.
# - name: dockercontainerlogdirectory
# mountPath: /var/lib/docker/containers
# readOnly: true
# When actual pod logs in /var/log/pods, the following lines should be used.
- name: dockercontainerlogdirectory
mountPath: /var/log/pods
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
# When actual pod logs in /var/lib/docker/containers, the following lines should be used.
# - name: dockercontainerlogdirectory
# hostPath:
# path: /var/lib/docker/containers
# When actual pod logs in /var/log/pods, the following lines should be used.
- name: dockercontainerlogdirectory
hostPath:
path: /var/log/pods
特別之處在於,為了收集master節點上的pod日誌,將會容忍fluentd
排程到master節點。其中tolerations
如下
Daemon Pods 通訊
與 DaemonSet 中的 Pod 進行通訊的幾種模式如下:
- 推送(Push):配置 DaemonSet 中的 Pod,將更新發送到另一個服務,例如統計資料庫。
- NodeIP 和已知埠:DaemonSet 中的 Pod 可以使用
hostPort
,從而可以通過節點 IP 訪問到 Pod。客戶端能通過某種方法獲取節點 IP 列表,並且基於此也可以獲取到相應的埠。比如prometheus的node-exporter。 - DNS:建立具有相同 Pod 選擇算符的 無頭服務 通過使用
endpoints
資源或從 DNS 中檢索到多個 A 記錄來發現 DaemonSet。
DaemonSet 更新
如果節點的標籤被修改,DaemonSet 將立刻向新匹配上的節點新增 Pod, 同時刪除不匹配的節點上的 Pod。
可以刪除一個 DaemonSet。如果使用 kubectl
指定 --cascade=orphan
選項, 則 Pod 將被保留在節點上。接下來如果建立使用相同選擇算符的新 DaemonSet, 新的 DaemonSet 會收養已有的 Pod。 如果有 Pod 需要被替換,DaemonSet 會根據其 updateStrategy
來替換。
比如prometheus中的node-exporter
以上是關於k8s中的DaemonSet相關內容。
參考:
希望小作文對你有些許幫助,如果內容有誤請指正。
您可以隨意轉載、修改、釋出本文,無需經過本人同意。blog:iqsing.github.io