tekton

从knative的build中演进而来,属于k8s的扩展

组件

  • pipeline:最核心组件,由一组CRD和相关operator、webhook组成。需要部署运行在k8s集群上,作为k8s扩展
  • trigger:触发器,可触发pipeline的实例化,可选组件。可直接从gitlab接收事件
  • cli:命令行客户端,与tekton交互
  • dashboard:tekton管道的基于web的图形化界面,可选组件
  • catalog:社区贡献的tekton构建块(building blocks),有现成的清单文件可以拿来用:https://github.com/tektoncd/catalog
  • hub:访问catalog的web图形,类似hub仓库:https://hub.tekton.dev/
  • tokton operator

核心概念

CRD资源

pipeline

  • 由1组task组成,可串行、并行、DAG(任意)
  • 由1个task的输出,再给其他task引用

image-20240103145201805

image-20240103145502942

task

  • 对应Jenkins的stage
  • 对应1个pod,由1组step组成的序列,安装定义的顺序依次允许在同一个pod不同容器中(每个step都是1个容器,1个step容器结束运行下1个step容器)
  • 可共享1组环境变量、存储卷
steps

属于task,一个task中定义多个steps,这些steps组合成task
cicd工作流的1个具体操作,如py web app的单元测试,或javaj程序编译操作
每个step都在pod的1个容器中运行

pipelineRun

运行pipeline模板,一个pipielineRun中由多个pipeline、TaskRun组成
pipeline使用k8s注解跟踪pipeline的状态,给每个step相关的容器注入entrypoint程序,此程序执行step定义的内容

运行流程

  • 定义pipelinerun,传参、调用的pipeline
  • 定义pipeline,声明参数、调用task、传参task
  • 定义task,声明参数,定义step

taskRun

运行task模板,一个taskRun中,由多个tasks组成。taskrun代表task的1次执行过程,pipelinerun也是类似
每个taskrun运行在1个独立的pod中,内部每个step分别运行在不同容器中

输入和输出资源

每个task或pipeline都有input和output,都可称为input resources和output resources

如:某task以git仓库为input,output为容器镜像。该task会从git仓库中克隆代码、运行、测试、构建打包为镜像容器

注:input和output现由Parameters替代,参考后面的parameters

支持的资源:

  • git仓库
  • pull请求:git仓库上的pr请求
  • image:容器镜像
  • cluster:k8s集群
  • storage:blob存储中的对象或目录
  • cloudevent

taskRun和pipelineRun

taskrun代表task的1次执行过程,pipelinerun也是类似。具体运行时,task和pipeline连接到配置的resource上,再创建出taskrun和pipelinerun

taskrun和pipelinerun可手动创建、trigger自动触发,创建过程中可进行参数赋值(parameters)

运行流程

  1. 定义pipelinerun,传参、调用的pipeline
  2. 定义pipeline,声明参数、调用task、传参task
  3. 定义task,声明参数,定义step

taskrun和step

每个taskrun运行在1个独立的pod中,内部每个step分别运行在容器中

状态跟踪:pipeline组件使用k8s注解跟踪pipeline的状态,给每个step相关的容器注入entrypoint程序,此程序执行step定义的内容、监视文件

每个step容器会在自己的注解中报告前一个容器执行结果(此结果是一个文件),查看文件,结果是运行成功,才运行当前容器的entrypoint

image-20240103175842384


parameters

是task和pipeline资源定于模板,类似ansible的变量使用方式,需要先声明,然后在引用,运行的时候再传参,或者以代码中形参与实参的关系理解

使用场景:在ci管道中定义git仓库时,可以在task中直接定义1个仓库变量,后续的step中引用这个变量即可,这样实现模板化

image-20240103175614475

parameters变量引用

变量引用(参数)方式:

$(params.变量名)   	#字符串类型,获取从params字段定义的变量名的值
$(params.变量名.k1)	#数组类型,获取变量名下的k1的值
$(params.flags[*])		#获取数组中所有值

数据共享

pipeline和task上可能会存在数据共享的需要,如:

  • 1个task的多个step之间,前1个step生成的结果交给后1个step引用
  • 1个pipeline的多个task间,前1个task的结果交给后1个task引用

解决方案:

  • results
  • workspace

workspace

为task的各step提供工作目录,在task声明,且需要taskrun中提供运行时的文件系统

