在雲原生應用開發的實踐中,自動化是提升開發效率的核心驅動力。當代 DevOps 工程中,能夠自動回應程式碼變更的 CI/CD 流程已經成為基礎設施的標準配備。Tekton 作為 Kubernetes 原生的 CI/CD 框架,透過其 Triggers 元件提供了強大的事件驅動自動化能力,徹底改變了傳統的手動觸發模式。

事件驅動架構的核心價值

在雲原生環境中實作自動化 CI/CD 流程時,傳統的手動觸發或定時執行策略面臨著多重挑戰。手動觸發不僅缺乏即時性,還增加了人為操作的失誤風險。定時執行則會造成資源的無效浪費,在無變更時也會執行檢查,消耗叢集運算資源。

Tekton Triggers 採用事件驅動架構,從根本上解決了這些問題。當開發者推播程式碼或建立 Pull Request 時,Git 伺服器透過 webhook 機制呼叫 Tekton 提供的 API 端點,自動觸發對應的構建 Pipeline。這種即時回應的方式實現了真正的自動化 CI/CD 流程,讓開發團隊能夠專注於程式碼品質與業務邏輯,而不需要花費精力在佈署流程的手動操作上。

從實務經驗來看,事件驅動架構帶來的效益遠不止於自動化本身。它縮短了從程式碼提交到應用上線的時間週期,提升了系統回應速度。同時,自動化流程確保了每次佈署的一致性,降低了因手動操作差異導致的環境不一致問題。對於採用微服務架構的團隊而言,當需要管理數十個甚至上百個服務時,這種自動化能力變得尤為關鍵。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

actor 開發者
participant "Git 伺服器" as git
participant "EventListener" as el
participant "TriggerBinding" as tb
participant "TriggerTemplate" as tt
participant "PipelineRun" as pr
participant "Kubernetes" as k8s

開發者 -> git : 推播程式碼
git -> el : webhook 請求
el -> tb : 解析事件資料
tb -> tb : 提取關鍵欄位
tb -> tt : 傳遞參數
tt -> pr : 建立 PipelineRun
pr -> k8s : 執行 Pipeline
k8s -> k8s : 構建與佈署

note right of el
  接收 webhook 事件
  驗證請求來源
end note

note right of tb
  從 JSON 負載
  提取必要參數
end note

note right of tt
  使用參數實例化
  Pipeline 資源
end note

@enduml

Tekton Triggers 核心元件架構

Tekton Triggers 由三個協同工作的核心元件組成,形成完整的事件處理鏈路。這三個元件各司其職,透過清晰的介面協作,實現從接收外部事件到觸發 Pipeline 執行的完整流程。

EventListener 事件接收器

EventListener 扮演著對外介面的角色,作為可定址的端點接收來自外部系統的 webhook 請求。當佈署到 Kubernetes 叢集時,EventListener 會自動建立對應的 Pod 與 Service,提供 HTTP 端點供外部系統呼叫。

EventListener 的職責不僅限於接收請求,還包括初步的請求驗證與路由。它會檢查請求的合法性,確認請求格式符合預期,然後根據配置將請求轉發給對應的 TriggerBinding 進行處理。在企業環境中,EventListener 通常會配置 TLS 加密與身份驗證機制,確保只有授權的系統能夠觸發 Pipeline。

從架構設計角度來看,EventListener 提供了很好的擴展性。單一 EventListener 可以配置多個 Trigger,每個 Trigger 對應不同的處理邏輯。這使得同一個端點能夠處理來自不同來源或類型的事件,簡化了外部系統的整合工作。

TriggerBinding 參數提取器

TriggerBinding 負責從 webhook 請求的 JSON 負載中提取關鍵資訊。不同的 Git 平台發送的 webhook 格式各有差異,GitHub、GitLab、Bitbucket 等平台的 JSON 結構都不盡相同。TriggerBinding 透過靈活的路徑表達式,能夠適應各種格式的 webhook 資料。

TriggerBinding 的設計體現了關注點分離的原則。它只專注於資料提取這一單一職責,將事件資料轉換為標準化的參數格式。這些參數隨後會被傳遞給 TriggerTemplate,用於實例化具體的 Pipeline 資源。

在實務應用中,TriggerBinding 通常會提取程式碼倉庫 URL、提交雜湊值、分支名稱、提交訊息等關鍵資訊。這些資訊對於 Pipeline 的執行至關重要,決定了從哪裡獲取程式碼、構建哪個版本、以及如何標記產生的容器映像。

TriggerTemplate 資源範本

TriggerTemplate 定義了當事件觸發時要建立的 Kubernetes 資源範本。它接收來自 TriggerBinding 的參數,使用這些參數填充範本變數,最終生成具體的資源實例,通常是 PipelineRun 或 TaskRun。

TriggerTemplate 的設計採用了範本化模式,支援參數化配置。這意味著同一個範本可以根據不同的輸入參數生成不同的資源實例。例如,相同的範本可以處理不同倉庫的構建請求,只需透過參數指定不同的倉庫 URL 與分支即可。

