暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes - CICD 工具之tektoncd介绍

Share and Fun喜来分 2020-03-13
508

击上方蓝字关注我们











Background

尽管我们现在没有把 Tekton 应用到项目中,但是我希望通过这篇文章,让大家有一个对 Tekton 这个工具的使用有个基本概念,希望我下一篇文章是写 Flux 的 CD 让大家对比下这两个工具。

Overview

Tekton 提供很强大而且灵活的开源组件,可以帮助我们去标准化 CI/CD (持续集成和持续发布)工具和流程。并且,它允许我们跨多个云提供商例如亚马逊云/微软云/谷歌云或者本地系统构建,测试和部署。 Tekton 提供的 Pipelines、 Release、Workflows 跟其他现有的工具例如 Jenkins 都可以集成。利用 Tekton ,我们可以实现类似 Rolling、Blue/green、Canary deployment 或者 GitOps 工作流。

Tekton特点

持续交付是现代软件开发的一个关键部分,但是现在这个领域非常分散。 Tekton 项目通过与开源社区跟其他几个主要供应商合作来解决这个问题,建立一个充分利用容器和更广法的云原生生态系统以及跟供应商无关的基础来创建规范和变化的 CI/CD。Tekton 是包含了 Tekton pipeline, Tekton dashboard, Tekton triggers 的一个开源框架,Tekton 的特点如下:

  1. 自动化部署

    Tekton Trigger 是 Tekton 其中一个开源框架之一,允许我们从 Event 中提取信息来自动化创建 Kubernetes 资源,可以做到类似 GitOps 一样,提交代码到 Git Repo,然后触发部署资源。

  2. 在 Kubernetes 内置的最佳实践

    Tekton 内置最佳实践是允许快速创建基于云的 CI/CD pipeline。可以快速让我们创建镜像和部署容器,管理 infrastructure 的版本控制或者执行简单的回滚,还可以实现 Rolling,、Blue/green、Canary 的部署。

  3. 灵活

    Tekton 相比 Flux 来说,更加灵活,他同时兼容在本地环境或者云环境的CI/CD。他可以支持单独一个 Task,也可以支持 Pipeline (管道)的多个 Task 部署,可以让我们选择需要的输入或者输出。

  4. 使用容器作为构建块

    在 Jenkins 里面,我们如果要构建基于 nodejs 或者 JAVA 的应用的时候,我们需要在基于 VM 的或者基于容器 Jenkins Slave 里面安装对应的应用程序去支持构建,而在 Tekton 里面,是基于 Container 来作为构建块,我们可以打一个 common 或者基于某个语言或者应用的 Container,来传递给 Tekton 去构建或者部署我们的应用。

  5. 支持跨平台

    Tekton 支持让我们跨平台去部署我们的应用,包括 VM, Kubernetes 去执行构建、测试和部署。并且我们可以使用 Tekton 管道跨多个云提供商或者混合环境进行部署。

Concept

Task

Task 其实简单来说呢是一个构建任务,包含了一系列的 steps,就 GoCD 里面的一个 Job 一样。Tekton Pipeline 的主要是运行单独一个Task任务,或者作为Pipeline 的一部分去运行。每个 step 在 Kubernetes 集群中是由一个 Pod 运行。

TaskRun

TaskRun 是运行我们定义的 Task,我们可以手动创建一个 taskRun,当 taskRun被创建之后,就会触发 Task 中的构建任务。下面是一个简单例子

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: TaskRun

  3. metadata:

  4. name: run-our-ut-task

  5. spec:

  6. taskRef:

  7. name: ci-ut

我们可以使用 Tekton 的 CLI 去查看我们 TaskRun
执行输出

  1. tkn taskrun describe run-our-ut-task

查看实际结果,可以使用以下命令

  1. tkn taskrun logs run-our-ut-task

Pipeline Resource

在很多场景下,我们都需要更多的输入跟输出的流程,例如我们的 Task 需要从我们的 Git 里面拉去代码并且构建 Image。PipelineResource 就是用来定义 Artifacts 去传递给 Task 输入或者输出。

