本文是對 Kubernetes 作業管理中的容器化守護進程相關設計的理解,由於 DaemonSet 這個知識點相對較爲容易理解,所以主要是作的張磊在極客時間上《深入剖析 Kubernetes》課程的筆記。
文章目錄
Why(爲什麼要有 DaemonSet)
使用場景:
- 各種網絡插件的 Agent 組件,都必須運行在每一個節點上,用來處理這個節點上的容器網絡;
- 各種存儲插件的 Agent 組件,也必須運行在每一個節點上,用來在這個節點上掛載遠程存儲目錄,操作容器的 Volume 目錄;
- 各種監控組件和日誌組件,也必須運行在每一個節點上,負責這個節點上的監控信息和日誌蒐集。
What(DaemonSet 是什麼)
一句話:在 Kubernetes 集羣中的每一個節點中運行一個 Daemon Pod。
How(DaemonSet 如何保證每個 Node 上有且只有一個被管理的 Pod)
DaemonSet 會保證每個 Node 上有且只有一個被管理的 Pod,是利用“控制器模型”原理實現。
原理: DaemonSet Controller,首先從 Etcd 裏獲取所有的 Node 列表,然後遍歷所有的 Node。這時,它就可以很容易地去檢查,當前這個 Node 上是不是有一個攜帶了指定標籤的 Pod 在運行。有多餘 Pod 的話就調用 Kubernetes API 刪除;沒有這種 Pod 的話就利用 Pod 來創建一個。
有2個點:
DaemonSet Controller 會在創建 Pod 的時候,自動在這個 Pod 的 API 對象裏,加上一個 nodeAffinity 定義。其中,需要綁定的節點名字,正是當前正在遍歷的這個 Node。
此外,DaemonSet 還會給這個 Pod 自動加上另外一個與調度相關的字段,叫作 tolerations。這個字段意味着這個 Pod,會“容忍”(Toleration)某些 Node 的“污點”(Taint)。
具體可以看最後的“使用實例”。
另外,DaemonSet 控制器操作的直接就是 Pod,沒有 ReplicaSet 這樣的對象參與其中,所以,它的版本維護是使用 API 對象的方式實現,名爲 ControllerRevision。
這個 ControllerRevision 對象,實際上會保存某一版本對應的完整的 DaemonSet 的 API 對象。並且,在 Annotation 字段保存了創建這個對象所使用的 kubectl 命令。
DaemonSet Controller 回滾版本實際上就是使用這個歷史 API 對象,對現有的 DaemonSet 做一次 PATCH 操作(等價於執行一次 kubectl apply -f “舊的 DaemonSet 對象”)
使用實例
實例:部署一個 DaemonSet 管理 fluentd-elasticsearch 鏡像的 Pod。通過 fluentd 將 Docker 容器裏的日誌轉發到 ElasticSearch 中。
1、創建 DaemonSet 對象
$ kubectl create -f fluentd-elasticsearch.yaml
實際過程分爲2步:
(1)用戶提交 YAML
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector: # 使用 selector 選擇管理所有攜帶了 name=fluentd-elasticsearch 標籤的 Pod
matchLabels:
name: fluentd-elasticsearch
template: # 這些 Pod 的模板,也是用 template 字段定義的
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations: # 爲了能在 Master 節點上部署 DaemonSet 的 Pod,我就必須讓這個 Pod“容忍”這個“污點”
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd-elasticsearch # 管理的是一個 fluentd-elasticsearch 鏡像的 Pod
image: k8s.gcr.io/fluentd-elasticsearch:1.20 # 定義了一個使用 fluentd-elasticsearch:1.20 鏡像的容器
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts: # 這個容器掛載了兩個 hostPath 類型的 Volume,分別對應宿主機的 /var/log 目錄和 /var/lib/docker/containers 目錄
- 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
(2)Daemon Controller 自動補充 YAML
- 補充 nodeAffinity:是 Pod 裏跟調度相關的一個字段
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 這個 nodeAffinity 必須在每次調度的時候予以考慮
nodeSelectorTerms:
- matchExpressions: # 這個 Pod,將來只允許運行在“metadata.name”是“node-geektime”的節點上
- key: metadata.name
operator: In
values:
- node-geektime
- 補充 tolerations :這個字段意味着這個 Pod,會“容忍”(Toleration)某些 Node 的“污點”(Taint)
apiVersion: v1
kind: Pod
metadata:
name: with-toleration
spec:
tolerations:
- key: node.kubernetes.io/unschedulable # “容忍”所有被標記爲 unschedulable“污點”的 Node;“容忍”的效果是允許調度。
operator: Exists
effect: NoSchedule
2、查看 DaemonSet 對象 及相關對象
$ kubectl get pod -n kube-system -l name=fluentd-elasticsearch
NAME READY STATUS RESTARTS AGE
fluentd-elasticsearch-dqfv9 1/1 Running 0 53m
fluentd-elasticsearch-pf9z5 1/1 Running 0 53m
$ kubectl get ds -n kube-system fluentd-elasticsearch
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
fluentd-elasticsearch 2 2 2 2 2 <none> 1h
3、版本管理
# 查看版本情況
$ kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
daemonsets "fluentd-elasticsearch"
REVISION CHANGE-CAUSE
1 <none>
# 升級鏡像
$ kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record -n=kube-system
# 查看“滾動更新”的過程
$ kubectl rollout status ds/fluentd-elasticsearch -n kube-system
Waiting for daemon set "fluentd-elasticsearch" rollout to finish: 0 out of 2 new pods have been updated...
Waiting for daemon set "fluentd-elasticsearch" rollout to finish: 0 out of 2 new pods have been updated...
Waiting for daemon set "fluentd-elasticsearch" rollout to finish: 1 of 2 updated pods are available...
daemon set "fluentd-elasticsearch" successfully rolled out
# 在升級命令後面加上了–record 參數,使用到的指令就會自動出現在 DaemonSet 的 rollout history 裏面
$ kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
daemonsets "fluentd-elasticsearch"
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --namespace=kube-system --record=true
# 以 ControllerRevision 方式查看版本
$ kubectl get controllerrevision -n kube-system -l name=fluentd-elasticsearch
NAME CONTROLLER REVISION AGE
fluentd-elasticsearch-64dc6799c9 daemonset.apps/fluentd-elasticsearch 2 1h
# 查看某個 ControllerRevision 對象版本詳細信息
$ kubectl describe controllerrevision fluentd-elasticsearch-64dc6799c9 -n kube-system
Name: fluentd-elasticsearch-64dc6799c9
Namespace: kube-system
Labels: controller-revision-hash=2087235575
name=fluentd-elasticsearch
Annotations: deprecated.daemonset.template.generation=2
kubernetes.io/change-cause=kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record=true --namespace=kube-system
API Version: apps/v1
Data:
Spec:
Template:
$ Patch: replace
Metadata:
Creation Timestamp: <nil>
Labels:
Name: fluentd-elasticsearch
Spec:
Containers:
Image: k8s.gcr.io/fluentd-elasticsearch:v2.2.0
Image Pull Policy: IfNotPresent
Name: fluentd-elasticsearch
...
Revision: 2
Events: <none>
# 回滾到 Revision=1 時的狀態
$ kubectl rollout undo daemonset fluentd-elasticsearch --to-revision=1 -n kube-system
daemonset.extensions/fluentd-elasticsearch rolled back
參考:
《深入剖析Kubernetes | 極客時間》張磊,容器編排和Kubernetes作業管理 21