範本中可以使用豐富的表達式語法,包括條件判斷、字串操作、預設值設定等。這種靈活性讓 TriggerTemplate 能夠處理複雜的業務邏輯,例如根據分支名稱決定佈署目標環境,或者根據提交訊息中的標籤執行不同的測試策略。

三個元件之間的協作流程清晰明確。EventListener 接收 webhook 請求,TriggerBinding 從請求中提取參數,TriggerTemplate 使用這些參數建立 Pipeline 執行實例。這種分層設計不僅提升了系統的可維護性,也增強了各元件的可重用性。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "Tekton Triggers 核心元件" {
  component "EventListener" as el {
    [HTTP 端點]
    [請求驗證]
    [路由分發]
  }
  
  component "TriggerBinding" as tb {
    [資料提取]
    [參數映射]
    [格式轉換]
  }
  
  component "TriggerTemplate" as tt {
    [範本定義]
    [參數替換]
    [資源生成]
  }
}

component "外部系統" as external
component "Kubernetes API" as k8s

external --> el : webhook 請求
el --> tb : 傳遞事件資料
tb --> tt : 傳遞提取參數
tt --> k8s : 建立資源

note right of el
  Service 對外暴露
  Pod 執行接收邏輯
end note

note right of tb
  支援多種 webhook 格式
  靈活的路徑表達式
end note

note right of tt
  參數化資源範本
  支援條件與預設值
end note

@enduml

實作 Git 變更自動觸發流程

在實際環境中建立完整的自動化 CI/CD 流程,需要正確配置權限並定義三個核心元件。以下展示如何建立一個回應 Git 推播事件的自動化構建流程。

定義 TriggerTemplate 資源範本

TriggerTemplate 定義了觸發事件時要建立的 Pipeline 執行實例。以下是一個完整的範本定義。

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
  name: tekton-greeter-triggertemplate
spec:
  params:
  - name: git-revision
  - name: git-commit-message
  - name: git-repo-url
  - name: git-repo-name
  - name: content-type
  - name: pusher-name
  resourcetemplates:
  - apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      labels:
        tekton.dev/pipeline: tekton-greeter-pipeline-hub
      name: tekton-greeter-pipeline-webhook-$(uid)
    spec:
      params:
      - name: GIT_REPO
        value: $(tt.params.git-repo-url)
      - name: GIT_REF
        value: $(tt.params.git-revision)
      serviceAccountName: tekton-triggers-example-sa
      pipelineRef:
        name: tekton-greeter-pipeline-hub
      workspaces:
      - name: app-source
        persistentVolumeClaim:
          claimName: app-source-pvc
      - name: maven-settings
        emptyDir: {}

這個範本接受多個輸入參數,核心參數包括 git-repo-url 指定程式碼倉庫位置,git-revision 標識要構建的提交雜湊值,git-commit-message 記錄提交訊息供追蹤使用,pusher-name 標記觸發者身份。

resourcetemplates 區段定義了要建立的資源清單。這裡建立一個 PipelineRun 資源,使用 uid 內建變數生成唯一的執行名稱,避免名稱衝突。params 區段將範本參數映射到 Pipeline 參數,建立參數傳遞通道。serviceAccountName 指定執行 Pipeline 的服務帳號,該帳號需要具備建立 Pod、存取儲存等必要權限。

workspaces 配置定義了 Pipeline 所需的工作空間。app-source 使用 PersistentVolumeClaim 提供持久化儲存,確保原始碼在不同 Task 間共享。maven-settings 使用 emptyDir 提供臨時儲存,適合儲存構建過程中的暫存檔案。

定義 TriggerBinding 參數映射

TriggerBinding 負責從 webhook JSON 負載中提取必要的資訊。

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: tekton-greeter-triggerbinding
spec:
  params:
  - name: git-repo-url
    value: $(body.repository.clone_url)
  - name: git-revision
    value: $(body.after)
  - name: git-commit-message
    value: $(body.head_commit.message)
  - name: pusher-name
    value: $(body.pusher.name)

這個 TriggerBinding 針對 GitHub webhook 格式設計。body.repository.clone_url 提取倉庫的 HTTPS 複製 URL,body.after 取得推播後的最新提交雜湊值,body.head_commit.message 擷取提交訊息,body.pusher.name 記錄推播者的使用者名稱。

路徑表達式使用點記法存取 JSON 物件的巢狀欄位。如果使用 GitLab 或其他 Git 平台,需要根據其 webhook 格式調整欄位路徑。例如 GitLab 使用 project.git_http_url 而非 repository.clone_url。

在設計 TriggerBinding 時,建議提取所有可能用到的資訊。即使當前 Pipeline 未使用某些參數,保留這些資訊也有助於未來的擴展需求,例如記錄審計日誌或實施條件執行邏輯。

定義 EventListener 事件端點

