Categories
程式開發

開源 CI/CD 構建框架 TekTon 的深入剖析


簡介

Tekton 是一個功能強大且靈活的 Kubernetes 原生 CI/CD 構建框架,用於創建持續集成和交付(CI/CD)系統。關於 Tekton ,網上可以搜到很多很多介紹文檔,本文主要闡述我對 Tekton 的實現原理和背後的技術邏輯的一點理解。

Tekton 定義了Task、TaskRun、Pipeline、PipelineRun、PipelineResource 五類核心對象,通過對Task 和Pipeline 的抽象,我們可以定義出任意組合的pipeline 模板來完成各種各樣的CI/CD 任務,再通過TaskRun、 PipelineRun和PipelineResource 可以將這些模板套用到各個實際的項目中。

實現原理

高度抽象的結構化設計使得 Tekton 具有非常靈活的特性,那麼 Tekton 是如何實現 workflow 的流轉的呢?

Tekton 利用 Kubernetes 的 List-Watch 機制,在啟動時初始化了 2 個 Controller、PipelineRunController 和 TaskRunController 。

PipelineRunController 監聽 PipelineRun 對象的變化。在它的 reconcile 邏輯中,將pipeline 中所有的 Task 構建為一張有向無環圖(DAG),通過遍歷 DAG 找到當前可被調度的 Task 節點創建對應的 TaskRun 對象。

TaskRunController 監聽 TaskRun 對象的變化。在它的 reconcile 邏輯中將 TaskRun 和對應 Task 轉化為可執行的 Pod ,由 kubernetes 調度執行。利用 Kubernetes 的 OwnerReference 機制, PipelineRun Own TaskRun、TaskRun Own Pod、Pod 狀態變更時,觸發 TaskRun 的 reconcile 邏輯, TaskRun 狀態變更時觸發 PipelineRun 的 reconcile 邏輯。

開源 CI/CD 構建框架 TekTon 的深入剖析 1

DAG 支持

Tekton 對 DAG 的支持相對比較簡單。在 Tekton 中一個 Pipeline 就是一張 DAG ,Pipeline 中的多個Task可是DAG中的節點。 Task 默認並發執行,可以通過 RunAfter 和 From 關鍵字控制執行順序。

示例:

- name: lint-repo
  taskRef:
    name: pylint
  resources:
    inputs:
      - name: workspace
        resource: my-repo
- name: test-app
  taskRef:
    name: make-test
  resources:
    inputs:
      - name: workspace
        resource: my-repo
- name: build-app
  taskRef:
    name: kaniko-build-app
  runAfter:
    - test-app
  resources:
    inputs:
      - name: workspace
        resource: my-repo
    outputs:
      - name: image
        resource: my-app-image
- name: build-frontend
  taskRef:
    name: kaniko-build-frontend
  runAfter:
    - test-app
  resources:
    inputs:
      - name: workspace
        resource: my-repo
    outputs:
      - name: image
        resource: my-frontend-image
- name: deploy-all
  taskRef:
    name: deploy-kubectl
  resources:
    inputs:
      - name: my-app-image
        resource: my-app-image
        from:
          - build-app
      - name: my-frontend-image
        resource: my-frontend-image
        from:
          - build-frontend

渲染出的執行順序為:

        |            |
        v            v
     test-app    lint-repo
    /        
   v          v
build-app  build-frontend
             /
    v        v
    deploy-all

相比於 Argo 等專注在 workflow 的項目而言, Tekton 支持的任務編排方式是非常有限的。常見的循環,遞歸,重試,超時等待等策略都是沒有的。

條件判斷

Tekton 支持 condition 關鍵字來進行條件判斷。 Condtion 只支持判斷當前Task是否執行,不能作為 DAG 的分支條件來進行動態 DAG 的渲染。

condition:

https://github.com/tektoncd/pipeline/blob/e2755583d52ae46907790d40ba4886d55611cd23/docs/conditions.md

* condition检查失败(exitCode != 0),task不会被执行,pipelineRun状态不会因为condition检查失败而失败。
* 多个条件之间 “与” 逻辑关系

PipelineResource 在 Task 間數據交換

作為 CI/CD 的工具,代碼在什麼時候 Clone 到 WorkSpace 中,如何實現的? Tekton 中抽象了 PipelineResource 進行任務之間的數據交換, GitResource 是其中最基礎的一種。用法如下。

聲明一個 Git 類型的 PipelineResource :

kind: PipelineResource
metadata:
  name: skaffold-git-build-push-kaniko
spec:
  type: git
  params:
  - name: revision
    value: v0.32.0
  - name: url
    value: https://github.com/GoogleContainerTools/skaffold

