天天看點

應用編排與管理:Job & DaemonSet

本節課程要點

  1. Job & CronJobs 基礎操作與概念解析;
  2. DaemonSet 基礎操作與概念解析。

Job

需求來源

Job 背景問題

首先我們來看一下 Job 的需求來源。我們知道 K8s 裡面,最小的排程單元是 Pod,我們可以直接通過 Pod 來運作任務程序。這樣做将會産生以下幾種問題:

  • 我們如何保證 Pod 内程序正确的結束?
  • 如何保證程序運作失敗後重試?
  • 如何管理多個任務,且任務之間有依賴關系?
  • 如何并行地運作任務,并管理任務的隊列大小?

Job:管理任務的控制器

我們來看一下 Kubernetes 的 Job 為我們提供了什麼功能:

  • 首先 kubernetes 的 Job 是一個管理任務的控制器,它可以建立一個或多個 Pod 來指定 Pod 的數量,并可以監控它是否成功地運作或終止;
  • 我們可以根據 Pod 的狀态來給 Job 設定重置的方式及重試的次數;
  • 我們還可以根據依賴關系,保證上一個任務運作完成之後再運作下一個任務;
  • 同時還可以控制任務的并行度,根據并行度來確定 Pod 運作過程中的并行次數和總體完成大小。

用例解讀

我們根據一個執行個體來看一下Job是如何來完成下面的應用的。

Job 文法

應用編排與管理:Job & DaemonSet

上圖是 Job 最簡單的一個 yaml 格式,這裡主要新引入了一個 kind 叫 Job,這個 Job 其實就是 job-controller 裡面的一種類型。 然後 metadata 裡面的 name 來指定這個 Job 的名稱,下面 spec.template 裡面其實就是 pod 的 spec。

這裡面的内容都是一樣的,唯一多了兩個點:

  • 第一個是 restartPolicy,在 Job 裡面我們可以設定 Never、OnFailure、Always 這三種重試政策。在希望 Job 需要重新運作的時候,我們可以用 Never;希望在失敗的時候再運作,再重試可以用 OnFailure;或者不論什麼情況下都重新運作時 Alway;
  • 另外,Job 在運作的時候不可能去無限的重試,是以我們需要一個參數來控制重試的次數。這個 backoffLimit 就是來保證一個 Job 到底能重試多少次。

是以在 Job 裡面,我們主要重點關注的一個是 restartPolicy 重新開機政策和 backoffLimit 重試次數限制。

Job 狀态

應用編排與管理:Job & DaemonSet

Job 建立完成之後,我們就可以通過 kubectl get jobs 這個指令,來檢視目前 job 的運作狀态。得到的值裡面,基本就有 Job 的名稱、目前完成了多少個 Pod,進行多長時間。

AGE的含義是指這個 Pod 從目前時間算起,減去它當時建立的時間。這個時長主要用來告訴你 Pod 的曆史、Pod 距今建立了多長時間。

DURATION主要來看我們 Job 裡面的實際業務到底運作了多長時間,當我們的性能調優的時候,這個參數會非常的有用。COMPLETIONS主要來看我們任務裡面這個 Pod 一共有幾個,然後它其中完成了多少個狀态,會在這個字段裡面做顯示。

檢視 Pod

下面我們來看一下 Pod,其實 Job 最後的執行單元還是 Pod。我們剛才建立的 Job 會建立出來一個叫“pi”的一個 Pod,這個任務就是來計算這個圓周率,Pod 的名稱會以“${job-name}-${random-suffix}”,我們可以看一下下面 Pod 的 yaml 格式。

應用編排與管理:Job & DaemonSet

它比普通的 Pod 多了一個叫 ownerReferences,這個東西來聲明此 pod 是歸哪個上一層 controller 來管理。可以看到這裡的 ownerReferences 是歸 batch/v1,也就是上一個 Job 來管理的。這裡就聲明了它的 controller 是誰,然後可以通過 pod 返查到它的控制器是誰,同時也能根據 Job 來查一下它下屬有哪些 Pod。

并行運作 Job

