一、什么是 TektonTekton 是一个功能强大且灵活的 Kubernetes 原生开源框架是谷歌开源的功能强大且灵活 开源社区也正在快速的迭代和发展壮大主要用于创建持续集成和交付CI/CD系统。通过抽象底层实现细节用户可以跨多云平台和本地系统进行构建、测试和部署。另外基于 kubernetes CRD 定义的pipeline 流水线也是 Tekton 最重要的特征。扩展CRD 是什么CRD 全称是 CustomResourceDefinition在 Kubernetes 中一切都可视为资源Kubernetes 1.7 之后增加了对 CRD 自定义资源二次开发能力来扩展 Kubernetes API通过 CRD 我们可以向 Kubernetes API 中增加新资源类型而不需要修改 Kubernetes 源码来创建自定义的 API server该功能大大提高了 Kubernetes 的扩展能力。 当你创建一个新的 CustomResourceDefinition (CRD)时Kubernetes API 服务器将为你指定的每个 版本创建一个新的 RESTful 资源路径我们可以根据该 api 路径来创建一些我们自己定义的类型资源。 CRD 可以是命名空间的也可以是集群范围的由 CRD 的作用域(scpoe)字段中所指定的与现有的内置对象一样删除名称空间将删除该名称空间中的所有自定义对象。customresourcedefinition 本身没有名称空间所有名称空间都可以使用。二、为什么要用 k8s 原生的 CI-CD 工具 Tekton持续集成是云原生应用的支柱技术之一因此在交付基于云原生的一些支撑产品的时候CICD 是非常好的方案。为了满足这种需要自然而然会想到对 Jenkins(X)或者 Gitlab 进行集成也有创业公司出来的一些小工具比如 Argo Rollout。Tekton 是一款 k8s 原生的应用发布框架主要用来构建CI/CD 系统。它原本是 knative 项目里面一个叫做 build-pipeline 的子项目用来作为 knative-build 的下一代引擎。然而随着 k8s 社区里各种各样的需求涌入这个子项目慢慢成长为一个通用的框架能够提供灵活强大的能力去做基于 k8s 的构建发布。Tekton 其实只提供Pipeline 这个一个功能Pipeline 会被直接映射成 K8s Pod 等 API 资源。而比如应用发布过程的控制灰度和上线策略都是我们自己编写 K8s Controller 来实现的也就意味着 Tekton 不会在 K8s 上盖一个”大帽子 “比如我们想看发布状态、日志等是直接通过 K8s 查看这个 Pipeline 对应的 Pod 的状态和日志不需要再面对另外一个 API。Tekton 功能1.Kubernetes 原生的 Tekton 的所有配置都是使用 CRD 方式进行编写存储的非常易于检索和使用2.配置和流程分离 Tekton 的 Pipeline 和配置可以分开编写使用名称进行引用。3.轻量级核心的 Pipeline 非常轻便适合作为组件进行集成另外也有周边的 Dashboard、Trigger、CLI 等工具能够进一步挖掘其潜力。4.可复用、组合的 Pipeline 构建方式非常适合在集成过程中对 Pipeline 进行定制三、使用 Tekton 自动化发布应用流程这里的流程大致是1、用户把需要部署的应用先按照一套标准的应用定义写成 YAML 文件类似 Helm Chart2、用户把应用定义 YAML 推送到 Git 仓库里3、Tekton CD (一个 K8s Operator) 会监听到相应的改动根据不同条件生成不同的 TektonPipelinesTekton CD 的操作具体分为以下几种情况1、如果 Git 改动里有一个应用 YAML 且该应用不存在那么将渲染和生成 Tekton Pipelines用来创建应用。2、如果 Git 改动里有一个应用 YAML 且该应用存在那么将渲染和生成 Tekton Pipelines 用来升级应用。这里我们会根据应用定义 YAML 里的策略来做升级比如做金丝雀发布、灰度升级。3、如果 Git 改动里有一个应用 YAML 且该应用存在且标记了“被删除”那么将渲染和生成Tekton Pipelines 用来删除应用。确认应用被删除后我们才从 Git 里删除这个应用的 YAML。四、安装 Tekton#把 tekton-0-12-0.tar.gz 和 busybox-v-1-0.tar.gz 上传到 xianchaonode1 机器上手动解压[rootnode1]# docker load -i tekton-0-12-0.tar.gz [rootnode1]# docker load -i busybox-v-1-0.tar.gz #编写安装 tekton 资源清单文件 [rootmaster1 ~]# kubectl apply -f release.yaml #验证 pod 是否创建成功 [rootmaster1 ~]# kubectl get pods -n tekton-pipelines NAME READY STATUS RESTARTS AGE tekton-pipelines-controller-d64889fb9-9b68f 1/1 Running 0 52s tekton-pipelines-webhook-7c8664944c-ctsgf 1/1 Running 0 52s [rootmaster1 ~]# kubectl get crd 找到下面这些东西说明创建 crd 成功了 pipelineresources.tekton.dev 2021-08-21T13:52:16Z pipelineruns.tekton.dev 2021-08-21T13:52:16Z pipelines.tekton.dev 2021-08-21T13:52:16Z taskruns.tekton.dev 2021-08-21T13:52:16Z tasks.tekton.dev 2021-08-21T13:52:16Z [rootmaster1 ~]# kubectl api-versions 看到下面说明 apiversion 创建成功了 tekton.dev/v1alpha1 tekton.dev/v1beta1五、Tekton 概念Tekton 为 Kubernetes 提供了多种 CRD 资源对象可用于定义我们的流水线主要有以下几个 CRD 资源对象1Task表示执行命令的一系列步骤task 里可以定义一系列的 steps例如编译代码、构建镜像、推送镜像等每个 step 实际由一个 Pod 里的容器执行。2TaskRuntask 只是定义了一个模版taskRun 才真正代表了一次实际的运行当然你也可以自己手动创建一个 taskRuntaskRun 创建出来之后就会自动触发 task 描述的构建任务。3Pipeline一组任务表示一个或多个 task、PipelineResource 以及各种定义参数的集合。4PipelineRun类似 task 和 taskRun 的关系pipelineRun 也表示某一次实际运行的pipeline下发一个 pipelineRun CRD 实例到 Kubernetes 后同样也会触发一次 pipeline 的构建。5PipelineResource表示 pipeline 输入资源比如 github 上的源码或者 pipeline 输出资源例如一个容器镜像或者构建生成的 jar 包等。六、测试 Tekton 构建 CI/CD 流水线我们测试一个简单的 golang 程序。应用程序代码测试及 dockerfile 文件可在如下地址获取Verify two-factor authenticationclone 应用程序代码进行测试创建一个 task 任务 [rootmaster1 ~]# cat task-test.yaml apiVersion: tekton.dev/v1beta1 kind: Task metadata: name: test spec: resources: inputs: - name: repo type: git steps: - name: run-test image: golang:1.14-alpine imagePullPolicy: IfNotPresent workingDir: /workspace/repo command: [go] args: [test] #更新资源清单文件 [rootmaster1 ~]# kubectl apply -f task-test.yaml task.tekton.dev/test created #查看 Task 资源 [rootmaster1 ~]# kubectl get Task NAME AGE test 23s #上面内容解释说明 resources 定义了我们的任务中定义的步骤中需要输入的内容这里我们的步骤需要 Clone 一个 Git 仓库作为 go test 命令的输入。Tekton 内置了一种 git 资源类型它会自动将代码仓库 Clone 到 /workspace/$input_name 目录中由于我们这里输入被命名成 repo所以代码会被 Clone 到 /workspace/repo 目录下面。然后下面的 steps 就是来定义执行运行测试命令的步骤这里我们直 接在代码的根目录中运行 go test 命令即可需要注意的是命令和参数需要分别定义。创建 pipelineresource 资源对象通过上面步骤我们定义了一个 Task 任务但是该任务并不会立即执行我们必须创建一个 TaskRun 引用它并提供所有必需输入的数据才行。这里我们就需要将 git 代码库作为输入我们必须先创建一个 PipelineResource 对象来定义输入信息创建一个名为 pipelineresource.yaml 的资源清 单文件内容如下所示 [rootmaster1 ~]# cat pipelineresource.yaml apiVersion: tekton.dev/v1alpha1 kind: PipelineResource metadata: name: xuegod-tekton-example spec: type: git params: - name: url value: https://github.com/luckylucky421/tekton-demo - name: revision value: master #更新资源清单文件 [rootmaster1 ~]# kubectl apply -f pipelineresource.yaml创建 taskrun 任务[rootmaster1 ~]# cat taskrun.yaml apiVersion: tekton.dev/v1beta1 kind: TaskRun metadata: name: testrun spec: taskRef: name: test resources: inputs: - name: repo resourceRef: name: xuegod-tekton-example #更新资源清单文件 [rootmaster1 ~]# kubectl apply -f taskrun.yaml #上面资源清单文件解释说明 这里通过 taskRef 引用上面定义的 Task 和 git 仓库作为输入resourceRef 也是引用上面定义的PipelineResource 资源对象。 #创建后我们可以通过查看 TaskRun 资源对象的状态来查看构建状态 [rootmaster1 ~]# kubectl get taskrun NAME SUCCEEDED REASON STARTTIME testrun Unknown Running 6s [rootmaster1 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE testrun-pod-x9rkn 2/2 Running 0 9s 当任务执行完成后 Pod 就会变成 Completed 状态了 [rootmaster1 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE testrun-pod-x9rkn 0/2 Completed 0 72s 我们可以通过 kubectl describe 命令来查看任务运行的过程首先就是通过 initContainer 中的 一个 busybox 镜像将代码 Clone 下来然后使用任务中定义的镜像来执行命令。当任务执行完成后 Pod 就会变成 Completed 状态了我们可以查看容器的日志信息来了解任务的执行结果信息 [rootmaster1 ~]# kubectl logs testrun-pod-x9rkn --all-containers {level:info,ts:1617616592.58145,caller:git/git.go:136,msg:Successfully cloned https://github.com/luckylucky421/tekton-demo c6c2a85091d538a13c44f85bcee9e861c362b0d3 (grafted, HEAD, origin/master) in path /workspace/repo} {level:info,ts:1617616592.6319332,caller:git/git.go:177,msg:Successfully initialized and updated submodules in path /workspace/repo} PASS ok _/workspace/repo 0.003s#通过上面可以看到我们的测试已经通过了。总结我们已经在 Kubernetes 集群上成功安装了 Tekton定义了一个 Task并通过 YAML 清 单和创建 TaskRun 对其进行了测试。自定义 CRD 资源通过 crd 资源创建自定义资源即自定义一个 Restful APIcat crontab-crd.yaml apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: crontabs.stable.example.com spec: group: stable.example.com versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: cronSpec: type: string image: type: string replicas: type: integer scope: Namespaced names: plural: crontabs singular: crontab kind: CronTab shortNames: - ct Yaml 文件注解 metadata.name 是用户自定义资源中自己自定义的一个名字。一般我们建议使用“顶级域 名.xxx.APIGroup”这样的格式名称必须与下面的 spec.Group 字段匹配格式为: plural.group spec 用于指定该 CRD 的 group、version。比如在创建 Pod 或者 Deployment 时它的 group 可能为 apps/v1 或者 apps/v1beta1 之类这里我们也同样需要去定义 CRD 的 group。 group: stable.example.com #组名称 versions: - name: v1 #指定组下的版本 served: true #每个版本都可以通过服务标志启用/禁用 storage: true #必须将一个且只有一个版本标记为存储版本。 scope: Namespaced #指定 crd 资源作用范围在命名空间或集群 names 指的是它的 kind 是什么比如 Deployment 的 kind 就是 DeploymentPod 的 kind 就是 Pod这里的 kind 被定义为了 CronTab plural 字段就是一个昵称比如当一些字段或者一些资源的名字比较长时可以用该字段自定义一些昵称来简化它的长度 singular: crontab # 在 CLI(shell 界面输入的参数)上用作别名并用于显示的单数名称 shortNames: - ct # 短名称允许短字符串匹配 CLI 上的资源就是能通过 kubectl 在查看资源的时候使用该资源的简 名称来获取。 创建自定义 contab 资源 $ kubectl apply -f crontab-crd.yaml 查看 crd kubectl get crd 查看自定义 crontab 资源的信息 $ kubectl get crontab创建自定义资源的对象根据 crd 对象资源创建出来的 RESTful API来创建 crontab 类型资源对象cat my-crontab.yaml apiVersion: stable.example.com/v1 kind: CronTab metadata: name: my-new-cron-object spec: cronSpec: * * * * * * image: busybox kubectl apply -f my-crontab.yaml #查看资源 kubectl get CronTab 显示如下 NAME AGE my-new-cron-object 9s 提示可以看到对应类型资源已经创建成功以上示例只是单纯的 crd 的使用示例没有任何实质的作用。示例部署 mongodb-aperator1、项目地址 https://github.com/mongodb/mongodb-kubernetes-operator.git 把课件里的压缩包传上来手动解压 unzip mongodb-kubernetes-operator-0.5.0.zip 2、创建名称空间 mongodb并进入到 mongodb-kubernetes-operator 目录应用 crd 资源 创建自定义资源类型 [rootmaster1 ~] kubectl create ns mongodb [rootmaster1 ~]# cd mongodb-kubernetes-operator-0.5.0 [rootmaster1 mongodb-kubernetes-operator-0.5.0]# kubectl apply -f deploy/crds/mongodb.com_mongodbcommunity_crd.yaml #查看 mongodb 是否创建成功 kubectl get crd/mongodbcommunity.mongodb.com 3、安装 operator [rootmaster1 mongodb-kubernetes-operator-0.5.0]# kubectl apply -f deploy/operator/ -n mongodb 提示mongodb-kubernetes-operator 这个项目是将自定义控制器和自定义资源类型分开实现 的其 operator 只负责创建和监听对应资源类型的变化在资源有变化时实例化为对应资源对 象并保持对应资源对象状态吻合用户期望状态上述四个清单中主要是创建了一个 sa 账户并对 对应的 sa 用户授权 验证查看 operator 是否正常运行 [rootmaster1 mongodb-kubernetes-operator-0.5.0]# kubectl get pods -n mongodb NAME READY STATUS RESTARTS AGE mongodb-kubernetes-operator-7f8c55db45-tmpk5 1/1 Running 0 44s 验证使用自定义资源类型创建一个 mongodb 副本集集群 [rootmaster1 mongodb-kubernetes-operator-0.5.0]# cat deploy/crds/mongodb.com_v1_mongodbcommunity_cr.yaml [rootmaster1 mongodb-kubernetes-operator-0.5.0]# kubectl apply -f deploy/crds/mongodb.com_v1_mongodbcommunity_cr.yaml -n mongodb [rootmaster1 mongodb-kubernetes-operator-0.5.0]# kubectl get pods -n mongodb NAME READY STATUS RESTARTS AGE example-mongodb-0 0/2 Pending 0 66s 提示这里可以看到对应 pod 处于 pending 状态 查看 pod 详细信息 [rootmaster1 mongodb-kubernetes-operator-0.5.0]# kubectl describe pod/example-mongodb-0 -n mongodb|grep -A 10 Events Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 116s default-scheduler 0/2 nodes are available: 2 pod has unbound immediate PersistentVolumeClaims. Warning FailedScheduling 116s default-scheduler 0/2 nodes are available: 2 pod has unbound immediate PersistentVolumeClaims. 提示这里提示没有可以用的 pvc 删除 mongodb 名称空间下 pvc kubectl get pvc -n mongodb kubectl delete pvc --all -n mongodb 创建 pv 和 pvc [rootmaster1 ~]# cat pv-demo.yaml apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv-v1 labels: app: example-mongodb-svc spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: [ReadWriteOnce,ReadWriteMany,ReadOnlyMany] persistentVolumeReclaimPolicy: Retain mountOptions: - hard - nfsvers4.1 nfs: path: /data/p1 server: 192.168.40.180 --- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv-v2 labels: app: example-mongodb-svc spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: [ReadWriteOnce,ReadWriteMany,ReadOnlyMany] persistentVolumeReclaimPolicy: Retain mountOptions: - hard - nfsvers4.1 nfs: path: /data/p2 server: 192.168.40.180 --- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv-v3 labels: app: example-mongodb-svc spec: capacity: storage: 1Gi volumeMode: Filesystem accessModes: [ReadWriteOnce,ReadWriteMany,ReadOnlyMany] persistentVolumeReclaimPolicy: Retain mountOptions: - hard - nfsvers4.1 nfs: path: /data/p3 server: 192.168.40.180 [rootmaster1 ~]# mkdir /data/p1 [rootmaster1 ~]# mkdir /data/p2 [rootmaster1 ~]# mkdir /data/p3 [rootmaster1 ~]# cat /etc/exports /data/v1 *(rw,no_root_squash) /data/p1 *(rw,no_root_squash) /data/p2 *(rw,no_root_squash) /data/p3 *(rw,no_root_squash) [rootmaster1 ~]# exportfs -arv [rootmaster1 ~]# kubectl apply -f pv-demo.yaml 创建 pvc 资源 [rootxianchaomaster1 ~]# cat pvc-demo.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: style="margin-top:12px">