在k8s中对应为存储卷,也就是:

  • cm、secret:只读workspace
  • pvc:支持跨task共享数据的工作空间
  • emptyDir:临时工作目录,step间可共享数据,task间不行

注:emptyDir的生命周期和pod相同,因此只能在1个taskrun的各step间共享数据,如果要跨task共享数据,则使用pvc

功能

  • 跨task共享数据(定义在pipeline的workspace)
  • 借助secret加载秘密数据
  • 借助cm加载配置数据
  • 持久化存储数据
  • 为task提供缓存加速构建过程。定义在task上的workspace,也可用于sidecat共享数据

建议:

  • 同一task内,使用emptyDir
  • 同一pipeline内,使用VolumeClaimTemplate
  • 跨pipeline,使用静态pvc或直接用存储卷

定义:

参考各资源的.spec.workspaces字段

变量引用

$(workspaces.名称.path)    	#挂载路径。可选项打开时,且taskrun未声明时为空
$(workspaces.名称.bound)  	#布尔值,是否已经已经绑定。可选项关闭时,始终为true
$(workspaces.名称.claim)  	#使用pvc时的名称,非pvc则为空
$(workspaces.名称.volume) 	#存储卷名称

results

由tekton的results api负责实现,在task声明,用于让task及step保存执行结果,可以在同一pipeline中的后续task调用此结果

task将会为每个results条目自动创建1个文件进行保存,这些文件统一放在:/tekton/results目录

每个results条目的相关值,需要在step中进行生成并保存,且task不会对相关数据进行任何多余的操作,然后后面的step就可以访问此路径,获取数据

:仅用于共享小于4096字节的数据,更多时小于1024字节

变量引用

step中引用
$(results.名称.path)  	#结果文件中的内容
task中引用
results.名称.path
results['名称'].path
results["名称"].path
pipeline中引用
task.task名称.results.名称
task.task名称.results['名称']
task.task名称.results["名称"]

volumes

允许在steps间挂载,共享挂载的卷数据,此配置是静态配置,也就是在task定义时就必须指定好,配置方法参考task.spec.volumestask.spec.steps.volumeMounts字段,与pod配置存储卷一样
不再需要workspace传递路径


CRD配置

运行方法:

  • 定义Tasks,各task中定义step完成各步骤
  • 定义pipeline,引用Task,并指定各task的运行顺序
  • 定义pipelineRun,手动触发pipeline运行
  • 定义Trigger,基于事件监听自动触发pipeline执行

task资源

命令

tkn task start hello --showlog
tkn task start logger --showlog -p text=123

语法

文档:https://tekton.dev/docs/pipelines/tasks/

注意:在script命令中,如果对results赋值,如果用echo输出,一定要使用:echo -n(不换行模式),否则有大坑(别的任务引用结果的时候,有一大串空空白符,识别起来部分有问题)

apiVersion: tekton.dev/v1 # or tekton.dev/v1beta1
kind: Task
metadata:
  name: example-task-name
spec:
  params:         #声明参数
  - name: 变量名
    type: 类型
      #str
      #arry
    description: 变量描述或|k
    default: 默认值        #空变量就赋值此默认的
  description: >-    #task描述信息,">-"表示开启多行模式,与"|"符号一样
  steps:          #步骤,必须项,本质上与定义pod的容器没有区别
  - name: 步骤名
    image: 镜像     #在此步骤中需要基于此镜像执行相关内容
    args: [str]     #传参
    command: [str]  #cmd命令,与script互斥
    script: |      #默认以sh为执行shell,与command互斥。在linux容器执行shell,win容器执行powershell,win使用执行器:#!win powershell.exe -File,或#!win pwsh.exe -File
      #!/usr/bin/env bash
      脚本内容
    workingDir: 工作目录        #可用workspaces变量获取
    timeout: 秒      #步骤执行超时时间,超时就中断退出
    onError: 条件     #忽略错误条件,查看错误命令:kubectl get tr po名 -o json | jq .status
      #stopAndFail,遇到错误就停止并中断
      #continue ,忽略错误,继续执行后续步骤
    volumentMounts:   #存储卷挂载,与pod使用方法一样
    - name: 名称
      mountPath: 路径
    computeResources:   #参考容器资源限制
      requests:
        memory: 1Gi
        cpu: 500m
      limits:
        memory: 2Gi
        cpu: 800m
  workspaces:     #卷路径
  - name: 名称
    description: 描述
    readOnly: false     #默认读写
    optional: false     #是否为可选,默认false
    mountPath: 挂载路径     #step容器中挂载路径,默认为:/workspace/名称
  results:        #执行结果
  - name: 名称     #结果名称
    description: 描述
  volumes:        #存储卷,step间共享此卷数据,与pod使用一样
  - name: 名称
    emptyDir: {}
  stepTemplate:   #所有step的基础容器步骤定义
  sidecars:       #注入step的容器

