從零開始入門 K8s | 應用編排與管理:Job & DaemonSet

1、Job

需求來源

Job 背景問題

首先咱們來看一下 Job 的需求來源。咱們知道 K8s 裏面,最小的調度單元是 Pod,咱們能夠直接經過 Pod 來運行任務進程。這樣作將會產生如下幾種問題:node

  • 咱們如何保證 Pod 內進程正確的結束?
  • 如何保證進程運行失敗後重試?
  • 如何管理多個任務,且任務之間有依賴關係?
  • 如何並行地運行任務,並管理任務的隊列大小?

Job:管理任務的控制器

咱們來看一下 Kubernetes 的 Job 爲咱們提供了什麼功能:api

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

 

用例解讀

咱們根據一個實例來看一下Job是如何來完成下面的應用的。微信

Job 語法

a1_jpeg

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

這裏面的內容都是同樣的,惟一多了兩個點:app

  • 第一個是 restartPolicy,在 Job 裏面咱們能夠設置 Never、OnFailure、Always 這三種重試策略。在但願 Job 須要從新運行的時候,咱們能夠用 Never;但願在失敗的時候再運行,再重試能夠用 OnFailure;或者不論什麼狀況下都從新運行時 Alway;
  • 另外,Job 在運行的時候不可能去無限的重試,因此咱們須要一個參數來控制重試的次數。這個 backoffLimit 就是來保證一個 Job 到底能重試多少次。

因此在 Job 裏面,咱們主要重點關注的一個是 restartPolicy 重啓策略和 backoffLimit 重試次數限制less

Job 狀態

a2

Job 建立完成以後,咱們就能夠經過 kubectl get jobs 這個命令,來查看當前 job 的運行狀態。獲得的值裏面,基本就有 Job 的名稱、當前完成了多少個 Pod,進行多長時間。dom

**AGE **的含義是指這個 Pod 從當前時間算起,減去它當時建立的時間。這個時長主要用來告訴你 Pod 的歷史、Pod 距今建立了多長時間。**DURATION **主要來看咱們 Job 裏面的實際業務到底運行了多長時間,當咱們的性能調優的時候,這個參數會很是的有用。**COMPLETIONS **主要來看咱們任務裏面這個 Pod 一共有幾個,而後它其中完成了多少個狀態,會在這個字段裏面作顯示。 微服務

查看 Pod

<br />下面咱們來看一下 Pod,其實 Job 最後的執行單元仍是 Pod。咱們剛纔建立的 Job 會建立出來一個叫「pi」的一個 Pod,這個任務就是來計算這個圓周率,Pod 的名稱會以「${job-name}-${random-suffix}」,咱們能夠看一下下面 Pod 的 yaml 格式。性能

a3_jpeg

它比普通的 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 運行

a4

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

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

好比說,剛剛咱們其實經過第二個參數來控制了當前 Job 並行執行的次數,這裏就能夠了解到這個緩衝器或者說管道隊列大小的做用。

Cronjob 語法

a5

下面來介紹另一個 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。

a6

Job 的建立及運行驗證

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

a7

並行 Job 的編排文件

下面再來看第二個例子:

a8

並行 Job 的建立及運行驗證

這個例子就是指剛纔的並行運行 Job 建立以後,能夠看到有第二個並行的 Job。

a9

如今已經有兩個 Pod 正在 running,能夠看到它大概執行了快到 30s。

a10_jpeg

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

a11_jpeg

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

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

a12_jpeg

Cronjob 的編排文件

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

a13

Cronjob 的建立及運行驗證

以下圖 CronJob 已經建立了,能夠經過 get cronjob 來看到當前有一個 CronJob,這個時候再來看 jobs,因爲它是每分鐘執行一次,因此得稍微等一下。

a14

同時能夠看到,上一個 job 還在運行,它的時間是 2m12s 左右,它的完成度是 7/八、6/8,剛剛看到 7/8 到 8/8,也就是說咱們上一個任務執行了最後一步,並且每次都是兩個兩個地去運行。每次兩個運行的 job 都會讓咱們在運行一些大型工做流或者工做任務的時候感到特別的方便。

a15_jpeg

上圖中能夠看到忽然出現了一個 job,「hello-xxxx」這個 job 就是剛纔所說的 CronJob。它距離剛纔 CronJob 提交已通過去 1 分鐘了,這樣就會自動建立出來一個 job,若是不去幹擾它的話,它之後大概每一分鐘都會建立出來這麼一個 job,除非等咱們何時指定它不能夠再運行的時候它纔會中止建立。

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

架構設計

Job 管理模式

a16

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

Job 控制器

a17_jpeg