我們有時候有些需求:希望 Job 運作的時候可以最大化的并行,并行出 n 個 Pod 去快速地執行。同時,由于我們的節點數有限制,可能也不希望同時并行的 Pod 數過多,有那麼一個管道的概念,我們可以希望最大的并行度是多少,Job 控制器都可以幫我們來做到。

這裡主要看兩個參數:一個是 completions,一個是 parallelism。

  • 首先第一個參數是用來指定本 Pod 隊列執行次數。可能這個不是很好了解,其實可以把它認為是這個 Job 指定的可以運作的總次數。比如這裡設定成 8,即這個任務一共會被執行 8 次;
  • 第二個參數代表這個并行執行的個數。所謂并行執行的次數,其實就是一個管道或者緩沖器中緩沖隊列的大小,把它設定成 2,也就是說這個 Job 一定要執行 8 次,每次并行 2 個 Pod,這樣的話,一共會執行 4 個批次。

檢視并行 Job 運作

應用編排與管理:Job & DaemonSet

下面來看一下它的實際運作效果,上圖就是當這個 Job 整體運作完畢之後可以看到的效果,首先看到 job 的名字,然後看到它一共建立出來了 8 個 pod,執行了 2 分 23 秒,這是建立的時間。

接着來看真正的 pods,pods 總共出來了 8 個 pod,每個 pod 的狀态都是完成的,然後來看一下它的 AGE,就是時間。從下往上看,可以看到分别有 73s、40s、110s 和 2m26s。每一組都有兩個 pod 時間是相同的,即:時間段是 40s 的時候是最後一個建立、 2m26s 是第一個建立的。也就是說,總是兩個 pod 同時建立出來,并行完畢、消失,然後再建立、再運作、再完畢。

比如說,剛剛我們其實通過第二個參數來控制了目前 Job 并行執行的次數,這裡就可以了解到這個緩沖器或者說管道隊列大小的作用。

Cronjob 文法

應用編排與管理:Job & DaemonSet

下面來介紹另外一個 Job,叫做 CronJob,其實也可以叫定時運作 Job。CronJob 其實和 Job 大體是相似的,唯一的不同點就是它可以設計一個時間。比如說可以定時在幾點幾分執行,特别适合晚上做一些清理任務,還有可以幾分鐘執行一次,幾小時執行一次等等,這就叫定時任務。

定時任務和 Job 相比會多幾個不同的字段:

  • schedule:schedule 這個字段主要是設定時間格式,它的時間格式和 Linux 的 crontime 是一樣的,是以直接根據 Linux 的 crontime 書寫格式來書寫就可以了。舉個例子: */1 指每分鐘去執行一下 Job,這個 Job 需要做的事情就是列印出大約時間,然後列印出“Hello from the kubernetes cluster” 這一句話;
  • startingDeadlineSeconds:即:每次運作 Job 的時候,它最長可以等多長時間,有時這個 Job 可能運作很長時間也不會啟動。是以這時,如果超過較長時間的話,CronJob 就會停止這個 Job;
  • concurrencyPolicy:就是說是否允許并行運作。所謂的并行運作就是,比如說我每分鐘執行一次,但是這個 Job 可能運作的時間特别長,假如兩分鐘才能運作成功,也就是第二個 Job 要到時間需要去運作的時候,上一個 Job 還沒完成。如果這個 policy 設定為 true 的話,那麼不管你前面的 Job 是否運作完成,每分鐘都會去執行;如果是 false,它就會等上一個 Job 運作完成之後才會運作下一個;
  • JobsHistoryLimit:這個就是每一次 CronJob 運作完之後,它都會遺留上一個 Job 的運作曆史、檢視時間。當然這個額不能是無限的,是以需要設定一下曆史存留數,一般可以設定預設 10 個或 100 個都可以,這主要取決于每個人叢集不同,然後根據每個人的叢集數來确定這個時間。

操作示範

Job 的編排檔案

下面看一下具體如何使用 Job。

應用編排與管理:Job & DaemonSet

Job 的建立及運作驗證

首先看一下 job.yaml。這是一個非常簡單的計算 pi 的一個任務。使用 kubectl creat-f job.yaml,這樣 job 就能送出成功了。來看一下 kubectl.get.jobs,可以看到這個 job 正在運作;get pods 可以看到這個 pod 應該是運作完成了,那麼接下來 logs 一下這個 job 以及 pod。可以看到下圖裡面列印出來了圓周率。

