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 时:

  1. Task 指定 Workspace 的名称及可选属性
  2. Task 定义 Workspace 的使用方式(只读或读写)
  3. Task 可指定 Workspace 的默认挂载路径
  4. Task 可将 Workspace 标记为可选
  5. TaskRun 或 PipelineRun 提供实际存储实现

Workspace 绑定

绑定 Workspace 时:

  1. TaskRun 或 PipelineRun 指定每个 Workspace 的卷来源
  2. 卷来源可以是 PersistentVolumeClaims、ConfigMaps、Secrets 或其他类型
  3. TaskRun 或 PipelineRun 可指定卷内的子路径(subPath)
  4. 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

参考资料