Tekton(三)逐步深入:掌握Tekton中Task和TaskRun的用法和原理
- August 23, 2023
在现代软件开发中,持续集成和持续交付(CI/CD)已经成为标配。Kubernetes生态系统中的Tekton项目为我们提供了一种强大而灵活的方式来实现自动化的CI/CD流程。其中,Task
和TaskRun
是Tekton中的两个重要概念,它们是构建流水线的基础。本文将深入介绍Task
和TaskRun
的使用,帮助您更好地掌握Tekton的能力
什么是Task?
Task
是Tekton中定义一个具体操作的单元。它可以看作是一个独立的步骤,用于执行特定的操作,比如构建代码、运行测试、部署应用等等,Task一般可以复用。每个Task
都可以包含多个Step
,Step
是Task
中的基本执行单元。
以下是一个简单的Task
示例,仅仅用于输出Hello World
:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: hello
spec:
steps:
- name: echo
image: alpine
script: |
#!/bin/sh
echo "Hello World"
在这个示例中,我们定义了一个名为 hello
的 Task
,其中包含了一个名为 echo
的 Step
,这个 Step
使用 Alpine 镜像执行脚本以输出 “Hello World”。
什么是Step?
步骤(Step) 是 Tekton Pipelines 中的一个关键概念,用于定义任务(Task)中要执行的实际操作。步骤是构成任务的基本单位,它描述了任务中的一个原子操作,可以是运行容器、执行脚本、构建镜像等。步骤的定义使得任务可以分解为多个独立的操作,从而实现任务的复杂性和灵活性。每个步骤都包含以下关键信息:
- 名称(Name):每个步骤都需要一个名称以唯一标识它,确保任务中的每个步骤都有明确的标识。
- 镜像(Image):步骤运行的容器镜像,通常是一个可执行环境,例如 Linux 基础镜像、特定编程语言的运行时等。
- 脚本(Script):在步骤中可以指定要运行的脚本,脚本可以是 Shell 脚本、Python 脚本、Bash 脚本等,用于执行特定的操作。
- 工作目录(Working Directory):步骤可以指定执行操作时的工作目录,以确保操作在正确的上下文中进行。
- 环境变量(Environment Variables):可以在步骤中定义需要的环境变量,这些环境变量可以用于在步骤执行时传递参数、配置、认证信息等。
步骤的灵活性允许开发者将任务分解为更小的、可重用的操作,从而更好地进行任务的组织和管理。在实际的 CI/CD 流程中,步骤可以代表构建、测试、部署、通知等不同的操作,每个步骤都可以独立执行,并且可以通过资源的传递和共享来实现任务之间的协作。
什么是TaskRun?
TaskRun
是Task
的实例化,它表示实际的任务运行。TaskRun
包含了要执行的Task
的引用以及一些参数配置,比如输入和输出的工作空间、环境变量等。
也就是我们定义好Task后,并不会真正的执行,如果想要让Task执行其他,还需要创建一个TaskRun。
以下是一个简单的TaskRun
示例,使用上面定义的hello
任务:
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: hello-task-run
spec:
taskRef:
name: hello
通过执行这个 TaskRun
,会生成一个 Pod,该 Pod 内有一个容器,容器执行的内容就是之前定义的脚本。您可以使用 Tekton 提供的 Dashboard 或 kubectl
命令来查看具体的执行情况。
随即,我们查看此次生成的资源pod、task、taskrun
可以看到:
- 生成taskrun后,会立即生成一个pod用于执行任务,该pod包含一个容器
- 任务执行完成后,pod的
STATUS
转为STATUS
。taskrun的SUCCEEDED
转为True
,REASON
转换为Succeeded
- 执行
kubectl logs hello-task-run-pod
可查看pod的日志
➜ ~ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-task-run-pod 0/1 Completed 0 58s
➜ ~ kubectl get task
NAME AGE
hello 65s
➜ ~ kubectl get taskruns
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
hello-task-run True Succeeded 75s 61s
➜ ~ kubectl logs hello-task-run-pod
Defaulted container "step-echo" out of: step-echo, prepare (init), place-scripts (init)
Hello World
除了直接在taskrun
中使用taskref
来绑定task,还可以直接taskrun
的taskSpec
中直接将所需的Task
定义直接嵌入到TaskRun
来达到相同的效果(不推荐)。
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: hello-task-run
spec:
taskSpec:
steps:
- name: echo
image: alpine
script: |
#!/bin/sh
echo "Hello World"
从Git拉取代码
既然对Task和TaskRun有了一定的了解,那么我们直接来点实际的吧!!!
Tekton主要用于CI/CD,那么肯定少不了用到代码仓库,那么,接下来我们使用Tekton来完成Git的拉取来进一步巩固。
-
首先定义Task,执行
git clone
命令,将代码仓库拉取到/workspace/source
目录下。apiVersion: tekton.dev/v1beta1 kind: Task metadata: name: clone spec: steps: - name: clone image: alpine/git script: | git clone https://gitee.com/lomtom/demo-nodejs.git -b main /workspace/source ls /workspace/source
-
定义TaskRun来让Task实际跑起来。
apiVersion: tekton.dev/v1beta1 kind: TaskRun metadata: name: clone-task-run spec: taskRef: name: clone
最终效果如下:
了解参数Params
前面有说Task可以复用,但是以目前的例子来说,脚本内的url和分支都是写死的,Task完全不能复用呀?🤔
那么就需要了解一下Task的参数了。
- 参数的命名规范:只能包含字母数字字符、连字符 (
-
)、下划线 (_
) 和点 (.
)。但是,object
参数名称及其键名称不能包含点 (.
)。并且必须以字母或下划线 (_
) 开头。 - 参数的值覆盖:在创建 TaskRun 时,可以通过设置 TaskRun 中的参数值来覆盖 Task 中定义的默认值。确保在 TaskRun 中正确配置参数,以满足具体的执行需求。如果参数没有隐式默认值,则必须显式设置其值
- 参数的类型:参数有三种类型:
string
,array
(beta 功能) 或object
(beta 功能),其中string类型最为常用 - 参数的默认值:参数可以在定义的时候设置默认值
- 参数的使用:若定义参数url,可在task中使用
$(params.url)
来获取参数值
那么如何将之前的Git的拉取改造成可复用的呢?
-
将Task的的url、branch抽出,由Task的params进行传递,需要定义两个参数
url
、branch
的名称和类型。apiVersion: tekton.dev/v1beta1 kind: Task metadata: name: param spec: params: - name: url description: Repository URL to clone from. type: string - name: branch description: Repository branch type: string steps: - name: param image: alpine/git script: | git clone $(params.url) -b $(params.branch) /workspace/source ls /workspace/source
-
在TaskRun中
spec.params
定义参数url
、branch
将参数值传入Task。apiVersion: tekton.dev/v1beta1 kind: TaskRun metadata: name: param-task-run spec: taskRef: name: param params: - name: url value: "https://gitee.com/lomtom/demo-nodejs.git" - name: branch value: "main"
最终执行效果:
了解空间Workspace
Workspace 允许在 Tekton 的 Pipeline 中的不同任务之间共享文件和数据,以便进行构建、测试、部署等操作。每个任务都可以定义一个或多个 Workspace,以指定其输入和输出的文件路径。这样,不同任务可以将文件从一个 Workspace 传递到另一个 Workspace,以便在任务之间共享数据。
Workspace 的用途:
- 存储输入和输出: 每个任务可以定义一个或多个 Workspace,用于存储输入和输出数据。例如,在构建任务中,输入 Workspace 可以包含源代码,输出 Workspace 可以包含构建生成的二进制文件。
- 任务间数据共享: 任务可以通过 Workspace 将数据从一个任务传递到另一个任务。这对于在流水线中不同的阶段之间共享数据非常有用,例如在构建后将构建好的应用程序传递给部署任务。
- 挂载凭证和配置: Workspace 可以作为挂载点,用于将凭证(如用户名和密码)或配置(如 API 密钥)从 Kubernetes 的 Secret 或 ConfigMap 中传递给任务。
- 共享工具: Workspace 可以作为任务所需的常用工具的挂载点。这样,可以确保所有任务都可以访问一组共享的工具,而不需要每个任务都重新安装。
- 构建缓存: Workspace 可以作为存储构建产生的缓存,这些工件可以在后续任务中加速处理。这在多个任务需要相同构建结果时特别有用。
要配置一个或多个 Workspace 在一个 Task 中,需要在 Task 的定义中添加一个 workspaces 列表,其中每个条目使用以下字段:
- name -(必需)用于引用 Workspace 的唯一字符串标识符。
- description - 描述 Workspace 用途的信息性字符串。
- readOnly - 一个布尔值,指示任务是否会向 Workspace 写入数据。默认为 false。
- optional - 一个布尔值,指示 TaskRun 是否可以省略 Workspace。默认为 false。
- mountPath - Workspace 在磁盘上可用于步骤的位置路径。如果未提供 mountPath,则 Workspace 将默认放置在 /workspace/
,其中 是 Workspace 的唯一名称。
请注意以下几点:
- Task 定义可以包括所需数量的 Workspace。建议任务最多使用一个可写 Workspace。
- 只读 Workspace 的卷将以只读方式挂载。尝试向只读 Workspace 写入数据将导致错误和失败的 TaskRun。
以下是一个实际的例子,例子中定义了一个名叫source
的workspace,并且挂载在/workspace/source
,最后将steps.workingDir
的值设置为$(workspaces.source.path)
,即表明当前step的工作目录为/workspace/source
。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: workspace
spec:
params:
- name: url
description: Repository URL to clone from.
type: string
workspaces:
- name: source
description: code source
mountPath: /workspace/source
steps:
- name: param
image: alpine/git
workingDir: $(workspaces.source.path)
script: |
git clone $(params.url) $(workspaces.source.path)
ls
随后,为改Task
定义TaskRun
,其中,spec.workspaces
指明使用的工作空间的类型为临时目录的emptyDir
。
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: workspace-task-run
spec:
taskRef:
name: workspace
params:
- name: url
value: "https://gitee.com/lomtom/demo-nodejs.git"
workspaces:
- name: source
emptyDir: {}
最终运行结果:
上方例子使用了emptyDir
类型的worksapce
,worksapce
的类型包括:
-
emptyDir
:emptyDir 是一个临时的空目录,它在容器运行期间存在,但在容器终止后会被清除。它适用于需要在任务运行期间临时存储数据的场景。 -
configMap
:configMap 是 Kubernetes 中的一种资源类型,用于存储配置数据。在 Tekton 中,可以将 configMap 挂载到 Workspace 中,使任务可以读取其中的配置信息。 -
secret
:secret 是 Kubernetes 中的一种资源类型,用于存储敏感数据,如密码、令牌等。在 Tekton 中,可以将 secret 挂载到 Workspace 中,使任务可以读取其中的敏感数据。 -
projected
:projected Workspace 允许将多个 Kubernetes 资源(如 configMap、secret)投影到一个 Workspace 中。它将这些资源的内容合并到一个目录中,任务可以从中读取。 -
csi
:csi(Container Storage Interface)是 Kubernetes 中用于连接外部存储系统的接口。csi Workspace 允许将外部存储挂载到任务容器中,以实现持久性存储。
# 1. emptyDir
workspaces:
- name: source
emptyDir: {}
# 2. configmap
workspaces:
- name: source
configmap:
name: my-configmap
# 3. secretName
workspaces:
- name: source
secret:
secretName: my-secret
# 4. projected
workspaces:
- name: source
projected:
sources:
- configMap:
name: my-configmap
- secret:
name: my-secret
# 5. csi
workspaces:
- name: my-credentials
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-database"
了解多任务
前面的例子是一个代码克隆的例子,如果想要在克隆后,完成编译等操作,就需要使用多任务进行执行。
想要使用多任务,也非常简单,只需要在Task
中新增step即可。在原有的基础上新增两个step:
- npm-install:执行npm的依赖安装
- npm-build:执行项目构建
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: steps
spec:
params:
- name: url
description: Repository URL to clone from.
type: string
workspaces:
- name: source
description: code source
mountPath: /workspace/source
steps:
- name: clone-repo
image: alpine/git
workingDir: $(workspaces.source.path)
script: |
git clone $(params.url) $(workspaces.source.path)
ls
- name: npm-install
image: node:14.19
workingDir: $(workspaces.source.path)
script: |
npm config set registry https://mirrors.huaweicloud.com/repository/npm/
npm install
- name: npm-build
image: node:14.19
workingDir: $(workspaces.source.path)
script: |
npm run build
ls
因为没有额外的参数或者工作空间改动,所以无需修改TaskRun
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: steps-task-run
spec:
taskRef:
name: steps
params:
- name: url
value: "https://gitee.com/lomtom/demo-nodejs.git"
workspaces:
- name: source
emptyDir: {}
最后运行结果:
实现镜像构建kaniko
在编译完成之后,就需要将编译完成的产物打成镜像,那么就需要新增一个step,镜像构建。
Kaniko可用于构建镜像,详情可访问:Kaniko:容器构建的灵活解决方案
这个示例中的 Tekton Task 定义的作用是构建一个 Docker 镜像。具体来说,它的功能和步骤如下:
- 克隆代码: 在
clone-repo
步骤中,使用alpine/git
镜像执行 Git 命令,从指定的仓库 URL 克隆代码到 Workspace 中,并列出文件。这将获取代码以供后续步骤使用。 - 安装依赖: 在
npm-install
步骤中,使用node:14.19
镜像执行npm install
命令,安装项目所需的依赖。这是构建过程中的一项常见操作。 - 构建项目: 在
npm-build
步骤中,继续使用node:14.19
镜像执行npm run build
命令,完成项目的构建。这可能包括编译、打包等操作。 - 使用 Kaniko 构建 Docker 镜像: 在
kaniko-build
步骤中,使用bitnami/kaniko:1.13.0
镜像执行 Kaniko 构建。Kaniko 是一个用于构建容器映像的工具,它可以在 Kubernetes 集群内部构建 Docker 镜像。在构建过程中,它会使用之前克隆的代码和构建的结果,根据提供的参数构建出一个 Docker 镜像。并且将镜像仓库的认证信息挂载到/kaniko/.docker
目录下。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kaniko
spec:
params:
- name: url
description: Repository URL to clone from.
type: string
- name: dockerfile
description: Dockerfile path
type: string
- name: context
description: Docker build context
type: string
- name: image
description: Docker image name
type: string
workspaces:
- name: source
description: code source
mountPath: /workspace/source
- name: docker-config
description: Includes a docker `config.json`
optional: true
mountPath: /kaniko/.docker
steps:
- name: clone-repo
image: alpine/git
workingDir: $(workspaces.source.path)
script: |
git clone $(params.url) $(workspaces.source.path)
ls /kaniko/.docker -al
ls
- name: npm-install
image: node:14.19
workingDir: $(workspaces.source.path)
script: |
npm config set registry https://mirrors.huaweicloud.com/repository/npm/
npm install
- name: npm-build
image: node:14.19
workingDir: $(workspaces.source.path)
script: |
npm run build
ls
- name: kaniko-build
image: bitnami/kaniko:1.13.0
workingDir: $(workspaces.source.path)
args:
- --dockerfile=$(params.dockerfile)
- --context=$(params.context)
- --destination=$(params.image)
随后为此Task创建TaskRun:
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: kaniko-task-run
spec:
taskRef:
name: kaniko
params:
- name: url
value: "https://gitee.com/lomtom/demo-nodejs.git"
- name: dockerfile
value: "Dockerfile"
- name: context
value: "./"
- name: image
value: "swr.cn-east-3.myhuaweicloud.com/lomtom-demo/lomtom:temp"
workspaces:
- name: source
emptyDir: {}
- name: docker-config
secret:
secretName: pull-secret
注意:
- 在
workspace
部分中,定义了一个名为docker-config
的工作空间,类型为secret,所以需要提前创建好一个名叫pull-secret
,类型为Opaque
的密钥。 - 在项目内存在Dockerfile文件
kind: Secret
apiVersion: v1
metadata:
name: pull-secret
data:
config.json: >-
<此处为base64>
type: Opaque最后运行结果:
更多示例请查看tekton_example 🔗
- 1-basic:基本使用
- 2-clone:使用Task克隆代码
- 3-param:在Task中使用参数
- 4-workspace:在Task中使用workspace
- 5-steps:在Task中使用多步骤
- 6-kaniko:使用kaniko构建镜像(使用workspace挂载secret)
- 7-kaniko-new:使用kaniko构建镜像(使用volumes挂载secret)
- 8-docker:使用docker构建镜像
- 9-pipeline:使用pipeline
- 10-multi-task:使用多任务
- 11-multi-docker-task:在多任务中使用docker构建镜像