status | title | creation-date | last-updated | authors | see-also | ||||
---|---|---|---|---|---|---|---|---|---|
implemented |
Propagating Workspaces |
2022-06-03 |
2022-09-16 |
|
|
This proposal builds on prior work to reduce the verbosity of passing Workspaces to improve usability of Tekton Pipelines.
The verbosity of writing specifications in Tekton Pipelines is a common pain point that creates difficulties in
getting-started scenarios. In addition, the verbosity leads to long specifications that are error-prone, harder to
maintain, and reach the etcd size limits for CRDs. Automatically propagating Workspaces
will lead to better user
experience.
apiVersion: v1
kind: ConfigMap
metadata:
name: sensitive-recipe-storage
data:
brownies: |
My secret recipe!
---
apiVersion: v1
kind: Secret
metadata:
name: secret-password
type: Opaque
data:
password: aHVudGVyMg==
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
spec:
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 16Mi
volumeMode: Filesystem
- name: recipe-store
configMap:
name: sensitive-recipe-storage
items:
- key: brownies
path: recipe.txt
- name: password-vault
secret:
secretName: secret-password
pipelineSpec:
workspaces:
- name: password-vault
- name: recipe-store
- name: shared-data
tasks:
- name: fetch-secure-data
workspaces:
- name: secret-password
workspace: password-vault
- name: secure-store
workspace: recipe-store
- name: filedrop
workspace: shared-data
taskSpec:
workspaces:
- name: secret-password
- name: secure-store
- name: filedrop
steps:
- name: fetch-and-write-secure
image: ubuntu
script: |
if [ "hunter2" = "$(cat $(workspaces.secret-password.path)/password)" ]; then
cp $(workspaces.secure-store.path)/recipe.txt $(workspaces.filedrop.path)
echo "success!!!"
else
echo "wrong password!"
exit 1
fi
- name: print-the-recipe
workspaces:
- name: filedrop
workspace: shared-data
runAfter:
- fetch-secure-data
taskSpec:
workspaces:
- name: filedrop
steps:
- name: print-secrets
image: ubuntu
script: cat $(workspaces.filedrop.path)/$(params.filename)
We propose interpolating Workspaces
in embedded specifications during resolution. With this approach, we do not mutate the specifications before storage. The Workspaces
that are required by each Step
of the PipelineTask
are determined by extracting the Workspace
variables from their Script
and Args
. Only the Workspaces
required by the Steps
of the PipelineTask
are propagated through to it. From the PipelineTasks
(at TaskRun
creation time) they are propagated down to the TaskSpec
(before Pod
creation).
The propagation of Workspaces
will only work for embedded specifications.
# Embedded specifications of a PipelineRun
apiVersion: v1
kind: ConfigMap
metadata:
name: sensitive-recipe-storage
data:
brownies: |
My secret recipe!
---
apiVersion: v1
kind: Secret
metadata:
name: secret-password
type: Opaque
data:
password: aHVudGVyMg==
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
spec:
params:
- name: filename
value: recipe.txt
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 16Mi
volumeMode: Filesystem
- name: recipe-store
configMap:
name: sensitive-recipe-storage
items:
- key: brownies
path: recipe.txt
- name: password-vault
secret:
secretName: secret-password
pipelineSpec:
#workspaces:
# - name: password-vault
# - name: recipe-store
# - name: shared-data
tasks:
- name: fetch-secure-data
# workspaces:
# - name: password-vault
# - name: recipe-store
# - name: shared-data
taskSpec:
# workspaces:
# - name: password-vault
# - name: recipe-store
# - name: shared-data
steps:
- name: fetch-and-write-secure
image: ubuntu
script: |
if [ "hunter2" = "$(cat $(workspaces.password-vault.path)/password)" ]; then
cp $(workspaces.recipe-store.path)/recipe.txt $(workspaces.shared-data.path)
echo "success!!!"
else
echo "wrong password!"
exit 1
fi
- name: print-the-recipe
# workspaces:
# - name: shared-data
runAfter:
- fetch-secure-data
taskSpec:
# workspaces:
# - name: shared-data
steps:
- name: print-secrets
image: ubuntu
script: cat $(workspaces.shared-data.path)/$(params.filename)
---
# Successful execution of the above PipelineRun
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
...
spec:
params:
- name: filename
value: recipe.txt
pipelineSpec:
tasks:
- name: fetch-secure-data
taskSpec:
steps:
- image: ubuntu
name: fetch-and-write-secure
resources: {}
script: |
if [ "hunter2" = "$(cat $(workspaces.password-vault.path)/password)" ]; then
cp $(workspaces.recipe-store.path)/recipe.txt $(workspaces.shared-data.path)
echo "success!!!"
else
echo "wrong password!"
exit 1
fi
- name: print-the-recipe
runAfter:
- fetch-secure-data
taskSpec:
steps:
- image: ubuntu
name: print-secrets
resources: {}
script: cat $(workspaces.shared-data.path)/$(params.filename)
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 16Mi
volumeMode: Filesystem
- configMap:
items:
- key: brownies
path: recipe.txt
name: sensitive-recipe-storage
name: recipe-store
- name: password-vault
secret:
secretName: secret-password
status:
completionTime: "2022-06-02T18:17:02Z"
conditions:
- lastTransitionTime: "2022-06-02T18:17:02Z"
message: 'Tasks Completed: 2 (Failed: 0, Canceled 0), Skipped: 0'
reason: Succeeded
status: "True"
type: Succeeded
pipelineSpec:
...
taskRuns:
recipe-time-lslt9-fetch-secure-data:
pipelineTaskName: fetch-secure-data
status:
...
taskSpec:
steps:
- image: ubuntu
name: fetch-and-write-secure
resources: {}
script: |
if [ "hunter2" = "$(cat /workspace/password-vault/password)" ]; then
cp /workspace/recipe-store/recipe.txt /workspace/shared-data
echo "success!!!"
else
echo "wrong password!"
exit 1
fi
workspaces:
- name: password-vault
- name: recipe-store
- name: shared-data
recipe-time-lslt9-print-the-recipe:
pipelineTaskName: print-the-recipe
status:
...
taskSpec:
steps:
- image: ubuntu
name: print-secrets
resources: {}
script: cat /workspace/shared-data/recipe.txt
workspaces:
- name: shared-data
The propagation of Workspaces
will not work for referenced specifications
because the behavior would become opaque when users can't see the relationship between Workspaces
declared in the referenced resources and the Workspaces
supplied in runtime resources. Attempting to propagate Workspaces
to referenced resources will cause failures.
# PipelineRun attempting to propagate Workspaces to referenced Tasks
apiVersion: v1
kind: ConfigMap
metadata:
name: sensitive-recipe-storage
data:
brownies: |
My secret recipe!
---
apiVersion: v1
kind: Secret
metadata:
name: secret-password
type: Opaque
data:
password: aHVudGVyMg==
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-task-storage
spec:
resources:
requests:
storage: 16Mi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: fetch-secure-data
spec:
steps:
- name: fetch-and-write
image: ubuntu
script: |
if [ "hunter2" = "$(cat $(workspaces.password-vault.path)/password)" ]; then
cp $(workspaces.recipe-store.path)/recipe.txt $(workspaces.shared-data.path)
else
echo "wrong password!"
exit 1
fi
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: print-data
spec:
params:
- name: filename
steps:
- name: print-secrets
image: ubuntu
script: cat $(workspaces.shared-data.path)/$(params.filename)
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: fetch-and-print-recipe
spec:
tasks:
- name: fetch-the-recipe
taskRef:
name: fetch-secure-data
- name: print-the-recipe
taskRef:
name: print-data
runAfter:
- fetch-the-recipe
params:
- name: filename
value: recipe.txt
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
spec:
pipelineRef:
name: fetch-and-print-recipe
workspaces:
- name: password-vault
secret:
secretName: secret-password
- name: recipe-store
configMap:
name: sensitive-recipe-storage
items:
- key: brownies
path: recipe.txt
- name: shared-data
persistentVolumeClaim:
claimName: shared-task-storage
---
# Failed execution of the above PipelineRun
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
...
spec:
pipelineRef:
name: fetch-and-print-recipe
workspaces:
- name: password-vault
secret:
secretName: secret-password
- configMap:
items:
- key: brownies
path: recipe.txt
name: sensitive-recipe-storage
name: recipe-store
- name: shared-data
persistentVolumeClaim:
claimName: shared-task-storage
status:
completionTime: "2022-06-02T19:02:58Z"
conditions:
- lastTransitionTime: "2022-06-02T19:02:58Z"
message: 'Tasks Completed: 1 (Failed: 1, Canceled 0), Skipped: 1'
reason: Failed
status: "False"
type: Succeeded
pipelineSpec:
...
taskRuns:
recipe-time-v5scg-fetch-the-recipe:
pipelineTaskName: fetch-the-recipe
status:
completionTime: "2022-06-02T19:02:58Z"
conditions:
- lastTransitionTime: "2022-06-02T19:02:58Z"
message: |
"step-fetch-and-write" exited with code 1 (image: "docker.io/library/ubuntu@sha256:26c68657ccce2cb0a31b330cb0be2b5e108d467f641c62e13ab40cbec258c68d"); for logs run: kubectl -n default logs recipe-time-v5scg-fetch-the-recipe-pod -c step-fetch-and-write
reason: Failed
status: "False"
type: Succeeded
...
taskSpec:
steps:
- image: ubuntu
name: fetch-and-write
resources: {}
script: | # See below: Replacements do not happen.
if [ "hunter2" = "$(cat $(workspaces.password-vault.path)/password)" ]; then
cp $(workspaces.recipe-store.path)/recipe.txt $(workspaces.shared-data.path)
else
echo "wrong password!"
exit 1
fi
In the case of embedded specifications that have references, we will propagate the Workspaces
up to the embedded specification level only. Users would need to explicitly declare Workspaces
wherever they reference resources. See the example PipelineRun
below for more details.
# PipelineRun attempting to propagate Workspaces to referenced Tasks
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: fetch-secure-data
spec:
workspaces: # If Referenced, Workspaces need to be explicitly declared
- name: recipe-store
- name: shared-data
- name: password-vault
steps:
- name: fetch-and-write
image: ubuntu
script: |
if [ "hunter2" = "$(cat $(workspaces.password-vault.path)/password)" ]; then
cp $(workspaces.recipe-store.path)/recipe.txt $(workspaces.shared-data.path)
else
echo "wrong password!"
exit 1
fi
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
spec:
workspaces:
- name: password-vault
secret:
secretName: secret-password
- name: recipe-store
configMap:
name: sensitive-recipe-storage
items:
- key: brownies
path: recipe.txt
- name: shared-data
persistentVolumeClaim:
claimName: shared-task-storage
pipelineSpec:
# workspaces: # Since this is embedded specs, Workspaces don’t need to be declared
# ...
tasks:
- name: fetch-the-recipe
workspaces: # If referencing resources, Workspaces need to be explicitly declared
- name: recipe-store
- name: shared-data
- name: password-vault
taskRef: # Referencing a resource
name: fetch-secure-data
- name: print-the-recipe
# workspaces: # Since this is embedded specs, Workspaces don’t need to be declared
# ...
taskSpec:
# workspaces: # Since this is embedded specs, Workspaces don’t need to be declared
# ...
params:
- name: filename
steps:
- name: print-secrets
image: ubuntu
script: cat $(workspaces.shared-data.path)/$(params.filename)
runAfter:
- fetch-the-recipe
params:
- name: filename
value: recipe.txt
---
# Successful execution of the above PipelineRun
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: recipe-time-
...
spec:
pipelineSpec:
...
workspaces:
- name: password-vault
secret:
secretName: secret-password
- configMap:
items:
- key: brownies
path: recipe.txt
name: sensitive-recipe-storage
name: recipe-store
- name: shared-data
persistentVolumeClaim:
claimName: shared-task-storage
status:
completionTime: "2022-06-09T18:42:14Z"
conditions:
- lastTransitionTime: "2022-06-09T18:42:14Z"
message: 'Tasks Completed: 2 (Failed: 0, Cancelled 0), Skipped: 0'
reason: Succeeded
status: "True"
type: Succeeded
pipelineSpec:
...
taskRuns:
recipe-time-pj6l7-fetch-the-recipe:
pipelineTaskName: fetch-the-recipe
status:
...
taskSpec:
steps:
- image: ubuntu
name: fetch-and-write
resources: {}
script: |
if [ "hunter2" = "$(cat /workspace/password-vault/password)" ]; then
cp /workspace/recipe-store/recipe.txt /workspace/shared-data
else
echo "wrong password!"
exit 1
fi
workspaces:
- name: recipe-store
- name: shared-data
- name: password-vault
recipe-time-pj6l7-print-the-recipe:
pipelineTaskName: print-the-recipe
status:
...
taskSpec:
params:
- name: filename
type: string
steps:
- image: ubuntu
name: print-secrets
resources: {}
script: cat /workspace/shared-data/recipe.txt
workspaces:
- name: shared-data
Propagating all Workspaces
defined at PipelineRun
down to all the PipelineTasks
regardless of whether they are used by that PipelineTask
. However, a workspace may have sensitive data that we don’t want to be accessible to all tasks. This approach is rejected because we only want data available where it is needed. We could remove the unwanted workspaces just before creating the task pod but this method will in turn also propagate workspaces for referenced parameters which we want to avoid because the behavior becomes opaque when users can't see the relationship between Workspaces declared in the referenced resources and the Workspaces supplied in runtime resources.