Workspaces
Workspace 是对 Task 或 Pipeline 在运行时所需文件系统的声明。Workspaces 允许 Task 声明运行时需要提供的文件系统部分,实现 Task 之间的数据共享、持久存储,以及挂载 Secrets、配置或公共工具。
目录
为什么需要 Workspaces
传统 CI/CD 存储挑战
在传统 CI/CD 系统中,不同步骤或作业之间共享数据存在诸多挑战:
- 数据共享:难以在流水线的不同阶段共享数据
- 存储配置:持久存储配置复杂
- 凭证管理:向作业提供凭证的方法不安全
- 灵活性:存储类型和配置选项有限
- 可重用性:Task 通常对存储位置有硬编码假设
Tekton 的解决方案
Tekton Workspaces 通过以下方式解决这些挑战:
- 声明式方式:Task 声明其存储需求,无需指定具体实现
- 运行时绑定:存储细节在运行时提供,Task 中不硬编码
- 灵活实现:Workspaces 可以由多种卷类型支持
- 数据共享:Workspaces 使 Pipeline 中的 Task 之间共享数据成为可能
- 职责分离:Task 作者定义存储需求,用户提供实际存储
优势
- 灵活性:Task 可在不同存储实现下运行,无需修改
- 可重用性:Task 可跨不同环境和存储配置复用
- 安全性:敏感数据可通过合适的卷类型安全提供
- 持久性:数据可通过 PersistentVolumeClaims 在 Task 运行间持久保存
- 隔离性:每个 TaskRun 可拥有独立隔离的存储
- 共享性:多个 Task 可通过同一 Workspace 共享数据
适用场景
Workspaces 在多种场景中非常有用,包括:
- 源码访问:为构建和测试 Task 提供源码
- 产物存储:在 Task 之间存储构建产物
- 凭证提供:安全地向 Task 提供凭证
- 配置共享:在 Task 之间共享配置文件
- 缓存存储:维护依赖或构建产物缓存
- 共享工具:提供公共工具和实用程序访问
约束与限制
- 以 ReadWriteOnce 访问模式的 PersistentVolumeClaims 支持的 Workspace 一次只能挂载到一个节点
- 以 ConfigMaps 或 Secrets 支持的 Workspace 大小限制为 1MB
- 以 ConfigMaps 或 Secrets 支持的 Workspace 始终以只读方式挂载
- Workspace 不支持无 VolumeClaimTemplate 的动态卷供应
- Workspace 数据持久性取决于底层卷类型
原则
Workspace 声明
声明 Workspace 时:
- Task 指定 Workspace 的名称及可选属性
- Task 定义 Workspace 的使用方式(只读或读写)
- Task 可指定 Workspace 的默认挂载路径
- Task 可将 Workspace 标记为可选
- TaskRun 或 PipelineRun 提供实际存储实现
Workspace 绑定
绑定 Workspace 时:
- TaskRun 或 PipelineRun 指定每个 Workspace 的卷来源
- 卷来源可以是 PersistentVolumeClaims、ConfigMaps、Secrets 或其他类型
- TaskRun 或 PipelineRun 可指定卷内的子路径(subPath)
- PipelineRun 定义 Workspace 在 Task 之间的共享方式
配置示例
Task 中的基本 Workspace
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build
spec:
workspaces:
- name: source
description: 包含源码的 workspace
readOnly: false
steps:
- name: build
image: golang
workingDir: $(workspaces.source.path)
script: |
go build -o app .
Task 中的可选 Workspace
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: lint
spec:
workspaces:
- name: cache
description: 用于缓存 linter 数据的 workspace
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 标志指示 Task 是否会修改 Workspace 内容。
使用场景
- 防止源码被意外修改
- 共享不应被修改的配置数据
- 允许多个 Task 安全地并发访问同一 Workspace
- 提供不应被更改的凭证
原则
只读 Workspace:
- 在 Task 容器中以只读卷挂载
- 阻止 Task 写入 Workspace
- 允许多个 Task 更安全地并发访问
- 可由只读卷来源(如 ConfigMaps 和 Secrets)支持
配置示例
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: test
spec:
workspaces:
- name: source
description: 包含源码的 workspace
readOnly: true
steps:
- name: test
image: golang
workingDir: $(workspaces.source.path)
script: |
go test ./...
Optional 标志
optional 标志表示 Workspace 对 Task 执行不是必需的。
使用场景
- 提供可选缓存以提升性能
- 支持可选凭证注入
- 使 Task 在不同环境下更灵活
- 允许 Task 适应数据存在与否的情况
原则
可选 Workspace:
- TaskRun 中可不提供
- Task 需处理 Workspace 未提供的情况
- Task 可通过 $(workspaces.name.bound) 变量检查 Workspace 是否绑定
- 使 Task 更灵活且可重用
配置示例
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build-with-cache
spec:
workspaces:
- name: source
description: 包含源码的 workspace
- 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
隔离 Workspace
隔离 Workspace 允许限制对敏感数据的访问,仅限 Task 中特定的 Steps。
使用场景
- 限制凭证访问仅限需要的 Steps
- 保护敏感配置避免不必要暴露
- 在 Task 内实现最小权限原则
- 降低凭证泄露风险
原则
隔离 Workspace:
- 仅挂载在显式请求的 Steps 中
- 需要启用 enable-api-fields 功能标志为 "beta"
- 允许更安全地处理敏感数据
- 不同 Steps 可有不同挂载路径
配置示例
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: clone-and-build
spec:
workspaces:
- name: source
description: 源码 workspace
- 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 ssh://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 生命周期之外持续存在。
使用场景
- Pipeline 中 Task 之间共享数据
- Pipeline 运行间持久保存构建产物
- 维护依赖缓存
- 存储测试结果以供后续分析
原则
PersistentVolumeClaims:
- 提供由 Kubernetes PersistentVolumes 支持的持久存储
- 可为预先存在或由 VolumeClaimTemplate 创建
- 支持不同访问模式(ReadWriteOnce、ReadWriteMany、ReadOnlyMany)
- 可在 Pipeline 中多个 Task 之间共享
配置示例
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 的临时存储
- Task 中 Steps 之间共享数据
- 不需要持久化的场景
- Task 测试和调试
原则
EmptyDir:
- 创建仅在 TaskRun 期间存在的临时目录
- TaskRun 完成后自动清理
- 不能在不同 TaskRun 之间共享
- 适合不需要持久化数据的 Task
配置示例
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: build-with-emptydir
spec:
taskRef:
name: build
workspaces:
- name: source
emptyDir: {}
ConfigMap 和 Secret
ConfigMaps 和 Secrets 提供向 Task 注入配置数据和敏感信息的方式。
使用场景
- 向 Task 提供配置文件
- 注入认证凭证
- 提供环境特定设置
- 共享少量只读数据
原则
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
参考资料