示例

例1:
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: hello
spec:
  steps:
  - name: say-hello
    image: alpine:3.15
    command: ['/bin/sh']
    args: ['-c', 'echo Hello World']
例2:
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: multiple
spec:
  steps:
  - name: first
    image: alpine:3.15
    command:
      - /bin/sh
    args: ['-c', 'echo First Step']
  - name: second
    image: alpine:3.15
    command:
      - /bin/sh
    args: ['-c', 'echo Second Step']
例4:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: logger
spec:
  params:
  - name: text
    type: string
    description: something to log
    default: "-"
  steps:
  - name: log
    image: alpine:3.15
    script: |
      #/bin/sh
      sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
      apk add -q tzdata
      cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      DATETIME=$(date "+%F %T")
      echo [$DATETIME] - $(params.text)

taskrun资源

语法

文档: https://tekton.dev/docs/pipelines/taskruns/

apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  name: my-taskrun
spec:
  taskRef:      #指定运行的task
    name: my-task
  taskSpec:     #直接在此处定义task,类似deploy中定义pod模板
  inputs:
    params:
    - name: param1
      value: value1
    - name: param2
      value: value2
  serviceAccountName: sa名
  params:       #task传参
  timeout: 1h   #taskrun执行超时时间
  podTemplate:      #定义pod模板
  workspaces:       #task声明的物理卷
  - name: 名
  debug:            #task调试
  stepOverrides:    #覆盖task中step的配置
  sidecarOverrides:     #step注入容器的配置

示例

apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  name: hello-run-00001
spec:
  taskRef:
    kind: Task
    name: hello

注解中标识报告前一个任务已经运行完成,有这个注解后,再继续执行当前stepimage-20240103191335554

通过注入的entrypoint,传入参数,等待前一个任务执行完成(查看前一个step执行完成后输出的文件结果,没问题则执行当前step),来实现依次运行
image-20240103191450280

pipeline资源

命令

tkn pipeline ls
tkn pipeline start pipeline-demo --showlog
tkn pipeline start pipeline-with-params --showlog -p text=123

语法

文档:https://tekton.dev/docs/pipelines/pipelines/

apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
spec:
  params:     #声明参数
  - name: k
    type: string|array
    value: v
    description: 描述
    default: xx
  workspaces:     #工作目录,声明工作目录
  - name: 名称
  tasks:      #需要运行的task
  - name: 名称            #用于上下文调用名称
    displayName: 名称     #用于显示名称
    description: 描述
    taskRef:          #引用task
      name: 名称
    taskSpec:         #直接在此处定义task
    runAfter:         #指定某task在其他task后面执行,不指定时默认并行
    - name: 名称
    retries: int      #task重试执行次数
    when:         #条件为真才执行task
    - input: str        #字符串、变量或运行结果,默认为空
      value: str        #字符串、变量、运行结果或数组(非空数组/列表),必须定义且不能为空
      operator: 操作符
        #in,input获取的内容存在于value中
        #notin,input的内容不存在与value中
    timeout: 秒
    params:
    - name: k
      type: string|array
      value: v          #如果需要pipelinerun传参,则值为:$(params.k)
      description: 描述
      default: xx
    workspaces:         #task的工作空间
    - name: 名称          #定义名称,task模板中使用此名称
      workspace: 名称    #引用spec.workspaces中定义的
    matrix:
  results:              #管道执行结果
  - name: 名称
    description: 描述
  displayName: 名称     #管道显示名称
  description: 描述
  finally:              #指定在所有任务完成后执行的task,与普通task一样配置。一般用于发送通知、清理资源、终止任务等
  - name: 名称            #用于上下文调用名称
    displayName: 名称     #用于显示名称
    description: 描述
    taskRef:          #引用task
    taskSpec:         #直接在此处定义task
    runAfter:         #指定某task在其他task后面执行
    retries: int      #task重试执行次数
    when: 条件        #条件为真才执行task
    timeout: 秒
    params:
    workspaces:         #task的工作空间
    matrix:

