Kubernetes原生CI/CD構建框架Tekton詳解

流水線(Pipeline)是把一個重複的過程分解爲若干個子過程,使每個子過程與其他子過程並行進行的技術。本文主要介紹了誕生於雲原生時代的流水線框架 Tekton。

什麼是流水線?

在計算機中,流水線是把一個重複的過程分解爲若干個子過程,使每個子過程與其他子過程並行進行的技術,也叫 Pipeline。由於這種 s工作方式與工廠中的生產流水線十分相似, 因此也被稱爲流水線技術。從本質上講,流水線技術是一種時間並行技術。以“構建鏡像”過程爲例:

一次構建鏡像中,我們都需要拉下代碼倉庫中的代碼,進行代碼編譯,構建鏡像,最後推往鏡像倉庫。在每一次代碼更改過後,這一過程都是不變的。使用流水線工具可以極大的提升這一過程的效率,只需要進行簡單的配置便可以輕鬆的完成重複性的工作。這樣的過程也被稱之爲 CI。

上圖流程中使用的是 Jenkins。Jenkins 作爲老牌流水線框架被大家所熟知。在雲原生時代,Jenkins 也推出了 Jenkins X 作爲基於 Kubernetes 的新一代流水線,但今天本文主要介紹誕生於雲原生時代的流水線框架——Tekton。

Tekton

Tekton 是一個基於 Kubernetes 的雲原生 CI/CD 開源框架,屬於 CD 基金會的項目之一。Tekton 通過定義 CRD 的方式,讓用戶以靈活的自定義流水線以滿足自身 CI/CD 需求。

基本概念

四個基本概念

Tekton 最主要的四個概念爲:Task、TaskRun、Pipeline 以及 PipelineRun。

  • Task:Task 爲構建任務,是 Tekton 中不可分割的最小單位,正如同 Pod 在 Kubernetes 中的概念一樣。在 Task 中,可以有多個 Step,每個 Step 由一個 Container 來執行。

  • Pipeline:Pipeline 由一個或多個 Task 組成。在 Pipeline 中,用戶可以定義這些 Task 的執行順序以及依賴關係來組成 DAG(有向無環圖)。

  • PipelineRun:PipelineRun 是 Pipeline 的實際執行產物,當用戶定義好 Pipeline 後,可以通過創建 PipelineRun 的方式來執行流水線,並生成一條流水線記錄。

  • TaskRun:PipelineRun 被創建出來後,會對應 Pipeline 裏面的 Task 創建各自的 TaskRun。一個 TaskRun 控制一個 Pod,Task 中的 Step 對應 Pod 中的 Container。當然,TaskRun 也可以單獨被創建。

綜上可知:Pipeline 由多個 Task 組成,每次執行對應生成一條 PipelineRun,其控制的 TaskRun 將創建實際運行的 Pod。下面以一個簡單例子來展示這些概念。

首先,創建一個最簡單的 Task,裏面僅有一個 Step。在一個 ubuntu 鏡像中執行 ls 命令。

接着創建一個 Pipeline,裏面引用第一步中創建的 Task。

在 Pipeline 存在的前提下,就可以通過創建 PipelineRun 來運行 Pipeline。

這樣就完成了一個最簡單的 Tekton 流水線案例。每一個 PipelineRun 的創建,都會遵循 Pipeline 中的順序規則去啓動 Task 的 Pod。下面引入另外一個概念 PipelineResource 來完成一個稍微複雜的例子,也是 DevOps 中最常見的場景:從代碼倉庫拉取鏡像、進行代碼構建、並最終將構建好的鏡像推往鏡像倉庫。

PipelineResource

