Chapter 7. Sharing Data with Workspaces
Делаю:
31.08.2023
Workspaces are shared volumes used to transfer data between the various steps of a task.
Types of volume sources:
- emptyDir
- ConfigMap
- Secret
Using your first workspace
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: clone-and-list
spec:
params:
- name: repo
type: string
description: Git repository to be cloned
default: https://github.com/joellord/handson-tekton
workspaces:
- name: source
steps:
- name: clone
image: alpine/git
workingDir: $(workspaces.source.path)
command:
- /bin/sh
args:
- '-c'
- git clone -v $(params.repo) ./source
- name: list
image: alpine
workingDir: $(workspaces.source.path)
command:
- /bin/sh
args:
- "-c"
- ls ./source
EOF
$ tkn task start clone-and-list -w name=source,emptyDir="" --showlog
TaskRun started: clone-and-list-run-6j24m
Waiting for logs to be available...
[clone] Cloning into './source'...
[clone] POST git-upload-pack (175 bytes)
[clone] POST git-upload-pack (667 bytes)
[list] README.md
[list] app
[list] demo
[list] installation
Using workspaces with task runs
$ vi ~/tmp/clone-and-list-tr.yaml
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
generateName: git-clone-tr-
spec:
workspaces:
- name: source
emptyDir: {}
taskRef:
name: clone-and-list
$ kubectl create -f ~/tmp/clone-and-list-tr.yaml
$ tkn taskrun logs git-clone-tr-c22wd
[clone] Cloning into './source'...
[clone] POST git-upload-pack (175 bytes)
[clone] POST git-upload-pack (667 bytes)
[list] README.md
[list] app
[list] demo
[list] installation
Adding a workspace to a pipeline
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: clone
spec:
params:
- name: repo
type: string
description: Git repository to be cloned
default: https://github.com/joellord/handson-tekton
workspaces:
- name: source
steps:
- name: clone
image: alpine/git
workingDir: $(workspaces.source.path)
command:
- /bin/sh
args:
- '-c'
- git clone -v $(params.repo) ./source
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: list
spec:
workspaces:
- name: source
steps:
- name: list
image: alpine
workingDir: $(workspaces.source.path)
command:
- /bin/sh
args:
- "-c"
- ls ./source
EOF
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-and-list
spec:
workspaces:
- name: codebase
tasks:
- name: clone
taskRef:
name: clone
workspaces:
- name: source
workspace: codebase
- name: list
taskRef:
name: list
workspaces:
- name: source
workspace: codebase
runAfter:
- clone
EOF
$ tkn pipeline start clone-and-list --showlog
? Name for the workspace : codebase
? Value of the Sub Path :
? Type of the Workspace : emptyDir
? Type of EmptyDir :
result:
[clone : clone] Cloning into './source'...
[clone : clone] POST git-upload-pack (175 bytes)
[clone : clone] POST git-upload-pack (667 bytes)
[list : list] ls: ./source: No such file or directory
failed to get logs for task list : container step-list has failed : [{"key":"StartedAt","value":"2023-07-31T12:05:12.310Z","type":3}]
To share the content across tasks, you will need to use a persistent volume, which you will do in the next section.
Persisting data within a pipeline
$ cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: tekton-pv
spec:
storageClassName: manual
capacity:
storage: 2Gi
accessModes:
- ReadWriteMany
- ReadWriteOnce
- ReadOnlyMany
hostPath:
path: "/mnt/data"
EOF
$ cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tekton-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
EOF
$ tkn pipeline start clone-and-list \
-w name=codebase,claimName=tekton-pvc \
--showlog
PipelineRun started: clone-and-list-run-m9bf8
Waiting for logs to be available...
[clone : clone] Cloning into './source'...
[clone : clone] POST git-upload-pack (175 bytes)
[clone : clone] POST git-upload-pack (667 bytes)
[list : list] README.md
[list : list] app
[list : list] demo
[list : list] installation
Если выполнить второй раз - будет ошибка, т.к. данные из pvc не были удалены.
Cleaning up with finally
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: cleanup
spec:
workspaces:
- name: source
steps:
- name: remove-source
image: registry.access.redhat.com/ubi8/ubi
command:
- /bin/bash
args:
- "-c"
- "rm -rf $(workspaces.source.path)/source"
- name: message
image: registry.access.redhat.com/ubi8/ubi
command:
- /bin/bash
args:
- "-c"
- echo All files were deleted
EOF
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-and-list
spec:
workspaces:
- name: codebase
tasks:
- name: clone
taskRef:
name: clone
workspaces:
- name: source
workspace: codebase
- name: list
taskRef:
name: list
workspaces:
- name: source
workspace: codebase
runAfter:
- clone
finally:
- name: clean
taskRef:
name: cleanup
workspaces:
- name: source
workspace: codebase
EOF
$ tkn pipeline start clone-and-list \
-w name=codebase,claimName=tekton-pvc \
--showlog
PipelineRun started: clone-and-list-run-cdbxj
Waiting for logs to be available...
task clone has failed: "step-clone" exited with code 128 (image: "docker-pullable://alpine/git@sha256:7ee4031c1e08fb1646878c53059535b5e88bcf1f0ccb3aad3485362e2039d886"); for logs run: kubectl -n default logs clone-and-list-run-cdbxj-clone-pod -c step-clone
[clone : clone] fatal: destination path './source' already exists and is not an empty directory.
[clean : message] All files were deleted
Using workspaces in pipeline runs
$ vi ~/tmp/pipelinerun.yaml
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-and-ls-pr-
spec:
pipelineRef:
name: clone-and-list
workspaces:
- name: codebase
persistentVolumeClaim:
claimName: tekton-pvc
$ kubectl create -f ~/tmp/pipelinerun.yaml
$ tkn pr logs -f clone-and-ls-pr-hsqfz
[clone : clone] Cloning into './source'...
[clone : clone] POST git-upload-pack (175 bytes)
[clone : clone] POST git-upload-pack (667 bytes)
[list : list] README.md
[list : list] app
[list : list] demo
[list : list] installation
[clean : message] All files were deleted
Using volume claim templates
Instead of specifying a persistent volume claim directly, you can also ask Tekton to create a temporary one for you. This can be useful when you don’t need to persist data outside of your pipelines.
$ vi ~/tmp/pvc-template.yaml
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-and-ls-pr-
spec:
pipelineSpec:
workspaces:
- name: codebase
tasks:
- name: clone
taskRef:
name: clone
workspaces:
- name: source
workspace: codebase
- name: list
taskRef:
name: list
workspaces:
- name: source
workspace: codebase
runAfter:
- clone
workspaces:
- name: codebase
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
$ kubectl create -f ~/tmp/pvc-template.yaml
$ tkn pr logs -f clone-and-ls-pr-xwsnd
[clone : clone] Cloning into './source'...
[clone : clone] POST git-upload-pack (175 bytes)
[clone : clone] POST git-upload-pack (667 bytes)
[list : list] README.md
[list : list] app
[list : list] demo
[list : list] installation
This volume claim template creates a new PVC for each pipeline execution.
Assessments
Write and read
Create a task that uses a workspace to share information across its two steps. The first step will write a message, specified in a parameter, to a file in the workspace. The second step will output the content of the file in the logs.
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: write-read-workspace
spec:
workspaces:
- name: data
params:
- name: message
default: "Hello World"
type: string
description: "Message to write in the workspace"
steps:
- name: write
image: registry.access.redhat.com/ubi8/ubi
command:
- /bin/bash
args:
- -c
- echo "$(params.message)" > $(workspaces.data.path)/message.txt
- name: read
image: registry.access.redhat.com/ubi8/ubi
command:
- /bin/bash
args:
- -c
- cat $(workspaces.data.path)/message.txt
EOF
$ tkn task start write-read-workspace --showlog
? Value for param `message` of type `string`? (Default is `Hello World`) Hello World
Please give specifications for the workspace: data
? Name for the workspace : data
? Value of the Sub Path :
? Type of the Workspace : emptyDir
? Type of EmptyDir :
TaskRun started: write-read-workspace-run-sg2b5
Waiting for logs to be available...
[read] Hello World
Pick a card
Using the Deck of Cards API available at http://deckofcardsapi.com/, create a pipeline that will generate a new deck of cards and then pick a single card from it. The first call will generate a deck identifier (ID) that you can then use in the next task to pick a card. Output the card value and suit in the second task.
$ cat << 'EOF' | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: deck-api-create
spec:
workspaces:
- name: deck
steps:
- name: create-deck
image: registry.access.redhat.com/ubi8/ubi
script: |
curl https://deckofcardsapi.com/api/deck/new/shuffle/ -o $(workspaces.deck.path)/deck-id.txt
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: deck-api-draw
spec:
workspaces:
- name: deck
steps:
- name: draw
image: node:14
script: |
#!/usr/bin/env node
const fs = require("fs");
const https = require("https");
const deck = fs.readFileSync("$(workspaces.deck.path)/deck-id.txt");
const deckId = JSON.parse(deck).deck_id;
const URL = `https://deckofcardsapi.com/api/deck/${deckId}/draw/`;
console.log(URL);
https.get(URL, response => {
response.on("data", data => {
let card = JSON.parse(data).cards[0];
console.log("Card was drawn from the deck");
console.log(`${card.value} of ${card.suit}`);
})
});
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: pick-a-card
spec:
workspaces:
- name: api-data
tasks:
- name: create-deck
taskRef:
name: deck-api-create
workspaces:
- name: deck
workspace: api-data
- name: pick-card
taskRef:
name: deck-api-draw
workspaces:
- name: deck
workspace: api-data
runAfter:
- create-deck
EOF
$ tkn pipeline start pick-a-card --showlog
[pick-card : draw] internal/fs/utils.js:332
[pick-card : draw] throw err;
[pick-card : draw] ^
[pick-card : draw]
[pick-card : draw] Error: ENOENT: no such file or directory, open '/workspace/deck/deck-id.txt'
[pick-card : draw] at Object.openSync (fs.js:498:3)
[pick-card : draw] at Object.readFileSync (fs.js:394:35)
[pick-card : draw] at Object.<anonymous> (/tekton/scripts/script-0-4wfnl:4:17)
[pick-card : draw] at Module._compile (internal/modules/cjs/loader.js:1114:14)
[pick-card : draw] at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
[pick-card : draw] at Module.load (internal/modules/cjs/loader.js:979:32)
[pick-card : draw] at Function.Module._load (internal/modules/cjs/loader.js:819:12)
[pick-card : draw] at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)
[pick-card : draw] at internal/main/run_main_module.js:17:47 {
[pick-card : draw] errno: -2,
[pick-card : draw] syscall: 'open',
[pick-card : draw] code: 'ENOENT',
[pick-card : draw] path: '/workspace/deck/deck-id.txt'
[pick-card : draw] }
failed to get logs for task pick-card : container step-draw has failed : [{"key":"StartedAt","value":"2023-07-31T12:12:06.068Z","type":3}]
$ tkn pr logs -f pick-a-card-run-5kmmq
Hello admin
Build a pipeline that will return a different greeting, whether the username passed as a parameter is admin or something else. This pipeline should have two tasks. The first task will verify the username and output the role ( admin or user ) in the result. The second task will pick up this role and display the appropriate message from a ConfigMap mounted as a workspace.
$ cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: messages
data:
admin-welcome: Welcome master.
user-welcome: Hello user.
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: get-role
spec:
results:
- name: role
params:
- name: user
type: string
steps:
- name: check-username
image: registry.access.redhat.com/ubi8/ubi
script: |
#!/usr/bin/env bash
if [ "$(params.user)" == "admin" ]; then
echo "admin" > $(results.role.path)
else
echo "user" > $(results.role.path)
fi
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: role-based-greet
spec:
params:
- name: role
type: string
workspaces:
- name: messages
steps:
- name: greet
image: registry.access.redhat.com/ubi8/ubi
script: |
ROLE=$(params.role)
cat $(workspaces.messages.path)/$ROLE-welcome
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: admin-or-not
spec:
params:
- name: username
default: user
type: string
workspaces:
- name: message-map
tasks:
- name: validate-admin
taskRef:
name: get-role
params:
- name: user
value: $(params.username)
- name: greetings
taskRef:
name: role-based-greet
params:
- name: role
value: $(tasks.validate-admin.results.role)
workspaces:
- name: messages
workspace: message-map
runAfter:
- validate-admin
EOF
$ tkn pipeline start admin-or-not --showlog
? Value for param `username` of type `string`? (Default is `user`) [user]
Please give specifications for the workspace: [message-map]
? Name for the workspace : message-map
? Value of the Sub Path :
? Type of the Workspace : emptyDir
? Type of EmptyDir :
PipelineRun started: admin-or-not-run-lknhx
Waiting for logs to be available...
[greetings : greet] cat: /workspace/messages/user-welcome: No such file or directory
failed to get logs for task greetings : container step-greet has failed : [{"key":"StartedAt","value":"2023-07-31T12:14:06.534Z","type":3}]