示例

例1:
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: pipeline-demo
spec:
  tasks:
  - name: first-task
    taskRef:
      name: hello
  - name: second-task
    taskRef:
      name: multiple
    runAfter:
    - first-task
例2:
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: pipeline-with-params
spec:
  params:
  - name: text
    type: string
  tasks:
  - name: task-one
    taskRef:
      name: hello
  - name: task-two
    taskRef:
      name: logger
    params:
    - name: text
      value: $(params.text)
例3:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: pipeline-task-ordering
spec:
  tasks:
    - name: task-a
      taskRef:
        name: logger
      params:
      - name: text
        value: "task-A executed"
    - name: task-b
      taskRef:
        name: logger
      params:
      - name: text
        value: "Executed after task-A"
      runAfter: ["task-a"]
    - name: task-c
      taskRef:
        name: logger
      params:
      - name: text
        value: "Executed after task-A"
      runAfter: ["task-a"]
    - name: task-d
      taskRef:
        name: logger
      params:
      - name: text
        value: "Executed after task-B and task-C"
      runAfter: ["task-b", "task-c"]

pipelinerun资源

语法

文档:https://tekton.dev/docs/pipelines/pipelineruns/

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
spec:
  pipelineRef:        #引用管道
    name: 名称
    resolver: 解析资源     #启用解析特性,允许声明参数中解析oci资源、远程资源
      #bundles,如docker镜像,在参数中的value字段直接使用镜像
      #git,解析git仓库,参数中value字段直接使用git仓库
  pipelineSpec:       #定义管道,与上面互斥
    tasks:
  params:
  - name: k
    value: v          #传参、声明参数都可以这么用
      k1: v1          #上面赋值,或这种赋值,2选一
      k2: v2
  serviceAccountName: sa        #所有task使用此sa的权限,与taskRunSpecs.serviceAccountName字段互斥
  status:             #取消管道运行的选项
  taskRunTemplate:      #taskrun模板
    serviceAccountName: sa      #sa的名称,可为task单独指定sa
    podTemplate:            #为task中容器指定单独内容,与pod资源一样使用
      securityContext:
        runAsNonRoot: true
         runAsUser: 1001
    volumes:
    - name: my-cache
      persistentVolumeClaim:
        claimName: my-volume-claim
  taskRunSpecs:       #指定PipelineRunTaskSpec的列表,允许为每个任务设置sa、Pod模板和Metadata。可覆盖整个Pipeline设置的Pod模板
  - pipelineTaskName: pipeline中task名称
    serviceAccountName: sa          #为task单独指定sa
    computeResources:
      requests:
        cpu: 2
    podTemplate:
      nodeSelector:
        disktype: ssd
    metadata: 
      annotations:
  timeouts: 秒
  podTemplate:        #定义task的基础pod模板,全局生效
  workspaces:         #定义工作目录
  - name: 名称
    volumeClaimTemplate:        #申请pvc,与pvc使用一致,但需要提前准备存储类
      spec:
        accessMode:
        - 模式
        ...
    subPath: 路径         #可定义挂载子路径。可以是绝对值:workspaces[].subPath,也可以引用pipelineRun上下文变量,例如 $(context.pipelineRun.name) 或 $(context.pipelineRun.uid)

示例

例1:
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: pipeline-demo-run-xxxxx
  namespace: default
spec:
  pipelineRef:
    name: pipeline-demo
  serviceAccountName: default
  timeout: 1h0m0s
例2:
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: pipeline-with-params-run-xxxxx
  namespace: default
spec:
  params:
  - name: target
    value: "one"
  - name: text
    value: "two"
  pipelineRef:
    name: pipeline-with-params
  serviceAccountName: default
  timeout: 10m0s

综合案例

例1:多steps间共享数据(使用wokrspace)

1)创建task
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: ws-demo
spec:
  params:
  - name: target
    type: string
    default: 123456
  steps:
  - name: alpine-img
    image: alpine
    script: |
      set -xe
      if [ $(workspaces.msg.bound) == true ]; then
        #实际路径为:/data/msg
        echo hello $(params.target) > $(workspaces.mgs.path)/msg
      fi
      echo "mount path: $(workspaces.mgs.path)"
      echo "volume name: $(workspaces.msg.volume)"
  workspaces:
  - name: msg
    description: "信息记录文件"
    optional: true
    mountPath: /data      #挂载到/data,