PipelineResource 代表着一系列的資源,主要承擔作爲 Task 的輸入或者輸出的作用。它有以下幾種類型:

  • Git:代表一個 Git 倉庫,包含了需要被構建的源代碼。將 Git 資源作爲 Task 的 Input,會自動 clone 此 Git 倉庫。

  • pullRequest:表示來自配置的 url(通常是一個 Git 倉庫)的 pull request 事件。將 pull request 資源作爲 Task 的 Input,將自動下載 pull request 相關元數據的文件,如 base/head commit、comments 以及 labels。

  • Image:代表鏡像倉庫中的鏡像,通常作爲 Task 的 Output,用於生成鏡像。

  • Cluster:表示一個除了當前集羣外的 Kubernetes 集羣。可以使用 Cluster 資源在不同的集羣上部署應用。

  • Dtorage:表示 blob 存儲,它包含一個對象或目錄。將 Storage 資源作爲 Task 的 Input 將自動下載存儲內容,並允許 Task 執行操作。目前僅支持 GCS。

  • cloud event:會在 TaskRun z執行完成後發送事件信息(包含整個 TaskRun) 到指定的 URI 地址,在與第三方通信的時候十分有用。

以上爲 Tekton 目前支持的六大 PipelineResource 類型,具體的配置及使用方法詳見 PipelineResource 文檔。

文檔地址:https://github.com/tektoncd/pipeline/blob/master/docs/resources.md

繼續分析較複雜的流水線案例:從代碼倉庫拉取鏡像、進行代碼構建、並將構建好的鏡像推往鏡像倉庫。從已有的 PipelineResource 類型可判斷,可以使用 git 類型作爲代碼資源作爲輸入,再用 image 類型作爲鏡像資源作爲輸出。有了輸入輸出後,我們可以直接使用 Kaniko 來構建鏡像。

Kaniko 是 Google 開源的項目之一,可在 Kubernetes 上無需特權模式地構建 Docker 鏡像。

首先創建這兩個 PipelineResource。在這個例子中,git-input 對應輸入,image-output 對應輸出。params 中的參數均爲該資源類型的固定參數:如 Git 中可以通過 revision 指定版本號,Image 中可以通過 url 指定鏡像倉庫地址。

Git-input:

Image-output:

在配置 PipelineResource 時,如果使用了私有倉庫,還需要配置 Service Account,詳見 configuring-authentication-for-docker。

configuring-authentication-for-docker 地址:https://github.com/tektoncd/pipeline/blob/master/docs/auth.md#configuring-authentication-for-docker

產物傳遞

創建完 PipelineResource 後,需要在 Task 中引入它們作爲輸入輸出。那麼,這些資源是如何在 Task 間傳遞的呢?

在 Tekton 的分區下,我們可以看到一個叫做 config-artifact-pvc 和一個叫做 config-artifact-bucket 的 Config Map。從命名就可以看出,這二者分別代表了產物存儲的兩種配置方式—— PVC 和存儲桶(目前支持 GCS 和 S3)。

以 PVC 爲例,修改 config-artifact-pvc 需要填寫兩個值:size 以及 storageClassName。size 默認爲 5GiB,storage class name 默認爲 default。這也意味着當我們使用 PipelineResource 進行資源傳遞時,會自動創建一個 5GiB 的存儲卷掛載在 Task 上,供 PipelineResource 使用。

在需要進行 Task 間的資源傳遞時,這個存儲卷會被掛載在 Task 的 /pvc 目錄下。當 Task 執行完成並且需要進行資源傳遞(通過 inputs/outputs 指定)後,TaskRun controller 會自動添加一個拷貝文件的步驟容器,並將輸出產物統一放到 /pvc/task_name/resource_name 命名規範的目錄下。

上面是針對產物需要進行傳遞的情況下,對於目前例子而言,由於只需要一個 Task,雖然指定了 Inputs 和 Outputs,但並沒有另一個 Task 來引用這些結果。因此,在這個例子中並不會去掛載 PVC。

對於 Git 以及 storage 類型的 input,資源下載後會被 放在 /workspace/task_resource_name 下;對於 output 則會放在 /workspace/output/resource_name 下。image 類型的資源則會直接上傳到鏡像倉庫。