Pipeline Resource 支持的类型有 Git、Image。通常情况下我们会使用 Git Repo 的代码作为 Input,然后构建生成的 tar或者 image 来作为 output 

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: PipelineResource

  3. metadata:

  4. name: fetch-code

  5. spec:

  6. type: git

  7. params:

  8. - name: revision

  9. value: master

  10. - name: url

  11. value: https://xx.gerrit.xx/project-name/component-name

Pipeline

Pipeline 类似 GoCD 里面的 Template, 在 GoCD 里面一个 Template 会有多个 Job,在 Tekton 里面一个 Pipeline 会有一个或者多个 Task。

Pipeline 通过 runAfter 参数来定义了一系列的 Task 的执行顺序,也有 condition 的参数让 Task 在满足条件后运行。

PipelineRun

同理,PipelineRun 就是去运行我们的 Pipeline 的。这里不细说。

实践

Tekton 允许你跨多个环境例如 VM,Kubernetes 构建、测试和部署,还可以跨多个云提供商或者混合环境进行部署。

安装

安装比较简单,使用 kubectl apply
命令即可把 Tekton pipelines 跟对应的依赖包安装好即可。

  1. kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

部署 Tekton 之后,我们可以看见  Tekton Pipeline 是由一个 controller 控制器来监听 CRD 并且执行逻辑,webhook 是用来检验创建的 CRD 资源。

CI

Jenkins 的确很强,但是 Jenkins 并不是设计为了给容器环境去构建的,并且开销很大,不适合微服务团队结构等。这里我想使用 Tekton 来给大家看看怎么使用它来做 CI。

先定义一个 ServiceAccount 去解决代码仓库以及镜像仓库的权限问题。

  1. ---

  2. apiVersion: v1

  3. kind: ServiceAccount

  4. metadata:

  5. name: tekton-account

  6. namespace: ci-test

  7. secrets:

  8. - name: fetch-git

  9. - name: docker-registry

  10. ---

  11. apiVersion: v1

  12. kind: Secret

  13. metadata:

  14. name: fetch-git

  15. namespace: ci-test

  16. annotations:

  17. xx: xx

  18. type: kubernetes.io/ssh-auth

  19. data:

  20. ssh-privatekey: xx...

  21. known_hosts: xx...

  22. ---

  23. apiVersion: v1

  24. kind: Secret

  25. metadata:

  26. name: docker-registry

  27. namespace: ci-test

  28. annotations:

  29. tekton.dev/docker-0: https://xx.artifactory.com

  30. type: kubernetes.io/basic-auth

  31. stringData:

  32. username: <non-encoded>

  33. password: <non-encoded>

从 Git 里面拉取代码,下例是使用了 revision 获取了 master 的代码,同样可以指定 tag 或者 commit

  1. ---

  2. apiVersion: Tekton.dev/v1alpha1

  3. kind: PipelineResource

  4. metadata:

  5. name: git-source

  6. spec:

  7. type: git

  8. params:

  9. - name: url

  10. value: https://xx.gerrit.com/project/test.git

  11. - name: revision

  12. value: master

拉取代码后,我们需要执行 maven 编译打包以及构建镜像,我们通过 input 来把刚刚定义的拉取代码资源作为输入传递给 Task,这里有三个步骤( steps ),第一个步骤是执行 maven 编译,第二个步骤是打成镜像,第三个步骤则是推送至镜像仓库

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: Task

  3. metadata:

  4. name: build-image

  5. spec:

  6. inputs:

  7. resources:

  8. - name: git-source

  9. type: git

  10. params:

  11. - name: component-imagenametag

  12. description: The component image name to build

  13. default: application-mgmt:1.0.0

  14. serviceAccount: tekton-account

  15. outputs:

  16. resources:

  17. - name: output-buildimage

  18. type: image

  19. steps:

  20. - name: maven-install

  21. image: maven:3.5.0-jdk-8-alpine

  22. workingDir: "${inputs.params.directory}"

  23. args:

  24. [

  25. "mvn",

  26. "clean",

  27. "install",

  28. "-D maven.test.skip=true",

  29. ]


  30. volumeMounts:

  31. - name: m2

  32. mountPath: /root/.m2

  33. - name: build-component-image

  34. image: xx-artifactory.xx/build-image:1.0.0

  35. command:

  36. - docker

  37. args:

  38. - build . -t

  39. - $(inputs.params.component-imagenametag)

  40. - $(outputs.resources.output-buildimage.url)

  41. - name: promote-component-image

  42. image: xx-artifactory.xx/build-image:1.0.0

  43. command:

  44. - docker

  45. args:

  46. - push $(outputs.resources.output-buildimage.url)/$(inputs.params.component-imagenametag)

