Kubernetes原生CI/CD流水线框架
Tekton 是一套以 CRD 形式运行在 Kubernetes 上的 CI/CD 框架。所有概念都是集群对象,没有任何需要长期驻留的「构建服务器」:流水线定义、每次执行、执行结果全部以 Kubernetes 资源的形式存在。
三层对象关系是理解 Tekton 的关键,必须分清「定义」与「执行」:
steps,每个 step 是一个容器。taskRef 引用 Task,或直接用 taskSpec 内联定义。runAfter 表达依赖)。<pipelinerun 名>-<pipeline 中 task 名>,并在自己的 status.childReferences 中列出这些子对象。也就是说:你提交的是 TaskRun / PipelineRun,Task 与 Pipeline 本身只被读取,不会被「运行」。
组件构成:
tkn) —— 命令行工具。要求 Kubernetes 1.28 或更高。所有组件都安装在 tekton-pipelines 命名空间:
# Pipelines(最新版)
kubectl apply --filename https://infra.tekton.dev/tekton-releases/pipeline/latest/release.yaml
# 指定版本(生产环境务必锁版本)
kubectl apply --filename \
https://infra.tekton.dev/tekton-releases/pipeline/previous/<version>/release.yaml
# 容器运行时不支持 tag@digest 时改用 release.notags.yaml
# Triggers(注意:截至目前官方 Triggers 文档仍指向旧的 GCS 地址)
kubectl apply --filename \
https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
kubectl apply --filename \
https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
# Dashboard(默认只读;需要写操作时用 release-full.yaml)
kubectl apply --filename \
https://infra.tekton.dev/tekton-releases/dashboard/latest/release.yaml
# 观察安装进度
kubectl get pods --namespace tekton-pipelines --watch
官方文档明确说明:这些清单「适用于快速开始,不适用于生产环境」,生产集群应改用 Tekton Operator 来安装与升级。
# macOS
brew install tektoncd-cli
# 需要作为 kubectl 插件使用时建软链接
ln -s $(brew --prefix)/opt/tektoncd-cli/bin/tkn /usr/local/bin/kubectl-tkn
# Linux(以 0.46.0 为例,注意文件名区分架构)
curl -LO https://github.com/tektoncd/cli/releases/download/v0.46.0/tkn_0.46.0_Linux_x86_64.tar.gz
sudo tar xvzf tkn_0.46.0_Linux_x86_64.tar.gz -C /usr/local/bin/ tkn
# Debian / RHEL 系也可以直接装包
sudo apt install -y tektoncd-cli
dnf copr enable chmouel/tektoncd-cli && dnf install tektoncd-cli
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build-and-push
spec:
params:
- name: image
type: string
workspaces:
- name: source
results:
- name: digest
description: 构建出的镜像 digest
steps:
- name: build
image: gcr.io/kaniko-project/executor:debug
script: |
#!/busybox/sh
/kaniko/executor --context=$(workspaces.source.path) \
--destination=$(params.image) --no-push
执行它:
# 用 tkn 启动
tkn task start build-and-push \
--param image=registry.example.com/app:1.0.0 \
--workspace name=source,claimName=my-pvc \
--showlog
# 查看 TaskRun 与日志
tkn taskrun list
tkn taskrun logs build-and-push-run-abcde -f # 持续输出
TaskRun 既可以用 taskRef 引用已存在的 Task,也可以把 Task 定义直接嵌进 taskSpec。注意一个硬限制:workspace 只能传递给内联的 taskSpec,不能在 taskRef 引用外部 Task 时注入 workspace。
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: ci-pipeline
spec:
params:
- name: git-url
type: string
workspaces:
- name: shared-data
tasks:
- name: clone
taskRef:
name: git-clone
params:
- name: url
value: $(params.git-url)
workspaces:
- name: output
workspace: shared-data
- name: test
runAfter: [clone]
taskRef:
name: run-tests
workspaces:
- name: source
workspace: shared-data
Pipeline 还支持 finally 段,其中的 Task 无论前面成功与否都会执行,适合做通知与清理。
# 启动 PipelineRun
tkn pipeline start ci-pipeline \
--param git-url=https://github.com/example/app.git \
--workspace name=shared-data,volumeClaimTemplateFile=workspace-template.yaml \
--showlog
# 一个 PipelineRun 会生成多个 TaskRun
tkn pipelinerun list
tkn pipelinerun logs ci-pipeline-run-abcde -f
# 查看它派生出的子对象
kubectl get pipelinerun ci-pipeline-run-abcde -o jsonpath='{.status.childReferences}'
PipelineRun 同样支持 pipelineRef(引用已存在的 Pipeline)或 pipelineSpec(内联定义)。
每个 step 是独立容器,步骤之间共享数据只能靠 workspace。在 PipelineRun/TaskRun 中为每个 workspace 绑定唯一一种 VolumeSource:
workspaces:
# 1. 复用已有 PVC
- name: source
persistentVolumeClaim:
claimName: my-pvc
subPath: app
# 2. 每次运行自动创建 PVC,运行结束随之删除
- name: source
volumeClaimTemplate:
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
# 3. 临时目录:只在同一个 TaskRun 的 steps 之间共享
- name: tmp
emptyDir: {}
# 4. 只读挂载(要求对象已存在,大小上限 1MB)
# - name: config
# configMap:
# name: build-config
# - name: creds
# secret:
# secretName: registry-creds
Triggers 用三件套把外部事件翻译成 PipelineRun:EventListener 接收请求,TriggerBinding 提取事件字段,TriggerTemplate 渲染出资源清单。
EventListener 会自动创建一个 Service 作为事件接收端点,配套的 RBAC 决定它能创建哪些资源:
kubectl get eventlistener
kubectl get svc -n default
TaskRun / PipelineRun 记录会持续累积,撑大 etcd。Tekton Pruner 通过两级 ConfigMap 控制保留策略:
# 全局策略(命名空间 tekton-pipelines,必须带 global 标签)
kubectl edit configmap tekton-pruner-default-spec -n tekton-pipelines
apiVersion: v1
kind: ConfigMap
metadata:
name: tekton-pruner-default-spec
namespace: tekton-pipelines
labels:
pruner.tekton.dev/config-type: global
data:
global-config: |
ttlSecondsAfterFinished: 300
successfulHistoryLimit: 3
enforcedConfigLevel: global
命名空间级策略使用同样带标签的 tekton-pruner-namespace-spec(数据键为 ns-config)。TTL 与历史条数两套规则独立生效,系统允许的最大 TTL 为 2592000 秒(30 天)。
TaskRun 的 Pod 默认使用 default ServiceAccount,在开启 Pod Security Admission restricted 策略的命名空间里会直接被拒绝:
# 在 feature-flags 中开启,让 Tekton 注入安全上下文
kubectl edit configmap feature-flags -n tekton-pipelines
# data:
# set-security-context: "true" # 默认为 false
config-defaults 里的 default-pod-template 可以给所有 TaskRun Pod 统一加上 nodeSelector、tolerations、securityContext 等。
tekton.dev/v1 里根本没有这个 kind,taskRef.kind: ClusterTask 会直接校验失败;替代方案是用命名空间级的 Task 加一个 ClusterResolver(需要开启 enable-cluster-resolver)。taskSpec」,用 taskRef 引用外部 Task 时无法从上层注入 workspace,只能依赖 Pipeline 层声明并在 Task 中同名声明。emptyDir 类型的 workspace 不能跨 Task 共享。它随 TaskRun 的 Pod 生灭,只有同一个 TaskRun 内的 steps 之间能共享;要在 Task 之间传文件必须用 PVC 或 volumeClaimTemplate。configMap / secret 挂载的 workspace 是只读的,且必须在提交前就存在,还有 1MB 大小上限 —— 不要把构建产物写进去。volumeClaimTemplate 生成的 PVC 随运行对象删除。删掉 PipelineRun,它的 PVC 也会被回收,想保留构建产物要用外部存储或提前绑定已有 PVC。tekton-pruner-* ConfigMap,注意两个 ConfigMap 都必须带对应的 pruner.tekton.dev/config-type 标签才会生效。restricted 命名空间下 Pod 起不来。Tekton 注入的容器默认不满足受限策略,需要把 feature-flags 里的 set-security-context 打开(默认是 false);该特性在 Windows 节点上不生效,部分发行版(如个别 OpenShift 环境)也可能不兼容。infra.tekton.dev,而 Triggers 的官方文档仍指向 storage.googleapis.com;升级前建议先确认目标版本的真实地址,不要按直觉把域名换掉。tkn hub 已废弃。Hub 的能力正在被并入 tkn 本体,新项目不要再基于 tkn hub 构建流程。config-defaults 或 Pod 模板中统一设置 requests/limits。kubectl — Kubernetes集群管理工具jenkins — CI/CD自动化服务器argo-workflows — Kubernetes原生工作流引擎gitlab-runner — GitLab CI 执行器skaffold — Kubernetes构建与部署流水线工具