瞭解了這些前置知識後,我們可以來創建 Task 了。Kaniko 需要三個參數來完成鏡像構建:Dockerfile 的地址,context 的地址以及鏡像倉庫的地址。在下面這個例子中,我們大量使用了 params 以及 Tekton 中的變量替換。Params 用於在 TaskRun 和 Task 中傳遞參數,而變量替換的格式爲 $(xxx)。使用這些變量可以讓 Tekton 在運行過程中根據規則進行賦值。值得注意的是,Tekton 並不會提前去檢查這些變量的內容,這就要求着我們在寫的時候需要多加註意。具體的變量編寫規則詳見:Tekton variables。

Tekton variables 地址:https://github.com/tektoncd/pipeline/blob/master/docs/variables.md

有了 Task 後,就能創建 TaskRun 來執行 Task。注意,在 spec 中申明瞭 serviceAccountName 用於指定私有倉庫的權限。

至此,一個更爲複雜的流水線也構建完成了。

DAG

在 Tekton 中,DAG(有向無環圖)的功能是原生支持的。只需要通過申明 runAfter 及 from 便可以便利的使 Pipeline 以 DAG 方式運行。

  • from:當 Task 的 Inputs 依賴於上一個 Task 的 Outputs 時,可以通過 from 參數來指定

  • runAfter:當 Task 間沒有資源依賴,但需要使一個 Task 在另外一個 Task 之後運行的話,可以使用 runAfter 來指定

例如在上面的例子中,任務會以下順序運行:

  • lint-repo 和 test-app 中的 Task 沒有 from 或 runAfter 關鍵字,會同時開始執行。

  • 一旦 test-app 完成,build-app 和 build-frontend 都會開始同時執行,因爲它們 runAfter 於 test-app。

  • deploy-all 會在 build-app 和 build-frontend 都完成後才執行,因爲它需要的資源 from 於這二者。

再來看看 Tekton 是怎麼樣來實現這段邏輯的:

在 Pipeline 的 Controller 中,一旦監聽到 Pipeline 的創建,在創建對應的 TaskRun 之前,會先檢測 Pipeline 中的依賴順序並構建 DAG 圖:

Step 執行順序

Pipeline 中可以進行對 Task 的順序控制,那麼 Task 中呢?

在 Kubernetes 中,Pod 裏的 Container 是並行啓動的。而在 Tekton 中,雖然 Task 對應 Pod,Task 中的 Step 對應 Container,但 Task 中的 Step 卻是順序執行的。要了解 Tekton 是怎麼完成這樣的順序控制,首先我們來看一下一個 Tekton 的 Pod。

在這個 Pod 中,除了用戶需要運行的 Container,還被注入了一個 InitContainer:

這個 InitContainer copy 了一個 entrypoint 的二進制到 Pod 中。再看下用戶的 container,我們可以看到 Pod 的執行命令被 Tekton 改寫了一下:

可以看到 command 被改寫爲了 entrypoint 命令,這個二進制包在 initContainer 中被導入,另外還有一些啓動參數:

  • -post_file:指定了 Step 完成後的文件寫入路徑。如果 Step 失敗,則寫入到 { {post_file}}.err。可以看到上面的寫入路徑爲 /tekton/tools/0,最後的這個數字即爲 Step 的編號。

  • -wait_file:指定了在啓動下一個 Step 之前要查看的文件路徑。它將監聽 { {wait_file}} 和 { {wait_file}}.err。若有錯誤則跳過執行寫入 { {post_file}}.err 並返回錯誤(exitCode >= 0);若無錯誤則執行下一個 Step。如上例子爲第一個 step,若爲第二個 step,wait_ file 的地址會是 /tekton/tools/0,也就是上一個 step 的 post_file 地址。

資源控制

在 Kubernetes 中,一個 Pod 被調度需要節點滿足 Pod 中的所有 Container 的資源。如下圖:

這個 Pod 有 4 個容器,總共需要 9 個 CPU。Kubernetes 將把這個 Pod 調度到一個擁有 9 個可用 CPU 的節點上。如果沒有節點有 9 個可用 CPU,Pod 將被調度失敗並無法啓動。

而對於 Tekton 而言,因爲 Pod 中的 Container 會順序執行,所以只需要滿足這個 Pod 中資源最大的 Container 即可。對於同一個TaskRun,Tekton 會獲取最大請求,並讓一個 Container 去請求這些資源,其他都設爲 0。

如下,該 Pod 請求 4 個 CPU,而不是 9 個。這樣的資源控制方式更爲合理且所有的 Step 容器仍保留所需要的資源。

在有 LimitRange 限制 Container 必須有資源的的情況下,每個 Container 最小會設置爲 LimitRange 的設置。

源碼部分邏輯如下:

數據傳遞

除了 PipelineResource 以外,Tekton 還提供了其他數據傳遞的方式。

PipelineResource 仍處於 Alpha 版本,它有可能會被重新設計、替換、棄用或者完全刪除。Tekton 社區鼓勵用戶用 Task 代替 PipelineResources。

Workspace

Workspace 與 Kubernetes 中 Volume 概念幾乎保持一致,只不過並不是 Pod 層級的而是作用於 Tekton 資源層級的。Workspace 在 Pipeline 中使用時是一個抽象的概念,實際的存儲類型需要在 PipelineRun 中指定。詳見:Workspaces,地址:https://github.com/tektoncd/pipeline/blob/master/docs/workspaces.md

Results

Tekton 提供了一個固定目錄用於存放 Task 的輸出:/tekton/results

如上,該 task 將日期輸出到了 /tekton/results/current-date 中。同時,也會被作爲 Results 字段加到 TaskRun 的 Status 中。這樣,其他的 Task 便可以通過 $(tasks..results.) 來獲取到該 Task 的 results。(變量替換將會實際從 TaskRun 中獲取到 Results 的值)

其他流程控制功能

條件判斷

低版本可以使用 Conditions,高版本推薦使用 WhenExpressions(Conditions 將在不久後廢棄,完全替換爲 WhenExpressions)。WhenExpressions 由 Input、Operator、Values 三部分組成,其中 Input 可以使用 Tekton 的 Parameter 或者 Results,Operator 目前僅支持 in 和 notin:

錯誤重嘗

通過 retries 來指定任務失敗後重新嘗試的次數:

退出處理

通過 finally 指定在 pipeline 結束時執行的 task,無論 pipeline 的結果是成功或失敗。

取消執行

要取消當前正在執行的 PipelineRun,可以在其 Spec 中更新 Status 爲取消。當 PipelineRun 被取消時,所有相關的 Pods 都被刪除。例如:

Pipeline 暫停的邏輯與之類似,但暫停 PR 尚未合入,暫停功能也在 Tekton 今年的 Roadmap 中。

Runs

Runs 是一個進行中的 feature,Run 允許實例化和執行一個 Custom Task,這個 Custom Task 可以通過用戶自定義的 controller 來執行。這對於用戶來說是一個非常實際的功能,可以通過自己寫的 Controller 來定義 Task 的邏輯,而不再拘泥於 Tekton 定義的 Task。

文章來源:K8sMeetup社區,點擊查看原文

Kubernetes管理員認證(CKA)培訓

本次CKA培訓在北京開班,基於最新考綱,通過線下授課、考題解讀、模擬演練等方式,幫助學員快速掌握Kubernetes的理論知識和專業技能,並針對考試做特別強化訓練,讓學員能從容面對CKA認證考試,使學員既能掌握Kubernetes相關知識,又能通過CKA認證考試,學員可多次參加培訓,直到通過認證。點擊下方圖片或者閱讀原文鏈接查看詳情。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章