2)运行
tkn task start --showlog ws-demo -p target="hj" -w name=msg,emptyDir=""

例2:多steps间共享数据(使用result)

:保存results变量时,一定不能加换行符,否则后面任务识别有问题(换行有坑)

apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: generate-buildid
spec:
  params:
    - name: version
      description: The version of the application
      type: string
      default: "v0.9"
  results:
    - name: datetime
      description: The current date and time
    - name: buildId
      description: The build ID
  steps:
    - name: generate-datetime
      image: ikubernetes/admin-box:v1.2
      script: |
        #!/usr/bin/env bash
        datetime=`date +%Y%m%d-%H%M%S`
        echo -n ${datetime} | tee $(results.datetime.path)
    - name: generate-buildid
      image: ikubernetes/admin-box:v1.2
      script: |
        #!/usr/bin/env bash
        buildDatetime=`cat $(results.datetime.path)`
        buildId=$(params.version)-${buildDatetime}
        echo -n ${buildId} | tee $(results.buildId.path)

例3:pipelinerun对task传参

apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: hello-task-1
spec:
  params:
  - name: target
    type: string
    description: one number
    default: 123456
  steps:
  - name: alpine-1
    image: alpine
    script: |
      echo hello $(params.target)
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: pipeline-demo
spec:
  params:
  - name: target
    type: string
    default: 654321
  tasks:
  - name: task1
    taskRef:
      name: hello-task-1
    params:
    - name: target
      value: $(params.target)       #获取Pipeline.spec.params.target的内容
---
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: pipelinerun-demo
spec:
  params:
  - name: target        #为pipeline-demo传参
    value: hj
  pipelineRef:
    name: pipeline-demo

例4:简单代码克隆、构建

1)创建任务与流水线
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: make-code-task
spec:
  params:
  - name: git-url           #声明变量
    type: string
  workspaces:
  - name: code              #声明工作目录
  steps:
  - name: clone-code
    image: alpine/git:2.40.1
    script: |
      sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
      apk add tzdata git curl
      cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      echo "Asia/Shanghai" > /etc/timezone
      git clone -v --depth 1 $(params.git-url) $(workspaces.code.path)/code
  - name: build
    image: maven:3.8.7-openjdk-18-slim
    workingDir: $(workspaces.code.path)/code
    script: |
      sed -i -e '/\/mirrors/i\    <mirror>' \
      -e '/\/mirrors/i\      <id>aliyunmaven</id>' \
      -e '/\/mirrors/i\      <mirrorOf>*</mirrorOf>' \
      -e '/\/mirrors/i\      <name>阿里云公共仓库</name>' \
      -e '/\/mirrors/i\      <url>https://maven.aliyun.com/repository/public</url>' \
      -e '/\/mirrors/i\    </mirror>' \
      /usr/share/maven/conf/settings.xml
      mvn clean test install
    #以下全部都是需要使用pvc,手动或使用nfs-csi都可
    volumeMounts:
    - name: mvn-cache
      mountPath: /root/.m2
  volume:
  - name: mvn-cache
    persistentVolumeClaim:
      claimName: mvn-cache
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: make-code
spec:
  params:                   #重新声明参数,为task声明的
  - name: git-url
    type: string
  workspaces:           #声明工作目录,为task声明的,后面与task的关联
  - name: code-dir
  tasks:
  - name: build-java
    params:
    - name: git-url
      value: $(params.git-url)      #传参给task的变量
    workspaces:
    - name: code            #task中对应的工作目录
      workspace: code-dir       #赋值给task的工作目录
    taskRef:
      name: make-code-task
2)运行
tkn pipeline start make-code --showlog -p git-url='https://gitee.com/mageedu/spring-boot-helloWorld.git' -w name=code-dir,emptyDir=""

例5:基于例3并加上动静态pvc实现

1)创建存储类

使用nfs-csi存储驱动,nfs-csi部署参考:nfs-csi驱动部署