在 Task 中引用這個 Resource 做為輸入:

kind: Task
metadata:
  name: build-push-kaniko
spec:
  inputs:
    resources:
    - name: workspace
      type: git
  steps:
  - name: build-and-push
    image: registry.cn-shanghai.aliyuncs.com/kaniko-project-edas/executor:v0.17.1

代碼會被 clone 在 /workspace 目錄。

Tekton 是如何處理這些 PipelineResource 的呢,這就要從 Taskrun Controller 如何創建 Pod 說起。

Tekton 中一個 TaskRun 對應一個 Pod ,每個 Pod 有一系列 init-containers 和 step-containers 組成。 init-container 中完成認證信息初始化, workspace 目錄初始化等初始化工作。

在處理 step-container 時,會根據這個 Task 引用的資源 Append 或者 Insert 一個 step-container 來處理對應的輸和輸出,如下圖所示。

開源 CI/CD 構建框架 TekTon 的深入剖析 2

Task中Step執行順序控制

Tekton 源自Knative Build ,在Knative Build 中使用Init-container 來串聯Steps 保證Steps 順序執行,在上面的分析中我們知道Tekton 是用Containers 來執行Steps , Pod 的Containers 是並行執行的, Tekton 是如何保證Steps執行順序呢?

這是一個 TaskRun 創建的 Pod 的部分描述信息,可以看到所有的 Step 都是被 /tekton/tools/entrypoints 封裝起來執行的。 -wait_file 指定一個文件,通過監聽文件句柄,在探測到文件存在時執行被封裝的 Step 任務。 -post_file 指定一個文件,在Step任務完成後創建這個文件。通過文件序列 /tekton/tools/${index} 來對 Step 進行排序。

- args:
    - -wait_file
    - /tekton/tools/0
    - -post_file
    - /tekton/tools/1
    - -termination_path
    - /tekton/termination
    - -entrypoint
    - /ko-app/git-init
    - --
    - -url
    - https://github.com/GoogleContainerTools/skaffold
    - -revision
    - v0.32.0
    - -path
    - /workspace/workspace
    command:
    - /tekton/tools/entrypoint
    image: registry.cn-shanghai.aliyuncs.com/kaniko-project-edas/git-init:v0.10.2
    name: step-git-source-skaffold-git-build-push-kaniko-rz765
  - args:
    - -wait_file
    - /tekton/tools/1
    - -post_file
    - /tekton/tools/2
    - -termination_path
    - /tekton/termination
    - -entrypoint
    - /kaniko/executor
    - --
    - --dockerfile=Dockerfile
    - --destination=localhost:5000/leeroy-web
    - --context=/workspace/workspace/examples/microservices/leeroy-web
    - --oci-layout-path=$(inputs.resources.builtImage.path)
    command:
    - /tekton/tools/entrypoint
    image: registry.cn-shanghai.aliyuncs.com/kaniko-project-edas/[email protected]:565d31516f9bb91763dcf8e23ee161144fd4e27624b257674136c71559ce4493
    name: step-build-and-push
  - args:
    - -wait_file
    - /tekton/tools/2
    - -post_file
    - /tekton/tools/3
    - -termination_path
    - /tekton/termination
    - -entrypoint
    - /ko-app/imagedigestexporter
    - --
    - -images
    - '[{"name":"skaffold-image-leeroy-web-build-push-kaniko","type":"image","url":"localhost:5000/leeroy-web","digest":"","OutputImageDir":"/workspace/output/builtImage"}]'
    command:
    - /tekton/tools/entrypoint
    image: registry.cn-shanghai.aliyuncs.com/kaniko-project-edas/imagedigestexporter:v0.10.2
    name: step-image-digest-exporter-lvlj9

實踐

使用 Tekton 構建代碼並部署到 SAE

Serverless 應用引擎( SAE ) 是阿里雲上一款面向應用的Serverless PaaS 平台,幫助PaaS 層用戶免運維IaaS,按需使用,按量計費,實現低門檻微服務應用上雲,有效解決成本及效率問題。支持 Spring Cloud、Dubbo 和 HSF 等流行的開發框架,真正實現了 Serverless 架構和微服務架構的完美融合。

接下來將使用 Tekton 部署一個 Spring Cloud 微服務應用到 SAE 平台。

示例中的演示代码地址:https://github.com/alicloud-demo/spring-cloud-demo

1、前置條件

在 Kubernetes 集群上安裝 Tekton :

https://github.com/tektoncd/pipeline/blob/master/docs/install.md

創建一個 SAE 應用:

https://help.aliyun.com/document_detail/122439.html

2、定義一個 Git 資源

apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: spring-cloud-demo
spec:
  type: git
  params:
  - name: url
    value: https://github.com/alicloud-demo/spring-cloud-demo

3、定義構建和部署 Task

根據 SAE 官方文檔進行部署,詳情參考:

https://help.aliyun.com/document_detail/110639.html

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: build-deploy-sae
spec:
  inputs:
    resources:
    - name: source
      type: git
  steps:
  - name: build-and-deploy
    image: maven:3.3-jdk-8
    command: ["mvn", "clean", "package", "-f", "source", "toolkit:deploy", "-Dtoolkit_profile=toolkit_profile.yaml", "-Dtoolkit_package=toolkit_package.yaml", "-Dtoolkit_deploy=toolkit_deploy.yaml"]
    securityContext:
      runAsUser: 0

4、定義 TaskRun 運行任務

apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: build-deploy-sae
spec:
  taskRef:
    name: build-deploy-sae
  inputs:
    resources:
    - name: source
      resourceRef:
        name: spring-cloud-demo

5、導入到kubernetes中運行

kubectl apply -f source-2-service-taskrun.yaml

開源 CI/CD 構建框架 TekTon 的深入剖析 3

6、查看日誌

kubectl logs build-deploy-sae-pod-85xdk step-build-and-deploy

構建日誌:

開源 CI/CD 構建框架 TekTon 的深入剖析 4

部署日誌:

[INFO] Start to upload [provider3-1.0-SNAPSHOT.jar] using [Sae uploader].
[INFO] [##################################################] 100.0%
[INFO] Upload finished in 3341 ms, download url: [https://edas-hz.oss-cn-hangzhou.aliyuncs.com/apps/K8S_APP_ID/37adb12b-5f0c-4711-98ec-1f1e91e6b043/provider3-1.0-SNAPSHOT.jar]
[INFO] Begin to trace change order: e2499b9a-6a51-4904-819c-1838c1dd62cb
[INFO] PipelineName: Batch: 1, PipelineId:f029314a-88bb-450b-aa35-7cc550ff1329
[INFO] Waiting...
[INFO] Waiting...
[INFO] Waiting...
[INFO] Waiting...
[INFO] Waiting...
[INFO] Waiting...
[INFO] Waiting...
[INFO] Waiting...
[INFO] Deploy application successfully!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 32:41 min
[INFO] Finished at: 2020-04-15T10:09:39+00:00
[INFO] Final Memory: 47M/190M
[INFO] ------------------------------------------------------------------------

7、驗證部署結果

在 SAE 控制台查看變更記錄:

開源 CI/CD 構建框架 TekTon 的深入剖析 5

驗證應用訪問:

開源 CI/CD 構建框架 TekTon 的深入剖析 6

總結

區別於傳統的 CI/CD 工具(Jenkins),Tekton 是一套構建 CICD 系統的框架。 Tekton 不能使你立即獲得 CI/CD 的能力。但是基於 Tekton 可以設計出各種花式的構建部署流水線。得益於 Tekton 良好的抽象,這些設計出的流水線可以作為模板在多個組織,項目間共享。 Tekton 源自 Knative 的 Build-Template 項目,設計之初的一個重要目標就是使人們能夠共享和重用構成 pipeline 的組件,以及 Pipeline 本身。在 Tekton的RoadMap 中 Tekton Catelog 就是為了實現這一目標而提出的。

區別於 Argo 這種基於 Kubernetes 的 Workflow 工具, Tekton 在工作流控制上的支持是比較弱的。一些複雜的場景比如循環,遞歸等都是不支持的。更不用說 Argo 在高並發和大集群調度下的性能優化。這和 Tekton 的定位有關, Tekton 定位於實現 CICD 的框架,對於 CICD 不需要過於復雜的流程控制。大部分的研發流程可以被若干個最佳實踐來覆蓋。而這些最佳實踐應該也必須可以在不同的組織間共享,為此 Tekton 設計了 PipelineResource 的概念。 PipelineResource 是 Task 間交互的接口,也是跨平台跨組織共享重用的組件,在 PipelineResource 上還可以有很多想像空間。

作者介紹

九辯,阿里巴巴高級開發工程師,負責阿里雲EDAS(企業級分佈式應用服務)應用生命週期研發工作,長期關注云時代微服務的部署和治理工作。

本文轉載自公眾號阿里巴巴中間件(ID:Aliware_2018)。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489348&idx=3&sn=161f6eabdfce7dfb8c51ae2e9f8faada&chksm=fdeb2524ca9cac326c362778f8dcf2299a5fb28c80657b44c7c82760f5c8df773421455faf90&scene=27#wechat_redirect