如果要做到我们现在的 image name tag 的话,首先要在容器里面运行 sed ,然后用镜像更新部署 YAML 文件,YAML 文件必须在更新的时候有一个 __IMAGE__
字符串。然后需要借助 lAchlan Evenson 的流行的 k8s-kubectl 容器来运行 kubectl, 去实现更新集群中提取 commit id 来作为 image name tag,如下代码所示

  1. set-e


  2. if[ $# -lt 4 ]; then

  3. echo "Usage: <resources> <container> <docker_url> <source_code_path>"

  4. exit 1

  5. fi

  6. resource=$1

  7. container=$2

  8. docker_url=$3

  9. source_code_path=$4


  10. commitid=$(cd $source_code_path && git rev-parse HEAD)


  11. kubectl set image deployment $resource $container=$docker_url:$commitid

然后我们开始定义一个 TaskRun 去执行我们的构建

  1. apiVersion: Tekton.dev/v1alpha1

  2. kind: TaskRun

  3. metadata:

  4. generateName: whatever-name

  5. spec:

  6. inputs:

  7. resources:

  8. - name: gitssh

  9. resourceRef:

  10. name: git-source

  11. taskRef:

  12. name: build-image

至此为止,构建镜像以及推镜到仓库的流程已经完成。

CD

在 Kubernetes 中,我们都知道如果要发布应用到编排器中,我们可以使用 Helm 也可以直接使用 manifest 的方法将应用部署。现在我们把我们的 manifest 文件放入到 Git Repo,假设这个 Git Repo 是叫 project-manifest/deploy-app,然后 example 的 manifest 如下:

  1. apiVersion: v1

  2. kind: Service

  3. metadata:

  4. name: app

  5. labels:

  6. app: app

  7. spec:

  8. type: NodePort

  9. ports:

  10. - port: 3300

  11. name: app

  12. nodePort: 32426

  13. selector:

  14. app: app

  15. ---

  16. apiVersion: apps/v1

  17. kind: Deployment

  18. metadata:

  19. name: app

  20. labels:

  21. app: app

  22. spec:

  23. replicas: 1

  24. selector:

  25. matchLabels:

  26. app: app

  27. template:

  28. metadata:

  29. labels:

  30. app: app

  31. spec:

  32. containers:

  33. - name: app

  34. image: IMAGE

  35. ports:

  36. - containerPort: 3300

然后我们定义PipelineResource是指定到我们存储manifest的Git Reo中

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: PipelineResource

  3. metadata:

  4. name: git-source

  5. spec:

  6. type: git

  7. params:

  8. - name: revision

  9. value: master

  10. - name: url

  11. value: https://xx.gerrit.com/project-manifest/deploy-app

task 如下

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: Task

  3. metadata:

  4. name: deploy-application

  5. spec:

  6. inputs:

  7. resources:

  8. - name: git-source

  9. type: git

  10. params:

  11. - name: app-deploy-file-name

  12. default: app-deploy.yaml

  13. steps:

  14. - name: deploy-app

  15. image: kabanero/kabanero-utils

  16. command: ['/bin/sh']

  17. args: ['-c', 'cd /workspace/$gitsource && kubectl apply -f $(inputs.params.app-deploy-file-name)']

  18. env:

  19. - name: gitsource

  20. value: git-source

在把上面的 deploy-application
的 Task 部署之前,我们需要配置 tekton-account 获取 tekton-ns
的管理权限,用来部署应用

  1. apiVersion: rbac.authorization.k8s.io/v1

  2. kind: ClusterRoleBinding

  3. metadata:

  4. name: tekton-cluster-admin

  5. subjects:

  6. - kind: ServiceAccount

  7. name: tekton-account

  8. namespace: tekton-ns

  9. roleRef:

  10. kind: ClusterRole

  11. name: cluster-admin

  12. apiGroup: rbac.authorization.k8s.io

接下来我们创建一个部署应用的 Pipeline:

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: Pipeline

  3. metadata:

  4. name: application-pipeline

  5. spec:

  6. resources:

  7. - name: git-source

  8. type: git

  9. params:

  10. - name: pathToContext

  11. description: The path to the build context, used byKaniko- within the workspace

  12. default: .

  13. - name: pathToYamlFile

  14. description: The path to the yaml file to deploy within the git source

  15. default: config.yaml

  16. - name: imageUrl

  17. description: Url of image repository

  18. default: deploy_target

  19. - name: imageTag

  20. description: Tag to apply to the built image

  21. default: latest

  22. tasks:

  23. # 这里build-image就是我们CI上定义的task

  24. - name: build-image

  25. params:

  26. - name: pathToContext

  27. value: "$(params.pathToContext)"

  28. - name: imageUrl

  29. value: "$(params.imageUrl)"

  30. - name: imageTag

  31. value: "$(params.imageTag)"

  32. resources:

  33. inputs:

  34. - name: git-source

  35. resource: git-source

  36. - name: deploy-application

  37. taskRef:

  38. name: deploy-application

  39. runAfter:

  40. - build-image

  41. params:

  42. - name: pathToContext

  43. value: "$(params.pathToContext)"

  44. - name: pathToYamlFile

  45. value: "$(params.pathToYamlFile)"

  46. - name: imageUrl

  47. value: "$(params.imageUrl)"

  48. - name: imageTag

  49. value: "$(params.imageTag)"

  50. resources:

  51. inputs:

  52. - name: git-source

  53. resource: git-source

最后我们定义一个 PipelineRun 去运行上面定义的 Pipeline:

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: PipelineRun

  3. metadata:

  4. name: application-pipeline-run

  5. spec:

  6. pipelineRef:

  7. name: application-pipeline

  8. resources:

  9. - name: git-source

  10. resourceRef:

  11. name: git

  12. params:

  13. - name: pathToContext

  14. value: "src"

  15. - name: pathToYamlFile

  16. value: "deploy.yaml"

  17. - name: "imageUrl"

  18. value: "IMAGE_URL"

  19. - name: "imageTag"

  20. value: "IMAGE_TAG"

  21. serviceAccount: tekton-account

现在我们使用 kubectl apply-f
把我们定义的 Pipeline 以及 Pipelinerun 部署至 Kubernetes 上。

触发

上面我们说了这么多,都是要手工的使用 kubectl apply-f
然后把我们定义的 PipelineRun/TaskRun 部署到 Kubernetes 上,这样明显是不可以满足我们自动化CI/CD的。而 Tekton 提供了一个叫 Triggers 的框架可以让我们做到从触发事件中提取信息去创建 Kubernetes 资源。

Tekton API 允许我们将功能从配置中分离除了包括 Pipeline、PipelineRuns,这些步骤可以重用,Tekton Trigger 提供了一种生成动态封装这些配置。基本的 Tekton Trigger 组件这里简单说一下:

TriggerTemplate: 定义了要创建的模板资源,例如创建要使用他们的PipelineRun。

TriggerBinding: 验证事件并且提取有效字段。

EventListener: 将 TriggerBindings 连接到 TriggerTemplates 并提供可寻址端点,这个是 webhook /事件定向的地方。

Tekton Trigger 可以让我们做到类似 GitOps 的工作流,以下代码是来自 Tekton Trigger 的官网,当我们提交代码到我们的 Git Repo 里面就可以看到我们定义的 Pipeline/Task 自动部署到 Kubernetes 里面。(除了支持 Github 同样也支持 GitLab 去做类似的事情)

安装配置略,此处我只想重点说一下如何配置 Event 实现提交代码到 Git repo 就可以触发 PipelineRun,需要替换变量才能使用。

首先会使用一个 EventListener
去接收 Push 事件

然后定义 TriggerTemplate
会为 template 的 PipelineRun 来接收事件

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: TriggerTemplate

  3. metadata:

  4. name: tekton-terigger-triggertemplate

  5. namespace: tekton-terigger

  6. spec:

  7. params:

  8. - name: gitrevision

  9. description: The git revision

  10. default: master

  11. - name: gitrepositoryurl

  12. description: The git repository url

  13. - name: namespace

  14. description: Thenamespace to create the resources

  15. resourcetemplates:

  16. - apiVersion: tekton.dev/v1alpha1

  17. kind: PipelineRun

  18. metadata:

  19. name: tekton-terigger-pipeline-run-$(uid)

  20. namespace: $(params.namespace)

  21. spec:

  22. serviceAccountName: tekton-triggers-admin

  23. pipelineRef:

  24. name: tekton-terigger-pipeline

  25. resources:

  26. - name: source-repo

  27. resourceSpec:

  28. type: git

  29. params:

  30. - name: revision

  31. value: $(params.gitrevision)

  32. - name: url

  33. value: $(params.gitrepositoryurl)

  34. - name: image-source

  35. resourceSpec:

  36. type: image

  37. params:

  38. - name: url

  39. value: DOCKERREPO-REPLACEME # docker-repo-location.com/repo:tekton-terigger

  40. - name: event-to-sink

  41. resourceSpec:

  42. type: cloudEvent

  43. params:

  44. - name: targetURI

  45. value: http://event-display.tekton-terigger.svc.cluster.local

  46. ---

  47. apiVersion: tekton.dev/v1alpha1

  48. kind: TriggerBinding

  49. metadata:

  50. name: tekton-terigger-pipelinebinding

  51. namespace: tekton-terigger

  52. spec:

  53. params:

  54. - name: gitrevision

  55. value: $(body.head_commit.id)

  56. - name: namespace

  57. value: tekton-terigger

  58. - name: gitrepositoryurl

  59. value: "https://github.com/$(body.repository.full_name)"

  60. ---

  61. apiVersion: tekton.dev/v1alpha1

  62. kind: EventListener

  63. metadata:

  64. name: tekton-terigger-listener

  65. namespace: tekton-terigger

  66. spec:

  67. serviceAccountName: tekton-triggers-admin

  68. triggers:

  69. - bindings:

  70. - name: tekton-terigger-pipelinebinding

  71. template:

  72. name: tekton-terigger-triggertemplate

Tekton Dashboard

这里快速说一下 Tekton dashboard,这个是 Tekton 提供的可视化 dashboard,可以查看 PipelineRun 的日志或者执行结果。

第一步,安装

  1. kubectl apply --filename https://github.com/tektoncd/dashboard/releases/download/v0.4.1/dashboard_latest_release.yaml

第二步,创建用于 Demo 的 task

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: Task

  3. metadata:

  4. name: echo-hello-world

  5. spec:

  6. steps:

  7. - name: echo

  8. image: ubuntu

  9. command:

  10. - echo

  11. args:

  12. - "hello world"

创建用于 Demo 的 pipeline

  1. apiVersion: tekton.dev/v1alpha1

  2. kind: Pipeline

  3. metadata:

  4. name: tutorial-pipeline

  5. spec:

  6. tasks:

  7. - name: echo-hello-world-n

  8. taskRef:

  9. name: echo-hello-world

浏览器访问 Tekton dashboard,创建 PipelineRun 以及查看这次 PipelineRun 的执行结果

查看 TaskRun 的执行结果

后话

(我本来想说,Tekton 已经得到了 Google, IBM 跟 RedHat 的支持。)

好像不止一个人跟我讲想用 GitLab 代替 Jenkins 成为我们的 CI 呢,不管是 GitLab 还是 Jenkins,其实我觉得都不适合,因为他们都不是以 K8S 为依托的, Kubernetes 已经是必然,而选择 CRD+operator 的 tekton 必然成为新一代 CICD 的标准,尽管现在还不算很成熟,但是我很看好 tekton.

Tekton & Flux

我放了一个链接在这里,就是 Tekton 跟 Flux 集成的消息,有兴趣的同学可以订阅下这个消息。

https://github.com/tektoncd/pipeline/issues/1259

Reference

https://cd.foundation/

https://tekton.dev/

https://github.com/tektoncd/pipeline

https://github.com/tektoncd/triggers

https://github.com/tektoncd/dashboard


文章转载自Share and Fun喜来分,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论