簡介
Tekton 是一個功能強大且靈活的Kubernetes 原生開源架構,用于建立持續內建和傳遞(CI/CD)系統。 關于Tekton, 網上可以搜到很多很多介紹文檔,本文主要闡述我對Tekton的實作原理和背後的技術邏輯的一點了解。
tekton.devTekton定義了Task, TaskRun, Pipeline, PipelineRun, PipelineResource 五類核心對象。Tekton通過對Task和Pipeline的抽象,我們可以定義出任意組合的pipeline模闆來完成各種各樣的CICD任務。通過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邏輯。
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檢查失敗(exitCode != 0),task不會被執行,pipelineRun狀态不會因為condition檢查失敗而失敗。
* 多個條件之間 “與” 邏輯關系
PipelineResource在Task間資料交換
作為CICD的工具,代碼在什麼時候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來處理對應的輸和輸出,如下圖所示。
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/executor@sha256: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
- 前置條件
- 定義一個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
- 定義建構和部署Task
根據SAE
官方文檔進行部署。
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
- 定義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
- 導入到kubernetes中運作
kubectl apply -f source-2-service-taskrun.yaml
- 檢視日志
kubectl logs build-deploy-sae-pod-85xdk step-build-and-deploy
建構日志:
部署日志:
[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] ------------------------------------------------------------------------
- 驗證部署結果
在SAE控制台檢視變更記錄:
驗證應用通路:
總結
差別于傳統的CICD工具(Jenkins),Tekton是一套建構CICD系統的架構。Tekton不能使你立即獲得CICD的能力。但是基于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(企業級分布式應用服務)應用生命周期研發工作,長期關注雲時代微服務的部署和治理工作。