Tekton(三)逐步深入:掌握Tekton中Task和TaskRun的用法和原理

Tekton(三)逐步深入:掌握Tekton中Task和TaskRun的用法和原理

在现代软件开发中,持续集成和持续交付(CI/CD)已经成为标配。Kubernetes生态系统中的Tekton项目为我们提供了一种强大而灵活的方式来实现自动化的CI/CD流程。其中,TaskTaskRun是Tekton中的两个重要概念,它们是构建流水线的基础。本文将深入介绍TaskTaskRun的使用,帮助您更好地掌握Tekton的能力

什么是Task?

Task是Tekton中定义一个具体操作的单元。它可以看作是一个独立的步骤,用于执行特定的操作,比如构建代码、运行测试、部署应用等等,Task一般可以复用。每个Task都可以包含多个StepStepTask中的基本执行单元。

以下是一个简单的Task示例,仅仅用于输出Hello World:

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: hello
spec:
  steps:
    - name: echo
      image: alpine
      script: |
        #!/bin/sh
        echo "Hello World"

在这个示例中,我们定义了一个名为 helloTask,其中包含了一个名为 echoStep,这个 Step 使用 Alpine 镜像执行脚本以输出 “Hello World”。

什么是Step?

步骤(Step) 是 Tekton Pipelines 中的一个关键概念,用于定义任务(Task)中要执行的实际操作。步骤是构成任务的基本单位,它描述了任务中的一个原子操作,可以是运行容器、执行脚本、构建镜像等。步骤的定义使得任务可以分解为多个独立的操作,从而实现任务的复杂性和灵活性。每个步骤都包含以下关键信息:

  1. 名称(Name):每个步骤都需要一个名称以唯一标识它,确保任务中的每个步骤都有明确的标识。
  2. 镜像(Image):步骤运行的容器镜像,通常是一个可执行环境,例如 Linux 基础镜像、特定编程语言的运行时等。
  3. 脚本(Script):在步骤中可以指定要运行的脚本,脚本可以是 Shell 脚本、Python 脚本、Bash 脚本等,用于执行特定的操作。
  4. 工作目录(Working Directory):步骤可以指定执行操作时的工作目录,以确保操作在正确的上下文中进行。
  5. 环境变量(Environment Variables):可以在步骤中定义需要的环境变量,这些环境变量可以用于在步骤执行时传递参数、配置、认证信息等。

步骤的灵活性允许开发者将任务分解为更小的、可重用的操作,从而更好地进行任务的组织和管理。在实际的 CI/CD 流程中,步骤可以代表构建、测试、部署、通知等不同的操作,每个步骤都可以独立执行,并且可以通过资源的传递和共享来实现任务之间的协作。

什么是TaskRun?

TaskRunTask的实例化,它表示实际的任务运行。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 命令来查看具体的执行情况。

image-20230811231228215

随即,我们查看此次生成的资源pod、task、taskrun

可以看到:

  • 生成taskrun后,会立即生成一个pod用于执行任务,该pod包含一个容器
  • 任务执行完成后,pod的STATUS转为STATUS。taskrun的SUCCEEDED转为TrueREASON转换为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,还可以直接taskruntaskSpec中直接将所需的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的拉取来进一步巩固。

  1. 首先定义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
    
  2. 定义TaskRun来让Task实际跑起来。

    apiVersion: tekton.dev/v1beta1
    kind: TaskRun
    metadata:
      name: clone-task-run
    spec:
      taskRef:
        name: clone
    

最终效果如下:

image-20230811234702257

了解参数Params

前面有说Task可以复用,但是以目前的例子来说,脚本内的url和分支都是写死的,Task完全不能复用呀?🤔

那么就需要了解一下Task的参数了。

  • 参数的命名规范:只能包含字母数字字符、连字符 ( -)、下划线 ( _) 和点 ( .)。但是,object参数名称及其键名称不能包含点 ( .)。并且必须以字母或下划线 ( _) 开头。
  • 参数的值覆盖:在创建 TaskRun 时,可以通过设置 TaskRun 中的参数值来覆盖 Task 中定义的默认值。确保在 TaskRun 中正确配置参数,以满足具体的执行需求。如果参数没有隐式默认值,则必须显式设置其值
  • 参数的类型:参数有三种类型:string, array(beta 功能) 或object(beta 功能),其中string类型最为常用
  • 参数的默认值:参数可以在定义的时候设置默认值
  • 参数的使用:若定义参数url,可在task中使用$(params.url)来获取参数值

那么如何将之前的Git的拉取改造成可复用的呢?

  1. 将Task的的url、branch抽出,由Task的params进行传递,需要定义两个参数urlbranch的名称和类型。

    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
    
  2. 在TaskRun中spec.params定义参数urlbranch将参数值传入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"
    

最终执行效果:

image-20230812000401799

了解空间Workspace

Workspace 允许在 Tekton 的 Pipeline 中的不同任务之间共享文件和数据,以便进行构建、测试、部署等操作。每个任务都可以定义一个或多个 Workspace,以指定其输入和输出的文件路径。这样,不同任务可以将文件从一个 Workspace 传递到另一个 Workspace,以便在任务之间共享数据。

Workspace 的用途:

  1. 存储输入和输出: 每个任务可以定义一个或多个 Workspace,用于存储输入和输出数据。例如,在构建任务中,输入 Workspace 可以包含源代码,输出 Workspace 可以包含构建生成的二进制文件。
  2. 任务间数据共享: 任务可以通过 Workspace 将数据从一个任务传递到另一个任务。这对于在流水线中不同的阶段之间共享数据非常有用,例如在构建后将构建好的应用程序传递给部署任务。
  3. 挂载凭证和配置: Workspace 可以作为挂载点,用于将凭证(如用户名和密码)或配置(如 API 密钥)从 Kubernetes 的 Secret 或 ConfigMap 中传递给任务。
  4. 共享工具: Workspace 可以作为任务所需的常用工具的挂载点。这样,可以确保所有任务都可以访问一组共享的工具,而不需要每个任务都重新安装。
  5. 构建缓存: 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: {}

最终运行结果:

image-20230822103933578

上方例子使用了emptyDir类型的worksapceworksapce的类型包括:

  • 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: {}

最后运行结果:

image-20230822110001879

实现镜像构建kaniko

在编译完成之后,就需要将编译完成的产物打成镜像,那么就需要新增一个step,镜像构建。

Kaniko可用于构建镜像,详情可访问:Kaniko:容器构建的灵活解决方案

这个示例中的 Tekton Task 定义的作用是构建一个 Docker 镜像。具体来说,它的功能和步骤如下:

  1. 克隆代码:clone-repo 步骤中,使用 alpine/git 镜像执行 Git 命令,从指定的仓库 URL 克隆代码到 Workspace 中,并列出文件。这将获取代码以供后续步骤使用。
  2. 安装依赖:npm-install 步骤中,使用 node:14.19 镜像执行 npm install 命令,安装项目所需的依赖。这是构建过程中的一项常见操作。
  3. 构建项目:npm-build 步骤中,继续使用 node:14.19 镜像执行 npm run build 命令,完成项目的构建。这可能包括编译、打包等操作。
  4. 使用 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最后运行结果:

image-20230822120416212

更多示例请查看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构建镜像
lomtom

标题:Tekton(三)逐步深入:掌握Tekton中Task和TaskRun的用法和原理

作者:lomtom

链接:https://lomtom.cn/c48hvhq96isqg