應用編排與管理:Job & DaemonSet

并行 Job 的編排檔案

下面再來看第二個例子:

應用編排與管理:Job & DaemonSet

并行 Job 的建立及運作驗證

這個例子就是指剛才的并行運作 Job 建立之後,可以看到有第二個并行的 Job。

應用編排與管理:Job & DaemonSet

現在已經有兩個 Pod 正在 running,可以看到它大概執行了快到 30s

應用編排與管理:Job & DaemonSet

30s 之後它應該會起第二個。

應用編排與管理:Job & DaemonSet

第一批的 pod 已經執行完畢,第二批的 pod 正在 running,每批次分别是兩個Pod。也就是說後面每隔 40s 左右,就會有兩個 pod 在并行執行,它一共會執行 4 批,共 8 個 pod,等到所有的 pod 執行完畢,就是剛才所說的并行執行的緩沖隊列功能。

過一段時間再看這個 pods,可以發現第二批已經執行結束,接下來開始建立第三批……

應用編排與管理:Job & DaemonSet

Cronjob 的編排檔案

下面來看第三個例子 —— CronJob。 CronJob 是每分鐘執行一次,每次一個 job。

應用編排與管理:Job & DaemonSet

Cronjob 的建立及運作驗證

如下圖 CronJob 已經建立了,可以通過 get cronjob 來看到目前有一個 CronJob,這個時候再來看 jobs,由于它是每分鐘執行一次,是以得稍微等一下。

應用編排與管理:Job & DaemonSet

同時可以看到,上一個 job 還在運作,它的時間是 2m12s 左右,它的完成度是 7/8、6/8,剛剛看到 7/8 到 8/8,也就是說我們上一個任務執行了最後一步,而且每次都是兩個兩個地去運作。每次兩個運作的 job 都會讓我們在運作一些大型工作流或者工作任務的時候感到特别的友善。

應用編排與管理:Job & DaemonSet

上圖中可以看到突然出現了一個 job,“hello-xxxx”這個 job 就是剛才所說的 CronJob。它距離剛才 CronJob 送出已經過去 1 分鐘了,這樣就會自動建立出來一個 job,如果不去幹擾它的話,它以後大概每一分鐘都會建立出來這麼一個 job,除非等我們什麼時候指定它不可以再運作的時候它才會停止建立。

在這裡 CronJob 其實主要是用來運作一些清理任務或者說執行一些定時任務。比如說 Jenkins 建構等方面的一些任務,會特别有效。

架構設計

Job 管理模式

應用編排與管理:Job & DaemonSet

我們來看一下 job 的架構設計。Job Controller 其實還是主要去建立相對應的 pod,然後 Job Controller 會去跟蹤 Job 的狀态,及時地根據我們送出的一些配置重試或者繼續建立。同時我們剛剛也提到,每個 pod 會有它對應的 label,來跟蹤它所屬的 Job Controller,并且還去配置并行的建立, 并行或者串行地去建立 pod。

Job 控制器

應用編排與管理:Job & DaemonSet

上圖是一個 Job 控制器的主要流程。所有的 job 都是一個 controller,它會 watch 這個 API Server,我們每次送出一個 Job 的 yaml 都會經過 api-server 傳到 ETCD 裡面去,然後 Job Controller 會注冊幾個 Handler,每當有添加、更新、删除等操作的時候,它會通過一個記憶體級的消息隊列,發到 controller 裡面。

通過 Job Controller 檢查目前是否有運作的 pod,如果沒有的話,通過 Scale up 把這個 pod 建立出來;如果有的話,或者如果大于這個數,對它進行 Scale down,如果這時 pod 發生了變化,需要及時 Update 它的狀态。

同時要去檢查它是否是并行的 job,或者是串行的 job,根據設定的配置并行度、串行度,及時地把 pod 的數量給建立出來。最後,它會把 job 的整個的狀态更新到 API Server 裡面去,這樣我們就能看到呈現出來的最終效果了。