EventListener 將前兩個元件連接起來,建立實際的 webhook 接收端點。

apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: tekton-greeter-eventlistener
spec:
  serviceAccountName: tekton-triggers-example-sa
  triggers:
  - name: github-push-trigger
    bindings:
    - ref: tekton-greeter-triggerbinding
    template:
      ref: tekton-greeter-triggertemplate

EventListener 配置相對簡潔但功能強大。serviceAccountName 指定用於建立資源的服務帳號,該帳號需要具備建立 PipelineRun 與 Pod 的權限。triggers 區段定義一個或多個觸發器,每個觸發器關聯特定的 TriggerBinding 與 TriggerTemplate。

當 webhook 請求到達時,EventListener 會依序處理配置的觸發器。它使用 TriggerBinding 從請求中提取參數,然後將這些參數傳遞給 TriggerTemplate 建立新的 PipelineRun。整個過程完全自動化,無需人工介入。

EventListener 支援配置多個觸發器,每個觸發器可以使用不同的 Binding 與 Template 組合。這種設計讓單一端點能夠處理多種類型的事件,例如同時處理推播事件與 Pull Request 事件,根據事件類型執行不同的 Pipeline。

佈署與驗證 Triggers 配置

建立這些資源到 Kubernetes 叢集的過程非常直接。

kubectl create -f tekton-greeter-triggertemplate.yaml
kubectl create -f tekton-greeter-triggerbinding.yaml
kubectl create -f tekton-greeter-eventlistener.yaml

佈署完成後,Kubernetes 會自動建立對應的 Pod 與 Service。檢查 Pod 狀態確認 EventListener 正常運作。

kubectl get pods

應該會看到一個以 el 為前綴的 Pod 處於 Running 狀態,這代表 EventListener 已經啟動並準備接收請求。

NAME                                                READY   STATUS    RESTARTS   AGE
el-tekton-greeter-eventlistener-5db7b9fcf9-6nrgx   1/1     Running   0          10s

EventListener 會自動建立一個 Service 資源,提供穩定的網路端點。

kubectl get svc

輸出顯示 Service 的叢集內部 IP 與連接埠資訊。預設情況下,Service 類型為 ClusterIP,只能從叢集內部存取。

NAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
el-tekton-greeter-eventlistener  ClusterIP   10.100.36.199   <none>        8080/TCP,9000/TCP   10s

EventListener 暴露兩個連接埠。8080 是主要的 webhook 接收埠,接受 POST 請求。9000 是 metrics 埠,提供 Prometheus 格式的監控指標,便於觀察 EventListener 的運作狀態與效能表現。

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

[*] --> 建立資源定義

state 建立資源定義 {
  [*] --> TriggerTemplate
  TriggerTemplate --> TriggerBinding
  TriggerBinding --> EventListener
}

建立資源定義 --> 佈署到叢集 : kubectl create

state 佈署到叢集 {
  [*] --> 建立Pod
  建立Pod --> 建立Service
  建立Service --> 準備就緒
}

佈署到叢集 --> 接收請求 : webhook 呼叫
接收請求 --> 執行Pipeline

note right of 準備就緒
  Pod 狀態: Running
  Service 暴露端點
end note

note right of 執行Pipeline
  建立 PipelineRun
  執行構建流程
end note

@enduml

測試 Webhook 觸發機制

在生產環境中,Git 伺服器需要能夠存取 EventListener 端點。如果 Git 伺服器位於叢集外部,需要透過 Ingress 或 LoadBalancer 暴露 Service。在開發與測試階段,可以使用 port-forward 建立本地測試通道。

建立本地測試通道

port-forward 指令在本地機器與 Kubernetes Service 之間建立 TCP 連線通道。

kubectl port-forward svc/el-tekton-greeter-eventlistener 8080

這個指令將本地的 8080 連接埠轉發到 Service 的 8080 連接埠。執行後,可以透過 localhost:8080 存取 EventListener 端點,就如同直接存取叢集內的 Service。

port-forward 會持續執行直到手動中斷。在測試期間保持這個視窗開啟,讓測試請求能夠順利到達 EventListener。

模擬 GitHub Webhook 請求

使用 curl 工具可以精確模擬 Git 平台發送的 webhook 請求。

curl -X POST \
  http://localhost:8080 \
  -H 'Content-Type: application/json' \
  -d '{
    "after": "d9291c456db1ce29177b77ffeaa9b71ad80a50e6",
    "repository": {
      "clone_url": "https://github.com/gitops-cookbook/tekton-tutorial-greeter.git"
    },
    "head_commit": {
      "message": "Update application version"
    },
    "pusher": {
      "name": "developer"
    }
  }'

這個 POST 請求的 JSON 負載模擬了 GitHub 推播事件的結構。after 欄位包含最新提交的完整雜湊值,repository.clone_url 指定倉庫位置,head_commit.message 記錄提交訊息,pusher.name 標識推播者。

成功處理後,EventListener 會回傳包含事件資訊的 JSON 回應。