kubectl apply -f - <<eof
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
  server: nfs-server.default.svc.cluster.local
  share: /
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
- nfsvers=4.1
eof
2)创建pvc
kubectl apply -f - <<eof
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mvn-cache
spec:
  storageClassName: nfs-csi
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
eof
3)创建任务
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: make-code-task
spec:
  params:
  - name: git-url
    type: string
  workspaces:
  - name: code
  steps:
  - name: clone-code
    image: alpine/git:2.40.1
    script: |
      sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
      apk add tzdata git curl
      cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      echo "Asia/Shanghai" > /etc/timezone
      git clone -v --depth 1 $(params.git-url) $(workspaces.code.path)
  - name: build
    image: maven:3.8.7-openjdk-18-slim
    workingDir: $(workspaces.code.path)
    script: |
      sed -i -e '/\/mirrors/i\    <mirror>' \
      -e '/\/mirrors/i\      <id>aliyunmaven</id>' \
      -e '/\/mirrors/i\      <mirrorOf>*</mirrorOf>' \
      -e '/\/mirrors/i\      <name>阿里云公共仓库</name>' \
      -e '/\/mirrors/i\      <url>https://maven.aliyun.com/repository/public</url>' \
      -e '/\/mirrors/i\    </mirror>' \
      /usr/share/maven/conf/settings.xml
      mvn clean test install
    volumeMounts:
    - name: mvn-cache
      mountPath: /root/.m2
  volumes:
  - name: mvn-cache
    persistentVolumeClaim:
      claimName: mvn-cache
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: make-code
spec:
  params:
  - name: git-url
    type: string
  workspaces:
  - name: code-dir
  tasks:
  - name: build-java
    params:
    - name: git-url
      value: $(params.git-url)
    workspaces:
    - name: code
      workspace: code-dir
    taskRef:
      name: make-code-task
4)创建流水线运行任务
kubectl apply -f - <<eof
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: make-code
spec:
  params:
  - name: git-url
    value: https://gitee.com/mageedu/spring-boot-helloWorld.git
  pipelineRef:
    name: make-code
  workspaces:
  - name: code-dir
    volumeClaimTemplate:
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 100Mi
        storageClassName: nfs-csi
eof

浏览器查看时,可以看到流水线已经执行完成image-20240104133119057

例6:cicd流水线

image-20240104150819687

k8s中,容器中构建镜像的方法有2种:

  • dink(docker-in-docker):挂载宿主机docker套接字,使用宿主机docker完成
  • kaniko:无任何依赖,直接容器中构建镜像
1)配置镜像仓库登录信息

docker信息文件可以在命令行登录后,自动生成,也可以手动创建:

# 将账号密码做编码转换
# echo 账号:密码 |base64
upw=`echo 账号:密码 |base64`

cat > docker-user.json <<eof
{
  "auths": {
      "https://index.docker.io/v1/": {
        "auth": "$upw"
      },
      "registry.cn-hangzhou.aliyuncs.com": {
        "auth": "$upw"
      }
  }
}
eof

创建secret资源

#docker login -u suyanhj https://hub.docker.com/

#此处登录阿里云
docker login -u 那是你的猫 registry.cn-hangzhou.aliyuncs.com
kubectl create secret generic docker-config --from-file=/root/.docker/config.json
2)创建集群部署管理账号

给kubectl命令访问api-server的权限,运行创建资源

kubectl apply -f - <<eof
apiVersion: v1
kind: ServiceAccount
metadata:
  name: helloworld-admin
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: helloworld-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: helloworld-admin
  namespace: default
eof
3)创建代码克隆任务
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: git-clone
spec:
  description: Clone the code repository to the workspace.
  params:
  - name: url
    type: string
    description: git url to clone
    default: ""
  - name: branch
    type: string
    description: git branch to checkout
    default: "main"
  workspaces:
  - name: source
    description: The git repo will be cloned onto the volume backing this workspace
  steps:
  - name: git-clone
    image: alpine/git:2.40.1
    script: |
      sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
      apk add tzdata git curl
      cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      echo "Asia/Shanghai" > /etc/timezone
      git clone -b $(params.branch) -v $(params.url) $(workspaces.source.path)