上圖是一個 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 裏面去,這樣咱們就能看到呈現出來的最終效果了。

2、DaemonSet

需求來源

DaemonSet 背景問題

下面介紹第二個控制器:**DaemonSet。**一樣的問題:若是咱們沒有 DaemonSet 會怎麼樣?下面有幾個需求:

  • 首先若是但願每一個節點都運行一樣一個 pod 怎麼辦?
  • 若是新節點加入集羣的時候,想要馬上感知到它,而後去部署一個 pod,幫助咱們初始化一些東西,這個需求如何作?
  • 若是有節點退出的時候,但願對應的 pod 會被刪除掉,應該怎麼操做?
  • 若是 pod 狀態異常的時候,咱們須要及時地監控這個節點異常,而後作一些監控或者彙報的一些動做,那麼這些東西運用什麼控制器來作?

DaemonSet:守護進程控制器

DaemonSet 也是 Kubernetes 提供的一個 default controller,它實際是作一個守護進程的控制器,它能幫咱們作到如下幾件事情:

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

用例解讀

DaemonSet 語法

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

a18

首先是 kind:DaemonSet。若是以前學過 deployment,其實咱們再看這個 yaml 會比較簡單。例如它會有 matchLabel,經過 matchLabel 去管理對應所屬的 pod,這個 pod.label 也要和這個 DaemonSet.controller.label 想匹配,它才能去根據 label.selector 去找到對應的管理 Pod。下面 spec.container 裏面的東西都是一致的。<br /> <br />這裏用 fluentd 來作例子。DaemonSet 最經常使用的點在於如下幾點內容:

  • 首先是存儲,GlusterFS 或者 Ceph 之類的東西,須要每臺節點上都運行一個相似於 Agent 的東西,DaemonSet 就能很好地知足這個訴求;

  • 另外,對於日誌收集,好比說 logstash 或者 fluentd,這些都是一樣的需求,須要每臺節點都運行一個 Agent,這樣的話,咱們能夠很容易蒐集到它的狀態,把各個節點裏面的信息及時地彙報到上面;

  • 還有一個就是,須要每一個節點去運行一些監控的事情,也須要每一個節點去運行一樣的事情,好比說 Promethues 這些東西,也須要 DaemonSet 的支持。

查看 DaemonSet 狀態

a19

建立完 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

a20

其實 DaemonSet 和 deployment 特別像,它也有兩種更新策略:一個是 RollingUpdate,另外一個是 OnDelete

  • RollingUpdate 其實比較好理解,就是會一個一個的更新。先更新第一個 pod,而後老的 pod 被移除,經過健康檢查以後再去見第二個 pod,這樣對於業務上來講會比較平滑地升級,不會中斷;

  • OnDelete 其實也是一個很好的更新策略,就是模板更新以後,pod 不會有任何變化,須要咱們手動控制。咱們去刪除某一個節點對應的 pod,它就會重建,不刪除的話它就不會重建,這樣的話對於一些咱們須要手動控制的特殊需求也會有特別好的做用。

操做演示

DaemonSet 的編排

下面舉一個例子。好比說咱們去改了些 DaemonSet 的鏡像,而後看到了它的狀態,它就會去一個一個地更新。

a21

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

DaemonSet 的建立與運行驗證

下面咱們建立一下 DaemonSet ,而後再看一下它的狀態。下圖就是咱們剛纔看到的 DaemonSet 在 ready 裏打出來的狀態。

a22

從下圖中能夠看到,一共有 4 個 pod 被建立出來。爲何是 4 個 pod呢?由於只有 4 個節點,因此每一個節點上都會運行一個對應的 pod。

a23

DaemonSet 的更新

這時,咱們來更新 DaemonSet, 執行完了kubectl apply -f 後,它的 DaemonSet 就已經更新了。接下來咱們去查看 DaemonSet 的更新狀態。

a24

上圖中能夠看到:DaemonSet 默認這個是 RollingUpdate 的,咱們看到是 0-4,如今是 1-4,也就是說它在更新第一個,第一個更新完成會去更新第二個,第二個更新完,就更新第三個······這個就是 RollingUpdate。RollingUpdate 能夠作到全自動化的更新,不用有人值守,而是一個一個地去自動更新,更新的過程也比較平滑,這樣能夠有利於咱們在現場發佈或者作一些其餘操做。<br />

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

架構設計

DaemonSet 管理模式

a25

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

DaemonSet 控制器

a26

最後咱們來看一下 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 的更新瞭解了滾動更新的概念和相對應的操做方式。

「阿里巴巴雲原生微信公衆號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術公衆號。」

相關文章
相關標籤/搜索