DaemonSet

需求來源

DaemonSet 背景問題

下面介紹第二個控制器:DaemonSet。同樣的問題:如果我們沒有 DaemonSet 會怎麼樣?下面有幾個需求:

  • 首先如果希望每個節點都運作同樣一個 pod 怎麼辦?
  • 如果新節點加入叢集的時候,想要立刻感覺到它,然後去部署一個 pod,幫助我們初始化一些東西,這個需求如何做?
  • 如果有節點退出的時候,希望對應的 pod 會被删除掉,應該怎麼操作?
  • 如果 pod 狀态異常的時候,我們需要及時地監控這個節點異常,然後做一些監控或者彙報的一些動作,那麼這些東西運用什麼控制器來做?

DaemonSet:守護程序控制器

DaemonSet 也是 Kubernetes 提供的一個 default controller,它實際是做一個守護程序的控制器,它能幫我們做到以下幾件事情:

  • 首先能保證叢集内的每一個節點都運作一組相同的 pod;
  • 同時還能根據節點的狀态保證新加入的節點自動建立對應的 pod;
  • 在移除節點的時候,能删除對應的 pod;
  • 而且它會跟蹤每個 pod 的狀态,當這個 pod 出現異常、Crash 掉了,會及時地去 recovery 這個狀态。

用例解讀

DaemonSet 文法

下面舉個例子來看一下,DaemonSet.yaml 會稍微長一些。

應用編排與管理:Job & DaemonSet

首先是 kind:DaemonSet。如果前面學過 deployment 後,其實我們再看這個 yaml 會比較簡單。例如它會有 matchLabel,通過 matchLabel 去管理對應所屬的 pod,這個 pod.label 也要和這個 DaemonSet.controller.label 想比對,它才能去根據 label.selector 去找到對應的管理 Pod。下面 spec.container 裡面的東西都是一緻的。

這裡用 fluentd 來做例子。DaemonSet 最常用的點在于以下幾點内容:

  • 首先是存儲,GlusterFS 或者 Ceph 之類的東西,需要每台節點上都運作一個類似于 Agent 的東西,DaemonSet 就能很好地滿足這個訴求;
  • 另外,對于日志收集,比如說 logstash 或者 fluentd,這些都是同樣的需求,需要每台節點都運作一個 Agent,這樣的話,我們可以很容易搜集到它的狀态,把各個節點裡面的資訊及時地彙報到上面;
  • 還有一個就是,需要每個節點去運作一些監控的事情,也需要每個節點去運作同樣的事情,比如說 Promethues 這些東西,也需要 DaemonSet 的支援。

檢視 DaemonSet 狀态

應用編排與管理:Job & DaemonSet

建立完 DaemonSet 之後,我們可以使用 kubectl get DaemonSet(DaemonSet 縮寫為 ds)。可以看到 DaemonSet 傳回值和 deployment 特别像,即它目前一共有正在運作的幾個,然後我們需要幾個,READY 了幾個。當然這裡面,READY 都是隻有 Pod,是以它最後建立出來所有的都是 pod。

這裡有幾個參數,分别是:需要的 pod 個數、目前已經建立的 pod 個數、就緒的個數,以及所有可用的、通過健康檢查的 pod;還有 NODE SELECTOR,因為 NODE SELECTOR 在 DaemonSet 裡面非常有用。有時候我們可能希望隻有部分節點去運作這個 pod 而不是所有的節點,是以有些節點上被打了标的話,DaemonSet 就隻運作在這些節點上。比如,我隻希望 master 節點運作某些 pod,或者隻希望 Worker 節點運作某些 pod,就可以使用這個 NODE SELECTOR。

更新 DaemonSet

應用編排與管理:Job & DaemonSet

其實 DaemonSet 和 deployment 特别像,它也有兩種更新政策:一個是 RollingUpdate,另一個是 OnDelete。

  • RollingUpdate 其實比較好了解,就是會一個一個的更新。先更新第一個 pod,然後老的 pod 被移除,通過健康檢查之後再去見第二個 pod,這樣對于業務上來說會比較平滑地更新,不會中斷;
  • OnDelete 其實也是一個很好的更新政策,就是模闆更新之後,pod 不會有任何變化,需要我們手動控制。我們去删除某一個節點對應的 pod,它就會重建,不删除的話它就不會重建,這樣的話對于一些我們需要手動控制的特殊需求也會有特别好的作用。