{
  "eventListener": "tekton-greeter-eventlistener",
  "namespace": "default",
  "eventListenerUID": "c00567eb-d798-4c4a-946d-f1732fdfc313",
  "eventID": "17dd25bb-a1fe-4f84-8422-c3abc5f10066"
}

回應包含 eventListener 名稱確認處理的端點,namespace 顯示資源所在命名空間,eventListenerUID 是 EventListener 實例的唯一識別碼,eventID 是此次事件的唯一追蹤 ID。這個 eventID 可用於日誌查詢與問題追蹤。

驗證 Pipeline 執行狀態

觸發成功後,新的 PipelineRun 會被建立並開始執行。使用 Tekton CLI 可以方便地檢視執行狀態。

tkn pipelinerun ls

輸出列出最近的 PipelineRun 實例,顯示名稱、建立時間與執行狀態。

NAME                                                           AGE              STATUS
tekton-greeter-pipeline-webhook-3244b67f-31d3-4597-af1c-3c1aa6693719   4 seconds ago   Running

PipelineRun 名稱包含了範本名稱與唯一 ID,確保每次觸發都會建立新的實例而不會發生名稱衝突。狀態欄顯示當前執行階段,包括 Running 執行中、Succeeded 成功完成、Failed 執行失敗等狀態。

進一步可以檢視執行細節與即時日誌。

tkn pipelinerun logs -f tekton-greeter-pipeline-webhook-3244b67f-31d3-4597-af1c-3c1aa6693719

這個指令會串流顯示 Pipeline 執行過程的日誌輸出,包括每個 Task 的執行狀況與輸出訊息。透過日誌可以追蹤構建進度,及時發現錯誤並進行除錯。

Kustomize 與 GitOps 配置自動化

在 GitOps 實踐中,應用程式碼與部署配置通常分別儲存在不同的倉庫。程式碼變更觸發 CI 流程產生新的容器映像後,需要自動更新部署配置倉庫中的映像參照。Kustomize 作為 Kubernetes 原生的配置管理工具,提供了簡潔的映像更新機制。

GitOps 雙倉庫模式

GitOps 架構通常採用雙倉庫策略。應用倉庫儲存原始碼、Dockerfile 與構建腳本,負責應用程式的開發與測試。配置倉庫儲存 Kubernetes 資源清單、Kustomize 配置與環境參數,負責應用的部署管理。

這種分離帶來多重優勢。開發團隊可以專注於程式碼品質,無需關心部署細節。運維團隊可以獨立管理配置,實施環境隔離與權限控管。版本管理更加清晰,程式碼版本與部署版本可以獨立追蹤。

自動化流程串接兩個倉庫。CI Pipeline 監控應用倉庫的變更,構建並推播新的容器映像。隨後 Pipeline 自動更新配置倉庫中的映像參照,並將變更提交回 Git。CD 工具如 Argo CD 監控配置倉庫,檢測到變更後自動同步到 Kubernetes 叢集。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "GitOps 雙倉庫架構" {
  component "應用倉庫" as app {
    [原始碼]
    [Dockerfile]
    [測試程式]
  }
  
  component "配置倉庫" as config {
    [Kubernetes YAML]
    [Kustomize 配置]
    [環境參數]
  }
}

component "CI Pipeline" as ci
component "容器註冊表" as registry
component "CD 工具" as cd
component "Kubernetes 叢集" as k8s

app --> ci : 推播程式碼
ci --> registry : 推播映像
ci --> config : 更新映像參照
config --> cd : 監控變更
cd --> k8s : 同步部署

note right of ci
  構建容器映像
  執行測試驗證
  更新配置倉庫
end note

note right of cd
  Argo CD 或 Flux
  自動同步機制
end note

@enduml

建立配置更新 Task

Tekton Task 可以封裝 Kustomize 的映像更新邏輯,實現自動化配置管理。

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-update-deployment
  annotations:
    tekton.dev/pipelines.minVersion: 0.12.1
    tekton.dev/tags: git
  labels:
    app.kubernetes.io/version: '0.2'
