Workspaces
A Workspace is a declaration of a filesystem that a Task or Pipeline requires at runtime. Workspaces allow Tasks to declare parts of the filesystem that need to be provided at runtime, enabling data sharing between Tasks, persistent storage, and mounting of secrets, configurations, or common tools.
Why Workspaces are Needed
Traditional CI/CD Storage Challenges
In traditional CI/CD systems, sharing data between steps or jobs presents several challenges:
- Data Sharing: Difficulty in sharing data between different stages of a pipeline
- Storage Configuration: Complex configuration required for persistent storage
- Credentials Management: Insecure methods of providing credentials to jobs
- Flexibility: Limited options for storage types and configurations
- Reusability: Tasks often have hardcoded assumptions about storage locations
Tekton's Solution
Tekton Workspaces address these challenges by:
- Declarative Approach: Tasks declare their storage needs without specifying implementation
- Runtime Binding: Storage details are provided at runtime, not hardcoded in Tasks
- Flexible Implementation: Workspaces can be backed by various volume types
- Data Sharing: Workspaces enable sharing data between Tasks in a Pipeline
- Separation of Concerns: Task authors define storage needs, users provide the actual storage
Advantages
- Flexibility: Tasks can run with different storage implementations without modification
- Reusability: Tasks can be reused across different environments and storage configurations
- Security: Sensitive data can be provided securely through appropriate volume types
- Persistence: Data can be persisted between Task runs using PersistentVolumeClaims
- Isolation: Each TaskRun can have its own isolated storage
- Sharing: Multiple Tasks can share data through the same Workspace
Scenarios
Workspaces are useful in various scenarios, including:
- Source Code Access: Providing source code to build and test Tasks
- Artifact Storage: Storing build artifacts between Tasks
- Credential Provision: Securely providing credentials to Tasks
- Configuration Sharing: Sharing configuration files between Tasks
- Cache Storage: Maintaining a cache of dependencies or build artifacts
- Shared Tools: Providing access to common tools and utilities
Constraints and Limitations
- Workspaces backed by PersistentVolumeClaims with ReadWriteOnce access mode can only be mounted on one node at a time
- Workspaces backed by ConfigMaps or Secrets are limited to 1MB in size
- Workspaces backed by ConfigMaps or Secrets are always mounted as read-only
- Workspaces do not support dynamic provisioning of volumes without a VolumeClaimTemplate
- Workspace data persistence depends on the underlying volume type
Principles
Workspace Declaration
When declaring a Workspace:
- Tasks specify the name and optional properties of the Workspace
- Tasks define how the Workspace will be used (read-only or read-write)
- Tasks can specify a default mount path for the Workspace
- Tasks can mark a Workspace as optional
- TaskRuns or PipelineRuns provide the actual storage implementation
Workspace Binding
When binding a Workspace:
- TaskRuns or PipelineRuns specify the volume source for each Workspace
- Volume sources can be PersistentVolumeClaims, ConfigMaps, Secrets, or other types
- TaskRuns or PipelineRuns can specify a subPath within the volume
- PipelineRuns define how Workspaces are shared between Tasks
Configuration Examples
Basic Workspace in a Task
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build
spec:
workspaces:
- name: source
description: The workspace containing the source code
readOnly: false
steps:
- name: build
image: golang
workingDir: $(workspaces.source.path)
script: |
go build -o app .
Optional Workspace in a Task
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: lint
spec:
workspaces:
- name: cache
description: A workspace for caching linter data
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 ./...
Important Parameters
ReadOnly Flag
The readOnly flag indicates whether a Task will modify the contents of a Workspace.
Use Cases
- Preventing accidental modification of source code
- Sharing configuration data that should not be modified
- Allowing multiple Tasks to safely access the same Workspace concurrently
- Providing credentials that should not be altered
Principles
ReadOnly Workspaces:
- Are mounted as read-only volumes in the Task's containers
- Prevent Tasks from writing to the Workspace
- Allow for safer concurrent access by multiple Tasks
- Can be backed by read-only volume sources like ConfigMaps and Secrets
Configuration Example
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: test
spec:
workspaces:
- name: source
description: The workspace containing the source code
readOnly: true
steps:
- name: test
image: golang
workingDir: $(workspaces.source.path)
script: |
go test ./...
Optional Flag
The optional flag indicates that a Workspace is not required for a Task to execute.
Use Cases
- Providing optional caching for improved performance
- Supporting optional credential injection
- Making Tasks more flexible in different environments
- Allowing Tasks to adapt to the presence or absence of certain data
Principles
Optional Workspaces:
- Do not need to be provided in the TaskRun
- Tasks must handle the case when the Workspace is not provided
- Tasks can check if a Workspace is bound using the $(workspaces.name.bound) variable
- Enable more flexible and reusable Tasks
Configuration Example
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build-with-cache
spec:
workspaces:
- name: source
description: The workspace containing the source code
- name: cache
description: A cache for build artifacts
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
Isolated Workspaces
Isolated Workspaces allow restricting access to sensitive data to only specific Steps within a Task.
Use Cases
- Limiting access to credentials to only Steps that need them
- Protecting sensitive configuration from unnecessary exposure
- Implementing principle of least privilege within Tasks
- Reducing the risk of credential leakage
Principles
Isolated Workspaces:
- Are only mounted in the Steps that explicitly request them
- Require the enable-api-fields feature flag to be set to "beta"
- Allow for more secure handling of sensitive data
- Can have different mount paths in different Steps
Configuration Example
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: clone-and-build
spec:
workspaces:
- name: source
description: The workspace for the source code
- name: ssh-credentials
description: SSH credentials for git operations
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 .
Volume Sources
PersistentVolumeClaim
PersistentVolumeClaims provide durable storage that can persist beyond the lifetime of a TaskRun or PipelineRun.
Use Cases
- Sharing data between Tasks in a Pipeline
- Persisting build artifacts between Pipeline runs
- Maintaining a cache of dependencies
- Storing test results for later analysis
Principles
PersistentVolumeClaims:
- Provide durable storage backed by Kubernetes PersistentVolumes
- Can be pre-existing or created from a VolumeClaimTemplate
- Support different access modes (ReadWriteOnce, ReadWriteMany, ReadOnlyMany)
- Can be shared between multiple Tasks in a Pipeline
Configuration Example
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 provides temporary storage that exists only for the lifetime of a TaskRun.
Use Cases
- Temporary storage for a single TaskRun
- Sharing data between Steps in a Task
- Situations where persistence is not required
- Testing and debugging Tasks
Principles
EmptyDir:
- Creates a temporary directory that lasts only for the duration of the TaskRun
- Is automatically cleaned up when the TaskRun completes
- Cannot be shared between different TaskRuns
- Is suitable for Tasks that don't need to persist data
Configuration Example
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: build-with-emptydir
spec:
taskRef:
name: build
workspaces:
- name: source
emptyDir: {}
ConfigMap and Secret
ConfigMaps and Secrets provide a way to inject configuration data and sensitive information into Tasks.
Use Cases
- Providing configuration files to Tasks
- Injecting credentials for authentication
- Supplying environment-specific settings
- Sharing small amounts of read-only data
Principles
ConfigMaps and Secrets:
- Are always mounted as read-only volumes
- Are limited to 1MB in size
- Must exist before the TaskRun is created
- Are suitable for configuration data and credentials
Configuration Example
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
References