4)创建代码编译打包任务
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: build-to-pkg
spec:
  description: build application and package the files to image
  workspaces:
  - name: source
    description: The git repo that cloned onto the volume backing this workspace
  steps:
  - name: build
    image: maven:3.8.7-openjdk-18-slim
    workingDir: $(workspaces.source.path)
    script: |
      sed -i -e '/\/mirrors/i\    <mirror>' \
      -e '/\/mirrors/i\      <id>aliyunmaven</id>' \
      -e '/\/mirrors/i\      <mirrorOf>*</mirrorOf>' \
      -e '/\/mirrors/i\      <name>阿里云公共仓库</name>' \
      -e '/\/mirrors/i\      <url>https://maven.aliyun.com/repository/public</url>' \
      -e '/\/mirrors/i\    </mirror>' \
      /usr/share/maven/conf/settings.xml
      mvn clean install
    volumeMounts:
    - name: mvn-cache
      mountPath: /root/.m2
  volumes:
  - name: mvn-cache
    persistentVolumeClaim:
      claimName: mvn-cache
5)创建容器镜像版本号生成任务
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: generate-build-id
spec:
  params:
  - name: version
    description: The version of the application
    type: string
  results:
  - name: datetime
    description: The current date and time
  - name: buildId
    description: The build ID
  steps:
  - name: generate-datetime
    image: busybox
    script: |
      #!/bin/sh
      datetime=`date +%Y%m%d-%H%M%S`
      echo -n ${datetime} | tee $(results.datetime.path)
  - name: generate-buildid
    image: busybox
    script: |
      #!/bin/sh
      buildDatetime=`cat $(results.datetime.path)`
      buildId=$(params.version)-${buildDatetime}
      echo -n ${buildId} | tee $(results.buildId.path)
6)创建容器镜像构建任务
方法1:使用kaniko,直接在容器中构建镜像
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: img-build
spec:
  description: package the application files to image
  params:
  - name: dockerfile
    description: The path to the dockerfile to build (relative to the context)
    default: Dockerfile
  - name: image-url
    description: Url of image repository
  - name: image-tag
    description: Tag to apply to the built image
    default: latest
  workspaces:
  - name: source
  - name: dockerconfig
    #将docker账号信息,挂载到kaniko容器中,用于推送镜像到仓库
    mountPath: /kaniko/.docker
  steps:
  - name: build-and-push-img
    image: m.daocloud.io/gcr.io/kaniko-project/executor:debug
    securityContext:
      runAsUser: 0
    command:
    - /kaniko/executor
    args:
    #选项解释:https://github.com/GoogleContainerTools/kaniko#additional-flags
    - --dockerfile=$(params.dockerfile)		#dockefile文件名
    - --context=$(workspaces.source.path)		#构建镜像时的工作目录
    - --destination=$(params.image-url):$(params.image-tag)	#镜像上传路径与标签
    #- --build-arg
    #- --cache
    #- --cache-dir
    #- --cache-repo
    #- --cache-copy-layers
    #- --cache-run-layers
    #- --cache-ttl duration
    #- --cleanup
    #- --compressed-caching
    #- --context-sub-path
    #- --custom-platform
    #- --digest-file
    #- --force
    #- --git
    #- --image-name-with-digest-file
    #- --image-name-tag-with-digest-file
    #- --insecure
    #- --insecure-pull
    #- --insecure-registry
    #- --label
    #- --log-format
    #- --log-timestamp
    #- --oci-layout-path
    #- --push-retry
    #- --registry-certificate
    #- --registry-client-cert
    #- --registry-mirror		#镜像下载加速地址,不需要写访问协议,只需写域名
    #- --skip-default-registry-fallback
    #- --reproducible
    #- --single-snapshot
    #- --skip-tls-verify
    #- --skip-push-permission-check
    #- --skip-tls-verify-pull
    #- --skip-tls-verify-registry
    #- --skip-unused-stages
    #- --snapshot-mode
    #- --tar-path
    #- --target
    #- --use-new-run
    #- --verbosity
    #- --ignore-var-run
    #- --ignore-path
    #- --image-fs-extract-retry
    #- --image-download-retry
方法2:使用dind(需要安装docker并挂载套接字)
kind: Task
...
spec:
  params:
    - name: dockerfileName
      type: string
      description: The name of the Dockerfile
      default: Dockerfile
    - name: image
      type: string
      description: The image to build and push
  workspaces:
  - name: source
  steps:
    - name: dockerfile-build
      image: gcr.io/cloud-builders/docker
      workingDir: "$(workspaces.source.path)"
      args:
        [
          "build",
          "--no-cache",
          "--tag",
          "$(params.image)",
          "--file",
          "$(params.dockerfileName)",
          ".",
        ]
      volumeMounts:
        - name: docker-socket
          mountPath: /var/run/docker.sock
    - name: dockerfile-push
      image: gcr.io/cloud-builders/docker
      args: ["push", "$(params.image)"]
      volumeMounts:
        - name: docker-socket
          mountPath: /var/run/docker.sock
  volumes:
    - name: docker-socket
      hostPath:
        path: /var/run/docker.sock
        type: Socket