spec:
  description: 更新 Kubernetes 部署配置中的容器映像並推播變更到 Git 倉庫
  params:
  - name: GIT_REPOSITORY
    type: string
    description: 配置倉庫的 Git URL
  - name: GIT_REF
    type: string
    description: 要更新的分支名稱
  - name: NEW_IMAGE
    type: string
    description: 新的容器映像名稱
  - name: NEW_DIGEST
    type: string
    description: 新映像的 SHA256 摘要值
  - name: KUSTOMIZATION_PATH
    type: string
    description: kustomization.yaml 所在的目錄路徑
  results:
  - name: commit
    description: 提交的 SHA 雜湊值
  steps:
  - name: git-clone
    image: docker.io/alpine/git:v2.26.2
    workingDir: $(workspaces.workspace.path)
    script: |
      rm -rf git-update-digest-workdir
      git clone $(params.GIT_REPOSITORY) -b $(params.GIT_REF) git-update-digest-workdir
  - name: update-digest
    image: quay.io/wpernath/kustomize-ubi:latest
    workingDir: $(workspaces.workspace.path)
    script: |
      cd git-update-digest-workdir/$(params.KUSTOMIZATION_PATH)
      kustomize edit set image $(params.NEW_IMAGE)@$(params.NEW_DIGEST)
      echo "========== kustomization.yaml =========="
      cat kustomization.yaml
  - name: git-commit
    image: docker.io/alpine/git:v2.26.2
    workingDir: $(workspaces.workspace.path)
    script: |
      cd git-update-digest-workdir
      git config user.email "tektonbot@devops.local"
      git config user.name "Tekton Bot"
      git status
      git add $(params.KUSTOMIZATION_PATH)/kustomization.yaml
      git commit -m "[ci] 更新容器映像摘要"
      git push
      RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')"
      EXIT_CODE="$?"
      if [ "$EXIT_CODE" != 0 ]; then
        exit $EXIT_CODE
      fi
      echo -n "$RESULT_SHA" > $(results.commit.path)
  workspaces:
  - name: workspace
    description: Task 執行的工作空間

這個 Task 由三個步驟組成,形成完整的配置更新流程。git-clone 步驟使用輕量級的 alpine/git 映像複製配置倉庫。參數 GIT_REPOSITORY 指定倉庫位置,GIT_REF 指定要更新的分支。執行前會清理可能存在的舊工作目錄,確保乾淨的執行環境。

update-digest 步驟使用包含 Kustomize 工具的容器映像執行配置更新。進入 KUSTOMIZATION_PATH 指定的目錄後,執行 kustomize edit set image 指令。這個指令接受映像名稱與摘要值,自動更新 kustomization.yaml 中的 images 區段。更新後會輸出檔案內容供驗證,確認變更符合預期。

git-commit 步驟將變更推播回倉庫。首先配置 Git 使用者資訊,這對於提交識別與審計非常重要。執行 git add 暫存變更的檔案,然後提交並附上描述性訊息。推播到遠端倉庫後,取得新提交的 SHA 雜湊值並儲存到 Task 結果中,供後續 Task 使用。

整合到完整 Pipeline

將配置更新 Task 整合到 CI Pipeline 中,形成端到端的自動化流程。

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: pacman-pipeline
spec:
  params:
  - name: GIT_REPO
    type: string
    default: https://github.com/gitops-cookbook/pacman-kikd.git
  - name: GIT_REVISION
    type: string
    default: master
  - name: DESTINATION_IMAGE
    type: string
    default: quay.io/gitops-cookbook/pacman-kikd
  - name: CONTEXT_DIR
    type: string
    default: .
  - name: CONFIG_GIT_REPO
    type: string
    default: https://github.com/gitops-cookbook/pacman-kikd-manifests.git
  - name: CONFIG_GIT_REVISION
    type: string
    default: main
  tasks:
  - name: fetch-repo
    taskRef:
      name: git-clone
    params:
    - name: url
      value: $(params.GIT_REPO)
    - name: revision
      value: $(params.GIT_REVISION)
    - name: deleteExisting
      value: "true"
    workspaces:
    - name: output
      workspace: app-source
  - name: build-app
    taskRef:
      name: maven
    params:
    - name: GOALS
      value:
      - -DskipTests
      - clean
      - package
    - name: CONTEXT_DIR
      value: $(params.CONTEXT_DIR)
    workspaces:
    - name: maven-settings
      workspace: maven-settings
    - name: source
      workspace: app-source
    runAfter:
    - fetch-repo
  - name: build-push-image
    taskRef:
      name: buildah
    params:
    - name: IMAGE
      value: $(params.DESTINATION_IMAGE)
    workspaces:
    - name: source
      workspace: app-source
    runAfter:
    - build-app
  - name: git-update-deployment
    taskRef:
      name: git-update-deployment
    params:
    - name: GIT_REPOSITORY
      value: $(params.CONFIG_GIT_REPO)
    - name: NEW_IMAGE
      value: $(params.DESTINATION_IMAGE)
    - name: NEW_DIGEST
      value: $(tasks.build-push-image.results.IMAGE_DIGEST)
    - name: KUSTOMIZATION_PATH
      value: env/dev
    - name: GIT_REF
      value: $(params.CONFIG_GIT_REVISION)
    workspaces:
    - name: workspace
      workspace: app-source
    runAfter:
    - build-push-image
  workspaces:
  - name: app-source
  - name: maven-settings

這個 Pipeline 展示了完整的 GitOps CI 流程。fetch-repo Task 複製應用倉庫,取得最新的原始碼。build-app Task 使用 Maven 構建 Java 應用,生成可執行的 JAR 檔案。build-push-image Task 使用 Buildah 建立容器映像並推播到註冊表,同時輸出映像摘要值。