操作示範

DaemonSet 的編排

下面舉一個例子。比如說我們去改了些 DaemonSet 的鏡像,然後看到了它的狀态,它就會去一個一個地更新。

應用編排與管理:Job & DaemonSet

上圖這個就是剛才 DaemonSet 的 yaml,會比剛才會多一些, 我們做一些資源的限制,這個都不影響。

DaemonSet 的建立與運作驗證

下面我們建立一下 DaemonSet ,然後再看一下它的狀态。下圖就是我們剛才看到的 DaemonSet 在 ready 裡打出來的狀态。

應用編排與管理:Job & DaemonSet

從下圖中可以看到,一共有 4 個 pod 被建立出來。為什麼是 4 個 pod呢?因為隻有 4 個節點,是以每個節點上都會運作一個對應的 pod。

應用編排與管理:Job & DaemonSet

DaemonSet 的更新

這時,我們來更新 DaemonSet, 執行完了kubectl apply -f 後,它的 DaemonSet 就已經更新了。接下來我們去檢視 DaemonSet 的更新狀态。

應用編排與管理:Job & DaemonSet

上圖中可以看到:DaemonSet 預設這個是 RollingUpdate 的,我們看到是 0-4,現在是 1-4,也就是說它在更新第一個,第一個更新完成會去更新第二個,第二個更新完,就更新第三個……這個就是 RollingUpdate。RollingUpdate 可以做到全自動化的更新,不用有人值守,而是一個一個地去自動更新,更新的過程也比較平滑,這樣可以有利于我們在現場釋出或者做一些其他操作。

上圖結尾處可以看到,整個的 DaemonSet 已經 RollingUpdate 完畢。

架構設計

DaemonSet 管理模式

應用編排與管理:Job & DaemonSet

接下來看一下 DaemonSet 架構設計。DaemonSet 還是一個 controller,它最後真正的業務單元也是 Pod,DaemonSet 其實和 Job controller 特别相似,它也是通過 controller 去 watch API Server 的狀态,然後及時地添加 pod。唯一不同的是,它會監控節點的狀态,節點新加入或者消失的時候會在節點上建立對應的 pod,然後同時根據你配置的一些 affinity 或者 label 去選擇對應的節點。

DaemonSet 控制器

應用編排與管理:Job & DaemonSet

最後我們來看一下 DaemonSet 的控制器,DaemonSet 其實和 Job controller 做的差不多:兩者都需要根據 watch 這個 API Server 的狀态。現在 DaemonSet 和 Job controller 唯一的不同點在于,DaemonsetSet Controller需要去 watch node 的狀态,但其實這個 node 的狀态還是通過 API Server 傳遞到 ETCD 上。

當有 node 狀态節點發生變化時,它會通過一個記憶體消息隊列發進來,然後DaemonSet controller 會去 watch 這個狀态,看一下各個節點上是都有對應的 Pod,如果沒有的話就去建立。當然它會去做一個對比,如果有的話,它會比較一下版本,然後加上剛才提到的是否去做 RollingUpdate?如果沒有的話就會重新建立,Ondelete 删除 pod 的時候也會去做 check 它做一遍檢查,是否去更新,或者去建立對應的 pod。

當然最後的時候,如果全部更新完了之後,它會把整個 DaemonSet 的狀态去更新到 API Server 上,完成最後全部的更新。

本節總結

  • Job & CronJobs 基礎操作與概念解析:本節詳細介紹了 Job 和 CronJob 的概念,并通過兩個實際的例子介紹了 Job 和 CronJob 的使用,對于 Job 和 CronJob 内的各種功能便簽都進行了詳細的示範;
  • DaemonSet 基礎操作與概念解析:通過類比 Deployment 控制器,我們了解了一下 DaemonSet 控制器的工作流程與方式,并且通過對 DaemonSet 的更新了解了滾動更新的概念和相對應的操作方式。

繼續閱讀