Tekton 設計簡介 及 實踐

2022-12-04 06:00:21

本文是我對Tekton的實現原理和背後技術邏輯的理解,以及在實踐過程中的一些總結。

簡介

Tekton 是一個基於 Kubernetes 的雲原生 CI/CD 開源(https://cd.foundation/)框架,基於 CRD(Custom Resource Definitions)方式實現,目前阿里、google、ibm 都在使用這個框架。

Tekton 定義了 Task、TaskRun、Pipeline、PipelineRun、PipelineResource 五類核心物件,通過對task、pipeline資源的編排我可以實現CI/CD。
除此之外Tekton還提供了:

  • Tekton CLI 命令列工具可以更加快捷和針對性的現實tekton的執行狀態;
  • Tekton Dashboard 可以圖形化介面的形式檢視執行狀態和結果;
  • Tekton Trigger 提供了web api可以進行基本的觸發。

實現原理

Tekton 是基於CRD(Custom Resource Definitions)實現的,是標準的k8s擴充套件機制。Tekton 有四個基本的物件 Task、TaskRun、Pipeline、PipelineRun ,下圖是Tekton Dashboard 的介面,可以直觀的感受一下 這幾個物件。

如下圖所示, Pipeline 範例化為 Pipeline Run,Pipeline Run 建立並管理 Pod,一個 Pod 對應 Task 的範例 Task Run,Task Run / Task 中的 step 對應 Pod 中的 container,除此Pod通常會共用一個 PersistentVolume 支援的臨時檔案系統。

參考: 產品路線圖 https://github.com/orgs/tektoncd/projects/26

  • Task 構建任務,是 Tekton 中不可分割的最小單位,正如同 Pod 在 Kubernetes 中的概念一樣。在 Task 中,可以有多個 Step,每個 Step 由一個 Container 來執行。
  • Pipeline 由一個或多個 Task 組成。在 Pipeline 中,使用者可以定義這些 Task 的執行順序以及依賴關係來組成 DAG(有向無環圖)。
  • Pipeline Run 是 Pipeline 的實際執行產物,當用戶定義好 Pipeline 後,可以通過建立 PipelineRun 的方式來執行流水線,並生成一條流水線記錄。
  • Task Run PipelineRun 被建立出來後,會對應 Pipeline 裡面的 Task 建立各自的 TaskRun。一個 TaskRun 控制一個 Pod,Task 中的 Step 對應 Pod 中的 Container。當然,TaskRun 也可以單獨被建立。

參照:https://cloud.tencent.com/developer/article/1803399

CLI

https://tekton.dev/docs/cli/

Tekton Trigger

可以通過http介面的形式觸發Tekton流水線,包括三個主要元件,設定有點繁瑣,如果是所有人都需要設定會瘋掉。

  • EventListner 監聽http請求的發起
  • TriggerTemplate 設定Pipeline Run
  • TriggerBinding 從http的request body中獲取資料傳遞給Pipeline Run

參考:https://tekton.dev/docs/getting-started/triggers/

Tekton Dashboard

後端的介面會轉發到k8s的api

參考:https://tekton.dev/docs/dashboard/install/
原始碼:https://github.com/tektoncd/dashboard

實踐

以下yaml檔案均儲存於 https://github.com/smallidea/tekton-test

部署

以 linux / mac 為例

# docker & docker-compose install
curl -o- https://smartidedl.blob.core.chinacloudapi.cn/docker/linux/docker-install.sh | bash

# Kubectl install
curl -LO https://smartidedl.blob.core.chinacloudapi.cn/kubectl/v1.23.0/bin/linux/amd64/kubectl
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# minikube install,參考 https://minikube.sigs.k8s.io/docs/start/
curl -LO https://smartidedl.blob.core.chinacloudapi.cn/minikube/v1.24.0/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikub
minikube delete
minikube start --image-mirror-country=cn --driver=docker --cpus=2 --memory=2048mb

# Tekton Pipeline & Dashboard install
kubectl apply -f https://gitee.com/chileeb/SmartIDE/raw/main/server/deployment/online/pipeline/v0.32.0/smartide-tekton-release.yaml
kubectl apply -f https://gitee.com/chileeb/SmartIDE/raw/main/server/deployment/online/dashboard/v0.32.0/smartide-tekton-dashboard-release.yaml

# Tekton Trigger install (選裝)
kubectl apply -f https://gitee.com/chileeb/SmartIDE/raw/main/server/deployment/online/trigger/v0.18.0/smartide-release.yaml
kubectl apply -f https://gitee.com/chileeb/SmartIDE/raw/main/server/deployment/online/trigger/v0.18.0/smartide-interceptor.yaml

# Tekton CLI, https://tekton.dev/docs/cli/
brew install tektoncd-cli

參考:SmartIDE (https://smartide.cn/zh/)的私有化部署指令碼
國內網路一鍵安裝
curl -o- https://gitee.com/chileeb/SmartIDE/raw/main/server/deployment/online/deployment_cn.sh | bash
國際網路一鍵安裝
curl -o- https://gitee.com/chileeb/SmartIDE/raw/main/server/deployment/online/deployment.sh | bash

範例

1. yaml

task.yaml

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: tekton-task-test
spec:
  description: >-
    This Task is test task to test Tekton.

  params:
    - name: USERNAME
      description: your name
      type: string
      default: 

  steps:
    - name: step-01
      image: ubuntu
      script: |
        #!/bin/bash
        echo "Hello World!"

    - name: step-02
      image: ubuntu
      script: |
        #!/bin/bash
        echo "I'm $(params.USERNAME)"

pipeline.yaml

apiVersion: tekton.dev/v1beta1
kind: Pipeline

metadata:
  name: tekton-pipeline-test

spec:
  params:
    - name: FIRST_NAME
      description: Your first name
      type: string
      default: "jason"
    - name: LAST_NAME
      description: Your last name
      type: string
      default: "chen"

  tasks:
    - name: task-001
      taskRef:
        name: tekton-task-test
      params:
        - name: USERNAME
          value: $(params.FIRST_NAME)

    - name: task-002
      runAfter:
        - task-001
      taskRef:
        name: tekton-task-test
      params:
        - name: USERNAME
          value: $(params.LAST_NAME)

pipeline_run.yaml

apiVersion: tekton.dev/v1beta1
kind: PipelineRun

metadata:
  name: tekton-pipeline-test-run-003

spec:
  pipelineRef:
    name: tekton-pipeline-test
  params:
    - name: FIRST_NAME
      value: "Jason"
    - name: LAST_NAME
      value: "Chen"

2. Pipeline Run

# apply
kubectl apply -f task.yaml
kubectl apply -f pipeline.yaml
kubectl apply -f pipeline-run.yaml

# 通過 Tekton CLI 檢視執行結果
tkn pipelinerun logs tekton-pipeline-test-run-003 -f -n default 


通過 Dashboard 檢視執行結果

3. Tekton Trigger

trigger.yaml

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: pipeline-binding-test
spec:
  params:
  - name: FIRST_NAME
    value: $(body.FIRST_NAME)
  - name: LAST_NAME
    value: $(body.LAST_NAME)

---

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: trigger-listener-test
spec:
  serviceAccountName: tekton-triggers-test-sa
  triggers:
    - name: trigger-test
      bindings:
        - ref: pipeline-binding-test
      template:
        ref: tekton-pipeline-test

---

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: pipeline-template-test
spec:
  params:
  - name: FIRST_NAME
    default: 
  - name: LAST_NAME
    default: 

  resourcetemplates:
  - apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      generateName: tekton-pipeline-test-run-
    spec:
      pipelineRef:
        name: tekton-pipeline-test
      params:
      - name: FIRST_NAME
        value: $(tt.params.FIRST_NAME)
      - name: LAST_NAME
        value: $(tt.params.LAST_NAME)

--- 

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tekton-triggers-test-sa

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: tekton-triggers-test-eventlistener-binding
subjects:
- kind: ServiceAccount
  name: tekton-triggers-test-sa
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: tekton-triggers-eventlistener-roles

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tekton-triggers-test-eventlistener-clusterbinding
subjects:
- kind: ServiceAccount
  name: tekton-triggers-test-sa
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: tekton-triggers-eventlistener-clusterroles
# apply
kubectl apply -f trigger.yaml
# 埠儘量不要使用常用的,避免衝突;如果是多個pipeline的trigger,記得埠保持唯一。
# Tekton Listener 對應service的名稱,一般是 el-<tekton listener name>
kubectl port-forward service/el-trigger-listener-test 9091:8080 --address 0.0.0.0 &

# 使用curl命令觸發
curl -v \
   -H 'content-Type: application/json' \
   -d '{"FIRST_NAME": "Tekton", "LAST_NAME": "CD"}' \
   http://localhost:9091