git-update-deployment Task 是流程的關鍵環節。它接收前一個 Task 輸出的映像摘要值,透過 tasks.build-push-image.results.IMAGE_DIGEST 語法存取。這個摘要值確保部署使用的是剛剛構建的精確版本,避免標籤漂移問題。Task 更新配置倉庫後,CD 工具會檢測到變更並觸發實際部署。

runAfter 欄位定義了 Task 的執行順序,確保每個階段在前置依賴完成後才開始。這種宣告式的依賴管理讓 Pipeline 邏輯清晰易懂,也便於平行化執行無依賴關係的 Task。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

start

:fetch-repo;
note right
  複製應用倉庫
  取得原始碼
end note

:build-app;
note right
  Maven 構建
  執行測試
end note

:build-push-image;
note right
  建立容器映像
  推播到註冊表
  輸出映像摘要
end note

:git-update-deployment;
note right
  更新配置倉庫
  使用映像摘要
  提交並推播
end note

:CD 工具檢測變更;

:同步到 Kubernetes;

stop

@enduml

Helm 自動化部署整合

Helm 作為 Kubernetes 的套件管理器,提供了強大的應用打包與版本管理能力。將 Helm 整合到 Tekton Pipeline 中,可以實現應用的自動化安裝與更新。

Helm 與 GitOps 的結合

在 GitOps 架構中,Helm Chart 可以作為應用部署的標準格式。Chart 定義了應用的所有 Kubernetes 資源,透過 values.yaml 檔案提供配置彈性。這種結構化的定義方式讓應用部署更加可預測與可重複。

Tekton 提供了專門的 Helm Task,封裝了常見的 Helm 操作。從 Tekton Hub 安裝這個 Task 非常簡單。

tkn hub install task helm-upgrade-from-repo

這個 Task 支援從 Helm 倉庫安裝或升級 Chart,自動處理版本管理與配置覆寫。它整合了 Helm 的最佳實踐,包括原子性升級、自動回復與歷史追蹤等功能。

設定 Helm 倉庫存取

在使用 Helm Task 前,需要將 Chart 倉庫註冊到本地環境。

helm repo add gitops-cookbook https://gitops-cookbook.github.io/helm-charts/

註冊後,可以使用倉庫前綴存取其中的 Chart。例如 gitops-cookbook/pacman 參照該倉庫中的 pacman Chart。倉庫機制簡化了 Chart 的分發與版本管理,團隊可以建立私有倉庫集中管理內部應用的 Chart。

建立 Helm 部署 TaskRun

TaskRun 定義了單次 Task 執行的具體參數與配置。

apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
  generateName: helm-pacman-run-
spec:
  serviceAccountName: tekton-deployer-sa
  taskRef:
    name: helm-upgrade-from-repo
  params:
  - name: helm_repo
    value: https://gitops-cookbook.github.io/helm-charts/
  - name: chart_name
    value: gitops-cookbook/pacman
  - name: release_version
    value: 0.1.0
  - name: release_name
    value: pacman
  - name: overwrite_values
    value: replicaCount=2

這個 TaskRun 示範了如何透過 Tekton 執行 Helm 部署。generateName 使用名稱前綴加隨機後綴的方式生成唯一名稱,適合重複執行的場景。serviceAccountName 指定執行 Task 的服務帳號,該帳號需要具備在目標命名空間操作 Helm 與 Kubernetes 資源的權限。

params 區段提供 Helm 操作所需的所有參數。helm_repo 指定倉庫 URL,chart_name 標識要部署的 Chart,release_version 指定 Chart 版本,release_name 定義 Helm Release 名稱。overwrite_values 參數允許覆寫 Chart 的預設值,這裡將副本數設定為 2。

執行 TaskRun 會觸發實際的 Helm 操作。

kubectl create -f helm-pacman-taskrun.yaml

Helm Task 會自動處理 Release 的生命週期。如果 Release 不存在會執行安裝,如果已存在則執行升級。這種冪等性設計確保了操作的可重複性,無論執行多少次都會達到相同的最終狀態。

檢視執行日誌可以追蹤 Helm 操作的詳細過程。

tkn taskrun logs -f

日誌會顯示 Helm 的完整輸出,包括當前已安裝的 Release 清單、升級操作的進度、新 Release 的狀態與版本資訊。透過日誌可以確認部署是否成功,以及應用的最終配置狀態。

將 Helm 整合到 CI/CD Pipeline

在完整的自動化流程中,Helm 部署通常作為 Pipeline 的最後階段。

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: app-deploy-pipeline
spec:
  params:
  - name: HELM_REPO
    type: string
  - name: CHART_NAME
    type: string
  - name: RELEASE_NAME
    type: string
  - name: IMAGE_TAG
    type: string
  tasks:
  - name: deploy-app
    taskRef:
      name: helm-upgrade-from-repo
    params:
    - name: helm_repo
      value: $(params.HELM_REPO)
    - name: chart_name
      value: $(params.CHART_NAME)
    - name: release_name
      value: $(params.RELEASE_NAME)
    - name: overwrite_values
      value: image.tag=$(params.IMAGE_TAG)

