作者:FogDong(Tekton 社区)
编辑:Bach(才云)
什么是流水线?
在计算机中, 流水线是把一个反复的过程合成为若干个子过程,使每个子过程与其余子过程并行进行的技术,也叫 Pipeline。因为这种 s 工作形式与工厂中的生产流水线十分相似,因而也被称为流水线技术。从实质上讲,流水线技术是一种工夫并行技术。以“构建镜像”过程为例:
在每一次构建镜像中,咱们都须要拉下代码仓库中的代码,进行代码编译,构建镜像,最初推往镜像仓库。在每一次代码更改过后,这一过程都是不变的。应用流水线工具能够极大的晋升这一过程的效率,只须要进行简略的配置便能够轻松的实现重复性的工作。这样的过程也被称之为 CI。
上图流程中应用的是 Jenkins。Jenkins 作为老牌流水线框架被大家所熟知。在云原生时代,Jenkins 也推出了 Jenkins X 作为基于 Kubernetes 的新一代流水线,但明天本文次要介绍诞生于云原生时代的流水线框架——Tekton。
Tekton
Tekton 是一个基于 Kubernetes 的云原生 CI/CD 开源框架,属于 CD 基金会的我的项目之一。Tekton 通过定义 CRD 的形式,让用户以灵便的自定义流水线以满足本身 CI/CD 需要。
基本概念
四个基本概念
Tekton 最次要的四个概念为:Task、TaskRun、Pipeline 以及 PipelineRun。
- Task: Task 为构建工作,是 Tekton 中不可分割的最小单位,正如同 Pod 在 Kubernetes 中的概念一样。在 Task 中,能够有多个 Step,每个 Step 由一个 Container 来执行。
- Pipeline: Pipeline 由一个或多个 Task 组成。在 Pipeline 中,用户能够定义这些 Task 的执行程序以及依赖关系来组成 DAG(有向无环图)。
- PipelineRun: PipelineRun 是 Pipeline 的理论执行产物,当用户定义好 Pipeline 后,能够通过创立 PipelineRun 的形式来执行流水线,并生成一条流水线记录。
- TaskRun: PipelineRun 被创立进去后,会对应 Pipeline 外面的 Task 创立各自的 TaskRun。一个 TaskRun 管制一个 Pod,Task 中的 Step 对应 Pod 中的 Container。当然,TaskRun 也能够独自被创立。
综上可知:Pipeline 由多个 Task 组成,每次执行对应生成一条 PipelineRun,其管制的 TaskRun 将创立理论运行的 Pod。上面以一个简略例子来展现这些概念。
首先,创立一个最简略的 Task,外面仅有一个 Step。在一个 ubuntu 镜像中执行 ls 命令。
接着创立一个 Pipeline,外面援用第一步中创立的 Task。
在 Pipeline 存在的前提下,就能够通过创立 PipelineRun 来运行 Pipeline。
这样就实现了一个最简略的 Tekton 流水线案例。每一个 PipelineRun 的创立,都会遵循 Pipeline 中的程序规定去启动 Task 的 Pod。上面引入另外一个概念 PipelineResource 来实现一个略微简单的例子,也是 DevOps 中最常见的场景:从代码仓库拉取镜像、进行代码构建、并最终将构建好的镜像推往镜像仓库。
PipelineResource
PipelineResource 代表着一系列的资源,次要承当作为 Task 的输出或者输入的作用。它有以下几种类型:
- git:代表一个 git 仓库,蕴含了须要被构建的源代码。将 git 资源作为 Task 的 Input,会主动 clone 此 git 仓库。
- pullRequest:示意来自配置的 url(通常是一个 git 仓库)的 pull request 事件。将 pull request 资源作为 Task 的 Input,将主动下载 pull request 相干元数据的文件,如 base/head commit、comments 以及 labels。
- image:代表镜像仓库中的镜像,通常作为 Task 的 Output,用于生成镜像。
- cluster:示意一个除了以后集群外的 Kubernetes 集群。能够应用 Cluster 资源在不同的集群上部署利用。
- storage:示意 blob 存储,它蕴含一个对象或目录。将 Storage 资源作为 Task 的 Input 将主动下载存储内容,并容许 Task 执行操作。目前仅反对 GCS。
- cloud event:会在 TaskRun z 执行实现后发送事件信息(蕴含整个 TaskRun)到指定的 URI 地址,在与第三方通信的时候非常有用。
以上为 Tekton 目前反对的六大 PipelineResource 类型,具体的配置及应用办法详见 PipelineResource 文档。
文档地址:https://github.com/tektoncd/p…
持续剖析较简单的流水线案例: 从代码仓库拉取镜像、进行代码构建、并将构建好的镜像推往镜像仓库 。从已有的 PipelineResource 类型可判断,能够应用 git 类型作为代码资源作为输出,再用 image 类型作为镜像资源作为输入。有了输入输出后,咱们能够间接应用 Kaniko 来构建镜像。
Kaniko 是 Google 开源的我的项目之一,可在 Kubernetes 上无需特权模式地构建 docker 镜像。
首先创立这两个 PipelineResource。在这个例子中,git-input 对应输出,image-output 对应输入。params 中的参数均为该资源类型的固定参数:如 git 中能够通过 revision 指定版本号,image 中能够通过 url 指定镜像仓库地址。
Git-input:
Image-output:
在配置 PipelineResource 时,如果应用了公有仓库,还须要配置 Service Account,详见 configuring-authentication-for-docker。
configuring-authentication-for-docker 地址:https://github.com/tektoncd/p…
产物传递
创立完 PipelineResource 后,须要在 Task 中引入它们作为输入输出。那么,这些资源是如何在 Task 间传递的呢?
在 Tekton 的分区下,咱们能够看到一个叫做 config-artifact-pvc
和一个叫做 config-artifact-bucket
的 Config Map。从命名就能够看出, 这二者别离代表了产物存储的两种配置形式—— PVC 和存储桶(目前反对 GCS 和 S3)。
以 PVC 为例,批改 config-artifact-pvc
须要填写两个值:size 以及 storageClassName。size 默认为 5GiB,storage class name 默认为 default。这也意味着当咱们应用 PipelineResource 进行资源传递时,会主动创立一个 5GiB 的存储卷挂载在 Task 上,供 PipelineResource 应用。
在须要进行 Task 间的资源传递时,这个存储卷会被挂载在 Task 的 /pvc 目录下。当 Task 执行实现并且须要进行资源传递(通过 inputs/outputs 指定)后,TaskRun controller 会主动增加一个拷贝文件的步骤容器,并将输入产物对立放到 /pvc/task_name/resource_name 命名标准的目录下。
下面是针对产物须要进行传递的状况下,对于目前例子而言,因为只须要一个 Task,尽管指定了 Inputs 和 Outputs,但并没有另一个 Task 来援用这些后果。因而,在这个例子中并不会去挂载 PVC。
对于 git 以及 storage 类型的 input,资源下载后会被 放在 /workspace/task_resource_name 下;对于 output 则会放在 /workspace/output/resource_name 下。image 类型的资源则会间接上传到镜像仓库。
理解了这些前置常识后,咱们能够来创立 Task 了。Kaniko 须要三个参数来实现镜像构建:Dockerfile 的地址,context 的地址以及镜像仓库的地址。 在上面这个例子中,咱们大量应用了 params 以及 Tekton 中的变量替换。Params 用于在 TaskRun 和 Task 中传递参数,而变量替换的格局为 $(xxx)。应用这些变量能够让 Tekton 在运行过程中依据规定进行赋值。值得注意的是,Tekton 并不会提前去查看这些变量的内容,这就要求着咱们在写的时候须要多加留神。具体的变量编写规定详见:Tekton variables。
Tekton variables 地址:https://github.com/tektoncd/p…
有了 Task 后,就能创立 TaskRun 来执行 Task。留神,在 spec 中申明了 serviceAccountName 用于指定公有仓库的权限。
至此,一个更为简单的流水线也构建实现了。
DAG
在 Tekton 中,DAG(有向无环图)的性能是原生反对的。只须要通过申明 runAfter 及 from 便能够便当的使 Pipeline 以 DAG 形式运行。
- from:当 Task 的 Inputs 依赖于上一个 Task 的 Outputs 时,能够通过 from 参数来指定
- runAfter:当 Task 间没有资源依赖,但须要使一个 Task 在另外一个 Task 之后运行的话,能够应用 runAfter 来指定。
例如在下面的例子中,工作会以下程序运行:
lint-repo
和test-app
中的 Task 没有from
或runAfter
关键字,会同时开始执行。- 一旦
test-app
实现,build-app
和build-frontend
都会开始同时执行,因为它们runAfter
于test-app
。 deploy-all
会在build-app
和build-frontend
都实现后才执行,因为它须要的资源from
于这二者。
再来看看 Tekton 是怎么样来实现这段逻辑的:
在 Pipeline 的 Controller 中,一旦监听到 Pipeline 的创立,在创立对应的 TaskRun 之前,会先检测 Pipeline 中的依赖程序并构建 DAG 图:
Step 执行程序
Pipeline 中能够进行对 Task 的顺序控制,那么 Task 中呢?
在 Kubernetes 中,Pod 里的 Container 是并行启动的。 而在 Tekton 中,尽管 Task 对应 Pod,Task 中的 Step 对应 Container,但 Task 中的 Step 却是程序执行的 。要理解 Tekton 是怎么实现这样的顺序控制,首先咱们来看一下一个 Tekton 的 Pod。
在这个 Pod 中,除了用户须要运行的 Container,还被注入了一个 InitContainer:
这个 InitContainer copy 了一个 entrypoint 的二进制到 Pod 中。再看下用户的 container,咱们能够看到 Pod 的执行命令被 Tekton 改写了一下:
能够看到 command 被改写为了 entrypoint 命令,这个二进制包在 initContainer 中被导入,另外还有一些启动参数:
- -post_file:指定了 Step 实现后的文件写入门路。如果 Step 失败,则写入到
{{post_file}}.err
。能够看到下面的写入门路为 /tekton/tools/0,最初的这个数字即为 Step 的编号。 - -wait_file:指定了在启动下一个 Step 之前要查看的文件门路。它将监听
{{wait_file}}
和{{wait_file}}.err
。若有谬误则跳过执行写入{{post_file}}.err
并返回谬误(exitCode >= 0);若无谬误则执行下一个 Step。如上例子为第一个 step,若为第二个 step,wait_ file 的地址会是/tekton/tools/0
,也就是上一个 step 的 post_file 地址。
资源管制
在 Kubernetes 中, 一个 Pod 被调度须要节点满足 Pod 中的所有 Container 的资源 。如下图:
这个 Pod 有 4 个容器,总共须要 9 个 CPU。Kubernetes 将把这个 Pod 调度到一个领有 9 个可用 CPU 的节点上。如果没有节点有 9 个可用 CPU,Pod 将被调度失败并无奈启动。
而对于 Tekton 而言,因为 Pod 中的 Container 会程序执行,所以只须要满足这个 Pod 中资源最大的 Container 即可。对于同一个 TaskRun,Tekton 会获取最大申请,并让一个 Container 去申请这些资源,其余都设为 0。
如下,该 Pod 申请 4 个 CPU,而不是 9 个。这样的资源管制形式更为正当且所有的 Step 容器仍保留所须要的资源。
在有 LimitRange 限度 Container 必须有资源的的状况下,每个 Container 最小会设置为 LimitRange 的设置。
源码局部逻辑如下:
数据传递
除了 PipelineResource 以外,Tekton 还提供了其余数据传递的形式。
PipelineResource 仍处于 Alpha 版本,它有可能会被从新设计、替换、弃用或者齐全删除。Tekton 社区激励用户用 Task 代替 PipelineResources。
Workspace
Workspace 与 Kubernetes 中 Volume 概念简直保持一致,只不过并不是 Pod 层级的而是作用于 Tekton 资源层级的。Workspace 在 Pipeline 中应用时是一个形象的概念,理论的存储类型须要在 PipelineRun 中指定。详见:Workspaces。
Workspaces 地址:https://github.com/tektoncd/p…
Results
Tekton 提供了一个固定目录用于寄存 Task 的输入:/tekton/results
如上,该 task 将日期输入到了 /tekton/results/current-date 中。同时,也会被作为 Results 字段加到 TaskRun 的 Status 中。这样,其余的 Task 便能够通过 $(tasks..results.) 来获取到该 Task 的 results。(变量替换将会理论从 TaskRun 中获取到 Results 的值)
其余流程管制性能
条件判断
低版本能够应用 Conditions
,高版本举荐应用 WhenExpressions
(Conditions 将在不久后废除,齐全替换为 WhenExpressions)。WhenExpressions 由 Input、Operator、Values 三局部组成,其中 Input 能够应用 Tekton 的 Parameter 或者 Results,Operator 目前仅反对 in 和 notin:
谬误重尝
通过 retries 来指定工作失败后从新尝试的次数:
退出解决
通过 finally 指定在 pipeline 完结时执行的 task,无论 pipeline 的后果是胜利或失败。
勾销执行
要勾销以后正在执行的 PipelineRun,能够在其 Spec 中更新 Status 为勾销。当 PipelineRun 被勾销时,所有相干的 Pods 都被删除。例如:
Pipeline 暂停的逻辑与之相似,但暂停 PR 尚未合入,暂停性能也在 Tekton 往年的 Roadmap 中。
Runs
Runs 是一个进行中的 feature,Run 容许实例化和执行一个 Custom Task,这个 Custom Task 能够通过用户自定义的 controller 来执行。这对于用户来说是一个十分理论的性能,能够通过本人写的 Controller 来定义 Task 的逻辑,而不再拘泥于 Tekton 定义的 Task。