工作空间
工作空间是任务或管道在运行时所需的文件系统的声明。工作空间允许任务声明在运行时需要提供的文件系统部分,从而实现任务之间的数据共享、持久存储以及秘密、配置或公共工具的挂载。
为什么需要工作空间
传统 CI/CD 存储挑战
在传统的 CI/CD 系统中,步骤或作业之间共享数据面临几个挑战:
- 数据共享:在管道的不同阶段之间共享数据的困难
- 存储配置:持久存储所需的复杂配置
- 凭证管理:向作业提供凭证的不安全方法
- 灵活性:存储类型和配置的选项有限
- 重用性:任务通常对存储位置有硬编码的假设
Tekton 的解决方案
Tekton 工作空间通过以下方式解决这些挑战:
- 声明式方法:任务声明其存储需求,而不指定实现
- 运行时绑定:存储细节在运行时提供,而不是在任务中硬编码
- 灵活实现:工作空间可以由各种卷类型支持
- 数据共享:工作空间支持管道中任务之间的数据共享
- 关注点分离:任务作者定义存储需求,用户提供实际存储
优势
- 灵活性:任务可以在不同的存储实现上运行,而无需修改
- 重用性:任务可以在不同的环境和存储配置中重复使用
- 安全性:敏感数据可以通过适当的卷类型安全地提供
- 持久性:数据可以通过 PersistentVolumeClaims 在任务运行之间保持持久
- 隔离性:每个 TaskRun 都可以具有自己的独立存储
- 共享性:多个任务可以通过同一个工作空间共享数据
场景
工作空间在多个场景中非常有用,包括:
- 源代码访问:为构建和测试任务提供源代码
- 工件存储:在任务之间存储构建工件
- 凭证提供:安全地向任务提供凭证
- 配置共享:在任务之间共享配置文件
- 缓存存储:维护依赖项或构建工件的缓存
- 共享工具:提供对公共工具和实用程序的访问
限制和局限
- 由 PersistentVolumeClaims 支持的工作空间,使用 ReadWriteOnce 访问模式时,不能同时在多个节点上挂载
- 由 ConfigMaps 或 Secrets 支持的工作空间大小限制为 1MB
- 由 ConfigMaps 或 Secrets 支持的工作空间始终以只读方式挂载
- 工作空间不支持在没有 VolumeClaimTemplate 的情况下动态提供卷
- 工作空间的数据持久性取决于底层卷类型
原则
工作空间声明
在声明工作空间时:
- 任务指定工作空间的名称和可选属性
- 任务定义工作空间的使用方式(只读或读写)
- 任务可以指定工作空间的默认挂载路径
- 任务可以将工作空间标记为可选
- TaskRuns 或 PipelineRuns 提供实际的存储实现
工作空间绑定
在绑定工作空间时:
- TaskRuns 或 PipelineRuns 为每个工作空间指定卷源
- 卷源可以是 PersistentVolumeClaims、ConfigMaps、Secrets 或其他类型
- TaskRuns 或 PipelineRuns 可以在卷内指定 subPath
- PipelineRuns 定义工作空间在任务之间的共享方式
配置示例
任务中的基本工作空间
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build
spec:
workspaces:
- name: source
description: 包含源代码的工作空间
readOnly: false
steps:
- name: build
image: golang
workingDir: $(workspaces.source.path)
script: |
go build -o app .
任务中的可选工作空间
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: lint
spec:
workspaces:
- name: cache
description: 用于缓存 linter 数据的工作空间
optional: true
steps:
- name: lint
image: golangci/golangci-lint
script: |
if [ "$(workspaces.cache.bound)" == "true" ]; then
export GOLANGCI_LINT_CACHE=$(workspaces.cache.path)
fi
golangci-lint run ./...
重要参数
ReadOnly 标志
readOnly 标志指示任务是否会修改工作空间的内容。
使用场景
- 防止意外修改源代码
- 共享不应被修改的配置数据
- 允许多个任务安全地同时访问相同的工作空间
- 提供不应被更改的凭证
原则
只读工作空间:
- 在任务的容器中作为只读卷挂载
- 防止任务写入工作空间
- 允许多个任务更安全地并发访问
- 可以由 ConfigMaps 和 Secrets 等只读卷源支持
配置示例
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: test
spec:
workspaces:
- name: source
description: 包含源代码的工作空间
readOnly: true
steps:
- name: test
image: golang
workingDir: $(workspaces.source.path)
script: |
go test ./...
Optional 标志
optional 标志指示任务执行时工作空间不是必需的。
使用场景
- 提供可选缓存以提高性能
- 支持可选凭证注入
- 使任务在不同环境中更加灵活
- 允许任务适应特定数据的存在或缺失
原则
可选工作空间:
- 在 TaskRun 中不需要提供
- 任务必须处理工作空间未提供的情况
- 任务可以使用 $(workspaces.name.bound) 变量检查工作空间是否被绑定
- 使任务更加灵活和可重用
配置示例
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build-with-cache
spec:
workspaces:
- name: source
description: 包含源代码的工作空间
- name: cache
description: 构建工件的缓存
optional: true
steps:
- name: build
image: gradle
workingDir: $(workspaces.source.path)
script: |
if [ "$(workspaces.cache.bound)" == "true" ]; then
gradle build --build-cache --gradle-user-home=$(workspaces.cache.path)
else
gradle build
fi
隔离工作空间
隔离工作空间允许限制对敏感数据的访问,仅限于特定的步骤。
使用场景
- 限制对凭证的访问,仅限于需要的步骤
- 保护敏感配置免受不必要的暴露
- 在任务中实现最小特权原则
- 降低凭证泄露的风险
原则
隔离工作空间:
- 仅在明确请求的步骤中挂载
- 需要将 enable-api-fields 特性标志设置为 "beta"
- 允许更安全地处理敏感数据
- 在不同步骤中可以有不同的挂载路径
配置示例
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: clone-and-build
spec:
workspaces:
- name: source
description: 源代码的工作空间
- name: ssh-credentials
description: 用于 git 操作的 SSH 凭证
steps:
- name: clone
workspaces:
- name: ssh-credentials
image: alpine/git
script: |
mkdir -p ~/.ssh
cp $(workspaces.ssh-credentials.path)/* ~/.ssh/
chmod 600 ~/.ssh/id_rsa
git clone git@github.com:org/repo.git $(workspaces.source.path)
- name: build
image: golang
workingDir: $(workspaces.source.path)
script: |
go build -o app .
卷源
PersistentVolumeClaim
PersistentVolumeClaims 提供可持久化的存储,可以超出 TaskRun 或 PipelineRun 的生命周期。
使用场景
- 在管道中共享任务之间的数据
- 在管道运行之间持久化构建工件
- 维护依赖项的缓存
- 存储稍后分析的测试结果
原则
PersistentVolumeClaims:
- 提供通过 Kubernetes PersistentVolumes 支持的持久存储
- 可以是预先存在的或从 VolumeClaimTemplate 创建的
- 支持不同的访问模式(ReadWriteOnce、ReadWriteMany、ReadOnlyMany)
- 可以在管道中的多个任务之间共享
配置示例
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: build-with-pvc
spec:
taskRef:
name: build
workspaces:
- name: source
persistentVolumeClaim:
claimName: my-source-pvc
EmptyDir
EmptyDir 提供的临时存储仅存在于 TaskRun 的生命周期内。
使用场景
- 单个 TaskRun 的临时存储
- 在任务的步骤之间共享数据
- 不需要持久化的情况
- 测试和调试任务
原则
EmptyDir:
- 创建一个仅在 TaskRun 的持续时间内存在的临时目录
- 在 TaskRun 完成时自动清理
- 不能在不同的 TaskRuns 之间共享
- 适用于不需要持久化数据的任务
配置示例
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: build-with-emptydir
spec:
taskRef:
name: build
workspaces:
- name: source
emptyDir: {}
ConfigMap 和 Secret
ConfigMaps 和 Secrets 提供了一种将配置数据和敏感信息注入到任务中的方式。
使用场景
- 向任务提供配置文件
- 注入用于身份验证的凭证
- 提供特定于环境的设置
- 共享少量只读数据
原则
ConfigMaps 和 Secrets:
- 始终作为只读卷挂载
- 大小限制为 1MB
- 必须在创建 TaskRun 之前存在
- 适合用于配置数据和凭证
配置示例
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: deploy-with-config
spec:
taskRef:
name: deploy
workspaces:
- name: config
configMap:
name: deployment-config
- name: credentials
secret:
secretName: deployment-credentials
参考文献