這個簡化的 Pipeline 展示了 Helm 部署的基本模式。在實際應用中,通常會將構建與部署整合到同一個 Pipeline。構建階段生成容器映像並輸出標籤或摘要值,部署階段使用這些值更新 Helm Release。

透過 overwrite_values 參數傳遞映像標籤,確保部署使用剛剛構建的新版本。這種動態配置機制讓 Pipeline 能夠自動串接不同階段,實現端到端的自動化部署。

安全性與最佳實踐

在生產環境中實施 Tekton Triggers,安全性考量至關重要。EventListener 暴露的 webhook 端點可能成為潛在的攻擊面,需要實施多層防護機制。

端點安全加固

EventListener 預設使用 HTTP 協定,在生產環境中應該啟用 TLS 加密。透過 Kubernetes Ingress 配置 TLS 終止,確保傳輸過程中的資料機密性。同時應該實施 webhook 簽名驗證,確認請求確實來自授權的 Git 平台。

GitHub 與 GitLab 都支援 webhook 密鑰機制。在 Git 平台配置 webhook 時設定密鑰,在 EventListener 端使用 Interceptor 驗證請求簽名。只有簽名驗證通過的請求才會被處理,有效防止未授權的觸發。

apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: secure-eventlistener
spec:
  serviceAccountName: tekton-triggers-sa
  triggers:
  - name: github-webhook
    interceptors:
    - name: verify-signature
      ref:
        name: github
      params:
      - name: secretRef
        value:
          secretName: github-webhook-secret
          secretKey: secretToken
    bindings:
    - ref: app-triggerbinding
    template:
      ref: app-triggertemplate

這個配置展示了如何整合 GitHub Interceptor 進行簽名驗證。Interceptor 從 Secret 中讀取密鑰,計算請求的預期簽名並與 HTTP 標頭中的簽名比對。驗證失敗的請求會被拒絕,不會觸發 Pipeline。

權限最小化原則

