流水线是把一个重复的过程分解为若干个子过程,使每个子过程与其他子过程并行进行的技术,也叫 Pipeline。以“构建镜像更新应用”为例:
当一次代码变更之后,jenkins都需要拉取最新的代码,进行代码编译,构建镜像,推送镜像到镜像仓库,最后更新k8s资源对象。而且每次代码变更,此过程都是不变的。所以使用流水线工具可以极大的提升这一过程的效率,只需要进行简单的配置便可以轻松的完成重复性的工作,这样的过程也被称之为 CI。
Tekton 是一个基于 Kubernetes 的云原生 CI/CD 开源框架,属于 CD 基金会的项目之一。Tekton 通过定义 CRD 的方式,让用户以灵活的自定义流水线以满足自身 CI/CD 需求。
Tekton 由以下组件组成:
tkn
,它构建在 Kubernetes CLI 之上,允许您与 Tekton 进行交互。Tasks
、Pipelines
,等等 - 可以在您自己的管道中使用。Tekton Pipelines最基本的四个概念:Task、TaskRun、Pipeline、PipelineRun。
PipelineResource概念
PipelineResource 代表着一系列的资源,主要承担作为 Task 的输入或者输出的作用。它有以下几种类型:
Tekton Triggers是一个基于事件的触发器,它可以检测到事件的发生,并能提取事件中的信息,TaskRuns
和PipelineRuns
可以根据该信息进行实例化和执行。
Tekton Triggers最基本的四个概念:TriggerTemplate、TriggerBinding、EventListener、Interceptor。
TriggerTemplate:指定要在检测到事件时实例化和执行的资源,如TaskRuns
和PipelineRuns
。
TriggerBinding:指定要从事件信息中提取的字段,并将字段信息传递给TriggerTemplate
,这样字段就可以在TaskRuns
和PipelineRuns
中使用。
EventListener:在Kubernetes集群启动一个事件监听服务、并暴露服务,将TriggerTemplate
和TriggerBinding
绑定。
Interceptor:事件拦截器,用于过滤事件,运行在TriggerBinding
之前。
下边以接收gitlab pr merged事件自动从gitlab拉取代码、构建镜像、推送镜像到harbor仓库、更新k8s集群资源为例,演示tekton构建流水线。
git-input表示Task的输入,type=git表示使用git仓库类型,url表示gitlab的地址,revision表示分支。
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: git-input
namespace: test-tekton
spec:
type: git
params:
- name: url
value: https://xxxx.git
- name: revision
value: dev
image-output表示Task的输出,type=image表示使用镜像仓库类型,url表示仓库地址。
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: image-output
namespace: test-tekton
spec:
type: image
params:
- name: url
value: xxxx/xxxx
由于使用了私有gitlab和镜像仓库,所以需要配置仓库的认证信息。
git-basic-user-pass表示gitlab的认证信息,annotations
中tekton.dev/git-tekton.dev/git-
开头的key表示git类型的secret,value则是gitlab的地址,type
表示认证类型,支持kubernetes.io/basic-auth
、kubernetes.io/ssh-auth
。
apiVersion: v1
kind: Secret
metadata:
name: git-basic-user-pass
namespace: test-tekton
annotations:
tekton.dev/git-0: https://xxxx.git
type: kubernetes.io/basic-auth
stringData:
username: xxxx
password: xxxx
repo-basic-user-pass表示harbor的认证信息,annotations
中tekton.dev/docker-
开头的key表示docker仓库类型的secret,value则是harbor的地址,type
表示认证类型,支持kubernetes.io/basic-auth
、kubernetes.io/dockercfg
、kubernetes.io/dockerconfigjson
。
apiVersion: v1
kind: Secret
metadata:
name: repo-basic-user-pass
namespace: test-tekton
annotations:
tekton.dev/docker-0: xxxx
type: kubernetes.io/basic-auth
stringData:
username: xxxx
password: xxxx
build-bot表示PipelineRun、TaskRun使用的ServiceAccount,build-bot绑定git-basic-user-pass、repo-basic-user-pass,这样PipelineRun、TaskRun就能使用相应认证信息。
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-bot
namespace: test-tekton
secrets:
- name: git-basic-user-pass
- name: repo-basic-user-pass
由于部署应用时使用kubectl、triggers,所以build-bot需要集群权限,这里给了一个cluster-admin的权限。
kubectl create clusterrolebinding build-bot-cluster-admin --clusterrole=cluster-admin --serviceaccount=test-tekton:build-bot
build-push表示构建、推送镜像任务,params
下表示表示定义变量并设置了默认值,$()
表示引用某个变量,workspaces
类似于k8s中volume,用于存储、共享数据,支持pvc、configmap、secret,本例由于需要在task之间共享部署的yaml,所以在pipelineRun中指定使用pvc作为存储实现。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-push
namespace: test-tekton
spec:
workspaces:
- name: ws
resources:
inputs:
- name: docker-source
type: git
outputs:
- name: build-image
type: image
params:
- name: pathToDockerfile
type: string
default: $(resources.inputs.docker-source.path)/Dockerfile
- name: pathToContext
type: string
default: $(resources.inputs.docker-source.path)
- name: commitID
type: string
default: latest
steps:
- name: build-push
image: registry.cn-hangzhou.aliyuncs.com/tanber_rp/gcr.io.kaniko-project.executor:v0.16.0
env:
- name: "DOCKER_CONFIG"
value: "tekton/home/.docker/"
command:
- /kaniko/executor
args:
- --dockerfile=$(params.pathToDockerfile)
- --destination=$(resources.outputs.build-image.url):$(params.commitID)
- --context=$(params.pathToContext)
- name: store-image-url
image: busybox
script: | #这里代码目录下deploy为部署文件,可根据实际情况修改
cp -r $(resources.inputs.docker-source.path)/deploy/ $(workspaces.ws.path)/
url='$(resources.outputs.build-image.url):$(params.commitID)'
url=${url//\//\\/}
sed -i "s/image: tanber\/saml_idp:v1/image: ${url}/" $(workspaces.ws.path)/deploy/deploy.yaml
deploy表示部署应用。
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: deploy
namespace: test-tekton
spec:
workspaces:
- name: ws
params:
- name: pathToDeploy
type: string
default: $(workspaces.ws.path)/deploy/
steps:
- name: deploy
image: docker.io/bitnami/kubectl:1.22.1
securityContext:
runAsUser: 0
securityContext:
runAsUser: 0
command:
- kubectl
args:
- apply
- -f
- $(params.pathToDeploy)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: pipeline
namespace: test-tekton
spec:
workspaces:
- name: ws
resources:
- name: docker-source
type: git
- name: build-image
type: image
params:
- name: mrState
type: string
- name: targetBranch
type: string
- name: commitID
type: string
- name: pathToDockerfile
type: string
default: $(resources.inputs.docker-source.path)/Dockerfile
- name: pathToContext
type: string
default: $(resources.inputs.docker-source.path)
- name: pathToDeploy
type: string
default: $(workspaces.ws.path)/deploy
tasks:
- name: build-push
when:
- input: "$(params.mrState)"
operator: in
values: ["merged"]
- input: "$(params.targetBranch)"
operator: in
values: ["dev"]
taskRef:
name: build-push
workspaces:
- name: ws
workspace: ws
params:
- name: commitID
value: $(params.commitID)
- name: pathToDockerfile
value: $(params.pathToDockerfile)
- name: pathToContext
value: $(params.pathToContext)
resources:
inputs:
- name: docker-source
resource: docker-source
outputs:
- name: build-image
resource: build-image
- name: deploy
when:
- input: "$(params.mrState)"
operator: in
values: ["merged"]
- input: "$(params.targetBranch)"
operator: in
values: ["dev"]
runAfter:
- build-push
taskRef:
name: deploy
workspaces:
- name: ws
workspace: ws
params:
- name: pathToDeploy
value: $(params.pathToDeploy)
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: triggertemplate
namespace: test-tekton
spec:
params:
- name: mrState
- name: targetBranch
- name: commitID
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: pipelinerun-
namespace: test-tekton
spec:
serviceAccountName: build-bot
pipelineRef:
name: pipeline
workspaces:
- name: ws
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
params:
- name: pathToDockerfile
value: $(resources.inputs.docker-source.path)/Dockerfile
- name: pathToContext
value: $(resources.inputs.docker-source.path)
- name: pathToDeploy
value: $(workspaces.ws.path)/deploy
- name: mrState
value: $(tt.params.mrState)
- name: targetBranch
value: $(tt.params.targetBranch)
- name: commitID
value: $(tt.params.commitID)
resources:
- name: docker-source
resourceRef:
name: git-input
- name: build-image
resourceRef:
name: image-output
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
name: triggerbinding
namespace: test-tekton
spec:
params:
- name: mrState
value: $(body.object_attributes.state)
- name: targetBranch
value: $(body.object_attributes.target_branch)
- name: commitID
value: $(body.object_attributes.merge_commit_sha)
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: eventlistener
namespace: test-tekton
spec:
serviceAccountName: build-bot
triggers:
- bindings:
- ref: triggerbinding
template:
ref: triggertemplate
在Settings–>Webhooks下添加一个webhook,其中URL为创建Eventlistener时自动为你创建的svc,此svc默认是clusterIP,可自行创建一个NodePort类型svc。
在gitlab上提一个pr到dev分支,并合并就会触发流水线,查看生成的流水线记录。
$ kubectl -n test-tekton get pipelineruns.tekton.dev
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
pipelinerun-mxlbw True Completed 8d 8d
pipelinerun-ngj6h True Succeeded 8d 7d23h
$ kubectl -n test-tekton get pod
NAME READY STATUS RESTARTS AGE
el-eventlistener-67464796fd-5k62t 1/1 Running 0 8d
pipelinerun-ngj6h-build-push-qjbcz-pod-vltrq 0/5 Completed 0 7d23h
pipelinerun-ngj6h-deploy-rxmd9-pod-hnzps 0/1 Completed 0 7d23h