7)创建应用部署于集群任务

pod与k8s处于同一个集群时,sa就可以保障api-server可以访问,只有跨集群时,需要配置远程集群的kubeconfig文件

注:部署时要考虑是否在部署清单中配置拉镜像的仓库登录账号(取决于仓库公开/私有)

apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: deploy-using-kubectl
spec:
  workspaces:
  - name: source
    description: The git repo
  params:
  - name: deploy-config-file
    description: The path to the yaml file to deploy within the git source
  - name: image-url
    description: Image name including repository
  - name: image-tag
    description: Image tag
  steps:
  - name: update-yaml
    image: alpine:3.16
    command: ["sed"]
    args:
    - "-i"
    - "-e"
    - "s@__IMAGE__@$(params.image-url):$(params.image-tag)@g"
    - "$(workspaces.source.path)/deploy/$(params.deploy-config-file)"
  - name: run-kubectl
    image: lachlanevenson/k8s-kubectl
    command: ["kubectl"]
    args:
    #当前部署的集群与kubectl相同集群,所以不需要传递kubeconfig
    - "apply"
    - "-f"
    - "$(workspaces.source.path)/deploy/$(params.deploy-config-file)"
8)创建流水线,编排任务
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: source-to-img
spec:
  params:
  - name: git-url
  - name: pathToContext
    description: The path to the build context, used by Kaniko - within the workspace
    default: .
  - name: image-url
    description: Url of image repository
  - name: deploy-config-file
    default: all-in-one.yaml
  - name: version
    description: The version of the application
    type: string
    default: "v0.9"
  workspaces:
  - name: codebase
  - name: docker-config
  tasks:
  - name: git-clone
    taskRef:
      name: git-clone
    params:
    - name: url
      value: "$(params.git-url)"
    workspaces:
    - name: source
      workspace: codebase
  - name: build-to-pkg
    taskRef:
      name: build-to-pkg
    workspaces:
    - name: source
      workspace: codebase
    runAfter:
    - git-clone
  - name: generate-build-id
    taskRef:
      name: generate-build-id
    params:
    - name: version
      value: "$(params.version)"
    runAfter:
    - git-clone
  - name: img-build-push
    taskRef:
      name: img-build
    params:
    - name: image-url
      value: "$(params.image-url)"
    - name: image-tag
      value: "$(tasks.generate-build-id.results.buildId)"
    workspaces:
    - name: source
      workspace: codebase
    - name: dockerconfig
      workspace: docker-config
    runAfter:
    - build-to-pkg
    - generate-build-id
  - name: deploy-to-cluster
    taskRef:
      name: deploy-using-kubectl
    workspaces:
    - name: source
      workspace: codebase
    params:
    - name: deploy-config-file
      value: $(params.deploy-config-file)
    - name: image-url
      value: $(params.image-url)
    - name: image-tag
      value: "$(tasks.generate-build-id.results.buildId)"
    runAfter:
    - img-build-push
10)创建流水线运行任务,执行应用部署
kubectl apply -f - <<eof
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  name: deploy-java
spec:
  #serviceAccountName: default
  taskRunSpecs:
  - pipelineTaskName: deploy-to-cluster
    serviceAccountName: helloworld-admin
  pipelineRef:
    name: source-to-img
  params:
  - name: git-url
    value: https://gitee.com/mageedu/spring-boot-helloWorld.git
  - name: image-url
    value: registry.cn-hangzhou.aliyuncs.com/suyanhj/spring-boot-helloworld
    #value: suyanhj/spring-boot-helloworld
  - name: version
    value: v0.9.2
  workspaces:
  - name: docker-config
    secret:
      secretName: docker-config
  - name: codebase
    volumeClaimTemplate:
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 100Mi
        storageClassName: nfs-csi
eof
11)测试
pod_ip=`kubectl get po -o wide |awk '/helloworld/{print $6}'`
curl $pod_ip ;echo
posted @ 2024-01-04 11:34  suyanhj  阅读(111)  评论(0编辑  收藏  举报