服務帳號的權限應該遵循最小化原則,只授予執行必要操作所需的最低權限。為 EventListener 與 Pipeline 建立專用的服務帳號,避免使用預設帳號或過高權限的帳號。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tekton-triggers-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: tekton-triggers-role
rules:
- apiGroups: ["tekton.dev"]
  resources: ["pipelineruns", "taskruns"]
  verbs: ["create", "get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: tekton-triggers-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: tekton-triggers-role
subjects:
- kind: ServiceAccount
  name: tekton-triggers-sa

這個 RBAC 配置定義了限定範圍的權限。服務帳號只能建立與檢視 PipelineRun 與 TaskRun,無法修改或刪除已存在的資源。這種精細的權限控制降低了安全風險,即使服務帳號被入侵也無法執行破壞性操作。

Git 認證管理

當 Pipeline 需要推播變更到 Git 倉庫時,需要提供適當的認證資訊。建議使用個人存取權杖而非密碼,並設定最小必要的權限範圍。

apiVersion: v1
kind: Secret
metadata:
  name: git-credentials
  annotations:
    tekton.dev/git-0: https://github.com
type: kubernetes.io/basic-auth
stringData:
  username: git
  password: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Secret 儲存 Git 認證資訊,透過 annotations 指定適用的 Git 伺服器。Tekton 會自動使用這個 Secret 進行 Git 操作認證。定期輪換權杖並審計使用記錄,確保認證資訊的安全性。

對於容器註冊表認證,同樣應該使用專用的 Secret。

apiVersion: v1
kind: Secret
metadata:
  name: registry-credentials
  annotations:
    tekton.dev/docker-0: https://quay.io
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <base64-encoded-config>

將這些 Secret 關聯到服務帳號,讓 Pipeline 能夠自動存取所需的外部系統。

kubectl patch serviceaccount tekton-bot-sa -p '{"secrets": [{"name": "git-credentials"}, {"name": "registry-credentials"}]}'

監控與審計

建立完整的監控與審計機制,追蹤 Pipeline 的執行狀況與資源使用情況。EventListener 暴露的 metrics 端點提供了豐富的監控指標,包括請求數量、處理延遲、錯誤率等。

整合 Prometheus 收集這些指標,配置告警規則及時發現異常。例如當錯誤率突然上升或處理延遲增加時,可能表示系統出現問題或遭受攻擊。

記錄所有 webhook 請求與 Pipeline 執行的審計日誌。這些日誌對於問題排查與安全事件調查非常重要。在生產環境中,應該將日誌集中儲存並設定適當的保留期限。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

package "安全防護層次" {
  component "網路層" as network {
    [TLS 加密]
    [Ingress 控制]
  }
  
  component "應用層" as app {
    [簽名驗證]
    [Interceptor]
  }
  
  component "權限層" as auth {
    [RBAC 控制]
    [服務帳號]
  }
  
  component "認證層" as cred {
    [Git Secret]
    [Registry Secret]
  }
}

component "外部請求" as external
component "Tekton Pipeline" as pipeline

external --> network
network --> app
app --> auth
auth --> cred
cred --> pipeline

note right of network
  HTTPS 端點
  IP 白名單
end note

note right of app
  Webhook 簽名
  請求驗證
end note

note right of auth
  最小權限原則
  角色分離
end note

@enduml

擴展性設計策略

隨著團隊規模與專案數量的成長,CI/CD 系統需要具備良好的擴展性。Tekton Triggers 的模組化設計為擴展提供了堅實基礎。

範本重用與參數化

建立可重用的 TriggerTemplate 與 TriggerBinding,透過參數化支援不同的應用與環境。避免為每個專案建立專用的 Trigger 配置,而是設計通用的範本透過參數客製化。

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
  name: generic-build-template
spec:
  params:
  - name: git-repo-url
  - name: git-revision
  - name: app-name
  - name: dockerfile-path
    default: Dockerfile
  - name: image-registry
  - name: target-namespace
    default: default
  resourcetemplates:
  - apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      generateName: $(tt.params.app-name)-build-
      namespace: $(tt.params.target-namespace)
    spec:
      pipelineRef:
        name: generic-build-pipeline
      params:
      - name: GIT_REPO
        value: $(tt.params.git-repo-url)
      - name: GIT_REF
        value: $(tt.params.git-revision)
      - name: IMAGE_NAME
        value: $(tt.params.image-registry)/$(tt.params.app-name)
      - name: DOCKERFILE
        value: $(tt.params.dockerfile-path)

這個通用範本支援多種應用的構建需求。透過參數指定應用名稱、倉庫位置、Dockerfile 路徑等,同一個範本可以服務不同的專案。提供合理的預設值簡化常見場景的配置。

條件執行與過濾

使用 Interceptor 實施條件邏輯,根據事件內容決定是否觸發 Pipeline。例如只在特定分支的推播時觸發,或者根據提交訊息中的標籤選擇執行策略。

apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: conditional-listener
spec:
  serviceAccountName: tekton-triggers-sa
  triggers:
  - name: main-branch-only
    interceptors:
    - name: filter-branch
      ref:
        name: cel
      params:
      - name: filter
        value: body.ref == 'refs/heads/main'
    bindings:
    - ref: app-triggerbinding
    template:
      ref: production-template
  - name: feature-branches
    interceptors:
    - name: filter-branch
      ref:
        name: cel
      params:
      - name: filter
        value: body.ref.startsWith('refs/heads/feature/')
    bindings:
    - ref: app-triggerbinding
    template:
      ref: development-template

CEL Interceptor 提供了強大的表達式語言,可以實施複雜的過濾邏輯。這個例子根據推播的分支選擇不同的範本,main 分支使用生產環境配置,feature 分支使用開發環境配置。

多租戶支援

在大型組織中,可能需要支援多個團隊共用 CI/CD 基礎設施。透過命名空間隔離與 RBAC 配置實現多租戶架構。

為每個團隊建立專用的命名空間,部署獨立的 EventListener 實例。團隊只能存取自己命名空間中的資源,無法干擾其他團隊的 Pipeline。使用標籤與註解標記資源的所屬團隊,便於管理與審計。

考慮使用 Tekton Operator 集中管理多個 Tekton 實例。Operator 簡化了安裝、升級與配置管理,確保所有實例使用一致的配置與版本。

總結與展望

Tekton Triggers 為 Kubernetes 環境提供了強大的事件驅動 CI/CD 能力。透過 EventListener、TriggerBinding、TriggerTemplate 三個核心元件的協作,實現了從外部事件到 Pipeline 執行的完整自動化。

結合 Kustomize 與 Helm 等工具,Tekton 能夠建構端到端的 GitOps 工作流程。從程式碼提交到容器構建,從配置更新到應用部署,整個流程完全自動化且可審計。這種架構不僅提升了開發效率,也確保了部署的一致性與可靠性。

在實施過程中,安全性考量至關重要。透過 TLS 加密、簽名驗證、權限最小化等機制,可以建立安全可靠的 CI/CD 系統。完善的監控與審計讓系統運作狀況清晰可見,問題能夠及時發現與處理。

隨著雲原生技術的持續演進,Tekton 生態系統也在不斷成長。新的功能如 Pipeline as Code、遠端 Task 執行、更豐富的 Interceptor 類型等,進一步增強了 Tekton 的能力。掌握 Tekton Triggers 的核心概念與最佳實踐,能夠為團隊建立現代化的 CI/CD 基礎設施,支撐業務的快速發展與創新。

在微服務與雲原生的時代,自動化不僅是提升效率的工具,更是確保系統可靠性與可擴展性的基礎。透過 Tekton Triggers 實現的事件驅動架構,讓開發團隊能夠專注於創造價值,將重複性的工作交給自動化系統處理。這正是現代 DevOps 文化的核心理念,也是雲原生技術帶來的革命性變革。