前面介绍了如何通过jenkins完成构建,在使用jenkins过程中,也有一些不足,例如基于脚本的job配置复用率不足,另外代码调试困难。所以如何提高job的配置脚本的复用和让流水线作业的配置更好的适应云原生场景的需求变得越来越迫切。而基于声明式API的流水线-Tekton能有效解决上面的两个问题。
自定义:Tekton对象高度自定义,可扩展性极强,平台工程师可预定义可重用模块,开发人员可在其他项目中直接引用。Tekton的对象可充用性强,组件只需定义一次,组织内任何人就可以进行复用。
可扩展:Tekton组件目录(Tekton Catalog)是一个社区驱动的Tekton组件的存储仓库,任何用户可从社区获取成熟的组件,并在此基础上构建复杂的流水线。
标准化:Tekton作为Kubernetes集群的扩展安装和运行,是公认的Kubernetes资源模型,Tekton作业以Kubernetes容器形态执行。
规模化支持:只需增加Kubernetes节点,即可增加作业处理能力。
为了理解和使用Tekton,先来看看Tekton涉及的组件以及组件的作用。
Step:step是CI/CD工作流中的一种操作,比如为Python web应用程序运行一些单元测试,或者编译Java程序。Tekton使用您提供的容器镜像执行每个步骤。例如,你可以使用官方的Go Image来编译一个Go程序,就像你在本地工作站上编译一样(Go build)。
Task:Task是按顺序排列的步骤的集合。Tekton以Kubernetes pod的形式运行一个任务,每一步都成为pod中的一个运行容器。这种设计允许您为一系列相关step设置共享环境;例如,您可以在Task中挂载Kubernetes volume,该volume在Task的每个Step中都可以访问。
Pipeline: Pipeline是按顺序的Task集合。Tekton收集所有任务,将它们连接到一个有acyclic graph(DAG)中,并按顺序执行。换句话说,它创建了许多Kubernetes pod,并确保每个pod按预期成功运行。Tekton授予开发人员对过程的完全控制:可以设置任务完成的扇入/扇出场景,要求Tekton在存在不可靠的测试时自动重试,或者指定任务在继续之前必须满足的条件。
PipelineRun: PipelineRun是Pipeline的特定执行。例如,您可以要求Tekton每天运行两次CI/CD工作流,每次执行将成为Kubernetes集群中可跟踪的pipelineRun资源。您可以使用pipelineRuns查看CI/CD工作流的状态,包括每个任务执行的细节。
TaskRun: taskRun是任务的特定执行。当你选择在Pipeline外运行任务时,TaskRuns也是可用的,通过它你可以查看任务中每个步骤执行的细节。
Tekton Trigger: Tekton Triggers是一个Tekton组件,它允许你从各种来源的事件中检测和提取信息,并基于这些信息确定和执行TaskRuns和PipelineRuns。Tekton触发器还可以将从事件中提取的信息直接传递给TaskRuns和PipelineRuns。安装Tekton触发器在Kubernetes集群作为Tekton Pipeline的扩展。要理解Trigger如何工作,又需要理解下面的术语概念。
EventListener - 监听Kubernetes集群上指定端口的事件。指定一个或多个触发器。
Trigger - 指定当EventListener检测到事件时会发生什么。一个触发器指定一个TriggerTemplate、一个TriggerBinding和一个Interceptor(可选)。
TriggerTemplate - 指定资源的蓝图,例如TaskRun或PipelineRun,当你的EventListener检测到一个事件时,你想实例化和/或执行它。它公开了可以在资源模板中的任何位置使用的参数。
TriggerBinding - 指定希望提取的数据的字段,以及用提取的值填充相应TriggerTemplate中的字段。然后可以使用TriggerTemplate中填充的字段来填充相关的TaskRun或PipelineRun中的字段。
ClusterTriggerBinding - 一个适用于集群的TriggerBinding版本,特别适合在集群中重用。
Interceptor - 在TriggerBinding之前运行的特定平台的“万能”事件处理器,使您能够执行有效负载过滤、验证、转换、定义和测试触发条件,以及其他有用的处理。event data通过Inerceptor之后,将有效data传递给TriggerBinding之前,它将转到Trigger。
前面通过文字介绍了Tekton的主要组件,接下来通过实际实验来理解和使用Tekton。
首先是安装Tekton,通过如下名了可以安装Tekton的组件和TektonCLI,CLI是可选的。
### Setup tekton
```sh
kubectl create --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
kubectl create --filename https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
kubectl create --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
kubectl create --filename https://github.com/tektoncd/dashboard/releases/latest/download/tekton-dashboard-release.yaml
```
### Setup tekton cli tkn
```sh
curl -LO https://github.com/tektoncd/cli/releases/download/v0.20.0/tektoncd-cli-0.20.0_Linux-64bit.deb
sudo dpkg -i ./tektoncd-cli-0.20.0_Linux-64bit.deb
which tkn
```
下面定义了一个简单的Tekton task和taskrun,执行kubectl create -f xx.yaml命令,可以看到启动了task和taskrun,task中定义了step,step就是启动一个ubuntu的pod,然后显示 hello username
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: hello
spec:
steps:
- name: hello
image: ubuntu
command:
- echo
args:
- "Hello $(params.username)!"
params:
- name: username
type: string
TaskRun中引用了Task,并给Task传递了所需的参数。
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
generateName: hello-run-
spec:
taskRef:
name: hello
params:
- name: "username"
value: "jesse"
可以看到创建TaskRun的同时,会创建相应的pod。
查看pod的logs,可看到确实打印了hello username信息。
上面演示了一个简单的task和taskrun,接下来再看看如果想和github集成。
下面yaml文件中定义了一个Task和TaskRun,该Task的的build步骤引入了Kaniko实现docker in docker,即拉取源代码,通过源代码下面的Dockerfile,构建出镜像,并把镜像推送到tlqiao/httpserver:v1.0.镜像的目标地址定义在--destination上。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: github-build
spec:
params:
- name: IMAGE
description: Name (reference) of the image to build.
default: tlqiao/httpserver:v1.0
- name: DOCKERFILE
description: Path to the Dockerfile to build.
default: ./Dockerfile
resources:
inputs:
- name: repo
type: git
steps:
- name: github-build
image: cncamp/executor
workingDir: /workspace/repo
args:
- "--dockerfile=./Dockerfile"
- "--context=./"
- "--destination=tlqiao/httpserver:v1.0"
workspaces:
- name: dockerconfig
description: Includes a docker `config.json`
optional: true
mountPath: /kaniko/.docker
---
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: github-build
spec:
serviceAccountName: cncamp-sa
taskRef:
name: github-build
resources:
inputs:
- name: repo
resourceRef:
name: cncamp-golang
workspaces:
- name: dockerconfig
secret:
secretName: docker-auth
为了让上面的对象正常工作,需要创建SA和Secret以及PipelineResource。以下是PipelineResouce的定义,PipelineResource中需要引用github-secrets,另外里面定义了拉取代码的仓库地址url(这里需要替换成自己的代码仓库地址)和revision.
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: cncamp-golang
spec:
type: git
params:
- name: url
value: https://github.com/tlqiao/go-learning.git
- name: revision
value: main
secrets:
- fieldName: authToken
secretName: github-secrets
secretKey: token
以下是github secret的定义文件,里面是配置在github上的token信息,可以在自己的github仓库上生成token信息。
下面是登录dockerhub的credentials配置信息,因为生成的镜像是推送到dockerhub上。可以在k8s集群上执行docker login命令,输入dockerhub的用户和密码,然后在cat ~/.docker/config.json可以查找到配置信息。
最后还创建了SA,供上面的PipelineResource使用
apiVersion: v1
kind: ServiceAccount
metadata:
name: cncamp-sa
secrets:
- name: docker-auth
通过kubectl create -f xx.yaml文件创建上面的对象,task和taskrun创建完成后,查看pod信息
可以看到step-git-source-repo步骤成功从gihub上拉取到了代码信息。
查看ste-github-build步骤,可以看到生成的image被成功推送的dockerhub上。
上面演示了如何和github集成完成build,接下来看看如何通过gitlab的webhook完成任务触发。为了使用gitlab首先在集群上安装gitlab,安装gitlab的yaml文件如下所示,这里的service是NodePort类型,这样就可以通过Node节点IP+Port在外网访问启动的gitlab服务了。
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitlab
spec:
replicas: 1
selector:
matchLabels:
run: gitlab
template:
metadata:
labels:
run: gitlab
spec:
containers:
- image: gitlab/gitlab-ee
imagePullPolicy: IfNotPresent
name: gitlab
---
apiVersion: v1
kind: Service
metadata:
name: gitlab
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
run: gitlab
type: NodePort
登陆gitlab服务,需要输入密码,可以通过进入gitlab pod查看密码,即可登录gitlab服务,用户名是root。
kubectl get po -l run=gitlab
kubectl exec -it grep 'Password:' /etc/gitlab/initial_root_password
登录后,在admin-setting-network模块下,勾选如下选项。
创建一个名叫test的空白的project,然后在project下创建webhook,webhook的URL是http://el-gitlab-listener:8080,secret token=1234567,这个token会在yaml中定义。
webhook创建后,在Test之前,需要定义下面的yaml文件,并创建yaml文件中定义的对象。
下面的yaml文件定义了一个SA,SA的secretToken=1234567
定义了Secret存放登录gitlab的用户名和密码,这个密码需要替换成安装gitlab后最新的秘密
定义了EventListener,EventListener里面定义了Trigger,trigger里面包含interceptor和binding和template。按照前面的组件定义,triggerbinding负责提取字段信息,如下所示triggerbinding中获取了拉取的代码仓库地址和gitreversion,提取的字段信息在triggerTemplate中使用。
TriggerTemplate中定义了PipelineRun,PipelineRun里面是具体的Task。
apiVersion: v1
kind: ServiceAccount
metadata:
name: cncamp-gitlab-sa
---
apiVersion: v1
kind: Secret
metadata:
name: cncamp-gitlab-secret
type: Opaque
stringData:
### this secret token is to protect the webhook service
### when creating git lab webhook, this token need to be specified
secretToken: '1234567'
---
apiVersion: v1
kind: Secret
metadata:
name: cncamp-gitlab-auth
annotations:
tekton.dev/git-1: http://gitlab.default.svc.cluster.local
type: kubernetes.io/basic-auth
### this is the user/password for gitlab when checkout code
stringData:
username: root
password: 0PDUva92Ks8mTFJw/e46ruoN89UH8BGizH20pTh3Vy8=
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: gitlab-listener
spec:
serviceAccountName: cncamp-gitlab-sa
triggers:
- name: gitlab-push-events-trigger
interceptors:
- ref:
name: gitlab
params:
- name: secretRef
value:
secretName: cncamp-gitlab-secret
secretKey: secretToken
- name: eventTypes
value:
- Push Hook
bindings:
- ref: gitlab-binding
template:
ref: gitlab-triggertemplate
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: gitlab-binding
spec:
params:
- name: gitrevision
value: $(body.checkout_sha)
- name: gitrepositoryurl
value: http://gitlab/root/test.git
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: gitlab-triggertemplate
spec:
params:
- name: gitrevision
- name: gitrepositoryurl
resourcetemplates:
- kind: PipelineRun
apiVersion: tekton.dev/v1beta1
metadata:
generateName: gitlab-pipeline-run-
spec:
serviceAccountName: cncamp-gitlab-sa
pipelineSpec:
tasks:
- name: checkout
taskRef:
name: gitlab-checkout
resources:
inputs:
- name: source
resource: source
resources:
- name: source
type: git
resources:
- name: source
resourceSpec:
type: git
params:
- name: revision
value: $(tt.params.gitrevision)
- name: url
value: $(tt.params.gitrepositoryurl)
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: gitlab-checkout
spec:
resources:
inputs:
- name: source
type: git
steps:
- name: show-path
image: ubuntu
script: |
#! /bin/bash
cat /etc/resolv.conf
ls -la $(resources.inputs.source.path)
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cncamp-gitlab-sa
secrets:
- name: cncamp-gitlab-secret
- name: cncamp-gitlab-auth
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tekton-triggers-gitlab-minimal
rules:
- apiGroups: ['triggers.tekton.dev']
resources:
['eventlisteners', 'triggerbindings', 'triggertemplates', 'triggers']
verbs: ['get', 'list', 'watch']
- apiGroups: ['']
resources: ['configmaps']
verbs: ['get', 'list', 'watch']
- apiGroups: ['tekton.dev']
resources: ['pipelineruns', 'pipelineresources', 'taskruns']
verbs: ['create']
- apiGroups: ['']
resources: ['serviceaccounts']
verbs: ['impersonate']
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
resourceNames: ['tekton-triggers']
verbs: ['use']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tekton-triggers-gitlab-binding
subjects:
- kind: ServiceAccount
name: cncamp-gitlab-sa
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: tekton-triggers-gitlab-minimal
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: tekton-triggers-gitlab-clusterrole
rules:
- apiGroups: ['triggers.tekton.dev']
resources: ['clustertriggerbindings', 'clusterinterceptors']
verbs: ['get', 'list', 'watch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-triggers-gitlab-clusterbinding
subjects:
- kind: ServiceAccount
name: cncamp-gitlab-sa
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: tekton-triggers-gitlab-clusterrole
创建上面的对象后,选择push event进行Test,可以看到webhook触发成功。
查看集群上的pod日志,可以看到具体的task执行日志信息。
可以看到通过Tekton完成流水线的配置很灵活,且定义好yaml文件后,可以在团队共享。复用度高。但是同时Tekton的配置有一定的门槛,更多Tekton的使用可以查看官网信息。