kubernetes原生pipeline

安全劍客發表於2019-05-15
Tekton Pipeline,是一個k8s native的pipeline, 任務跑在pod中,透過自定義CRD去管理任務與工作流等等,我看完tekton之後感覺是功能很強大,但是有點過度設計了,沒有drone的簡約大方靈活之感。
Task

Tekton Pipelines的主要目標是單獨執行您的任務或作為管道的一部分執行。每個任務都在Kubernetes叢集上作為Pod執行,每個步驟都作為自己的容器。這點深得drone思想精髓,其實drone也有計劃將kubernetes作為任務執行引擎,只是沒有下文了。

A Task定義了需要執行的工作,例如以下是一個簡單的任務:

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: echo-hello-world
spec:
  steps:
    - name: echo
      image: ubuntu
      command:
        - echo
      args:
        - "hello world"

這steps是一系列由任務順序執行的 。這個steps內的配置幾乎與drone如出一轍,Task定義好並沒有被執行,建立TaskRun時才會執行。這是合理的,相當於是一個觸發

apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: echo-hello-world-task-run
spec:
  taskRef:
    name: echo-hello-world
  trigger:
    type: manual
kubectl apply -f < name-of-file.yaml >

檢視TaskRun kubectl get taskruns / echo-hello-world-task-run -o yaml

apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  creationTimestamp: 2018-12-11T15:49:13Z
  generation: 1
  name: echo-hello-world-task-run
  namespace: default
  resourceVersion: "6706789"
  selfLink: /apis/tekton.dev/v1alpha1/namespaces/default/taskruns/echo-hello-world-task-run
  uid: 4e96e9c6-fd5c-11e8-9129-42010a8a0fdc
spec:
  generation: 1
  inputs: {}
  outputs: {}
  taskRef:
    name: echo-hello-world
  taskSpec: null
  trigger:
    type: manual
status:
  conditions:
    - lastTransitionTime: 2018-12-11T15:50:09Z
      status: "True"
      type: Succeeded
  podName: echo-hello-world-task-run-pod-85ca51
  startTime: 2018-12-11T15:49:39Z
  steps:
    - terminated:
        containerID: docker://fcfe4a004...6729d6d2ad53faff41
        exitCode: 0
        finishedAt: 2018-12-11T15:50:01Z
        reason: Completed
        startedAt: 2018-12-11T15:50:01Z
    - terminated:
        containerID: docker://fe86fc5f7...eb429697b44ce4a5b
        exitCode: 0
        finishedAt: 2018-12-11T15:50:02Z
        reason: Completed
        startedAt: 2018-12-11T15:50:02Z

狀態Succeeded = True顯示任務已成功執行。

任務輸入和輸出

在更常見的場景中,任務需要多個步驟來處理輸入和輸出資源。例如,Task可以從GitHub儲存庫獲取原始碼並從中構建Docker映象。

PipelinesResources用於定義任務的輸入(如程式碼)與輸出(如Docker映象)。有一些系統定義的資源型別可供使用,以下是通常需要的兩個資源示例。

該git資源可以是你要編譯的程式碼:

apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: skaffold-git
spec:
  type: git
  params:
    - name: revision
      value: master
    - name: url
      value: 

該image資源代表要被任務編譯成的映象:

apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: skaffold-image-leeroy-web
spec:
  type: image
  params:
    - name: url
      value: gcr.io//leeroy-web

以下是Task輸入和輸出。輸入資源是GitHub儲存庫,輸出是從該源生成的影像。任務 的引數支援模板化,因此任務的定義是常量,引數的值可以在執行時更改。

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: build-docker-image-from-git-source
spec:
  inputs:
    resources:
      - name: docker-source
        type: git
    params:
      - name: pathToDockerFile       # 這些引數都是可以自定義的
        description: The path to the dockerfile to build
        default: /workspace/docker-source/Dockerfile
      - name: pathToContext
        description:
          The build context used by Kaniko
          ()
        default: /workspace/docker-source
  outputs:
    resources:
      - name: builtImage
        type: image
  steps:
    - name: build-and-push
      image: gcr.io/kaniko-project/executor  # 特定功能的映象,可以用來docker build
      command:
        - /kaniko/executor
      args:
        - --dockerfile=${inputs.params.pathToDockerFile}   # 這時原pathToDockerFile就是上面定義的引數
        - --destination=${outputs.resources.builtImage.url}
        - --context=${inputs.params.pathToContext}

TaskRun將輸入和輸出繫結到已定義的PipelineResources值,除了執行任務步驟外,還將值設定為用於模板化的引數。

apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: build-docker-image-from-git-source-task-run
spec:
  taskRef:
    name: build-docker-image-from-git-source
  trigger:
    type: manual
  inputs:
    resources:
      - name: docker-source
        resourceRef:
          name: skaffold-git
    params:                       # 執行時把引數傳給Task,這樣就不需要重複定義task,只需要增加input output 和taskrun 就可以跑一個別的工程, 從解耦這個角度到說比drone更好,任務流程可以複用
      - name: pathToDockerFile
        value: Dockerfile
      - name: pathToContext
        value: /workspace/docker-source/examples/microservices/leeroy-web #configure: may change according to your source
  outputs:
    resources:
      - name: builtImage
        resourceRef:
          name: skaffold-image-leeroy-web  # 這也是上面指定的資源

PS: inputs outputs應當不限制死必須叫這兩個名字,只要是能支援引數就好。比如定義一個叫build的資源去指定docker build的映象:

apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: skaffold-image-leeroy-web
spec:
  type: image
  params:
    - name: url
      value: docker-in-docker:latest

Task 裡:

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: build-docker-image-from-git-source
spec:
  build:
     resources:
     - name: build
       type: image
  params:
  - name: build-image
    default: docker-in-docker:latest
  steps:
      - name: build-and-push
      image: ${build.params.build-image}

我是覺得需要能進行這樣的擴充套件了, 僅是inputs outputs就狹義了

獲取pipeline全部資訊 kubectl get build-pipeline

NAME                                                   AGE
taskruns/build-docker-image-from-git-source-task-run   30s
NAME                                          AGE
pipelineresources/skaffold-git                6m
pipelineresources/skaffold-image-leeroy-web   7m
NAME                                       AGE
tasks/build-docker-image-from-git-source   7m

要檢視TaskRun的輸出,請使用以下命令:

kubectl get taskruns / build-docker-image-from-git-source-task-run -o yaml
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  creationTimestamp: 2018-12-11T18:14:29Z
  generation: 1
  name: build-docker-image-from-git-source-task-run
  namespace: default
  resourceVersion: "6733537"
  selfLink: /apis/tekton.dev/v1alpha1/namespaces/default/taskruns/build-docker-image-from-git-source-task-run
  uid: 99d297fd-fd70-11e8-9129-42010a8a0fdc
spec:
  generation: 1
  inputs:
    params:
      - name: pathToDockerFile
        value: Dockerfile
      - name: pathToContext
        value: /workspace/git-source/examples/microservices/leeroy-web #configure: may change depending on your source
    resources:
      - name: git-source
        paths: null
        resourceRef:
          name: skaffold-git
  outputs:
    resources:
      - name: builtImage
        paths: null
        resourceRef:
          name: skaffold-image-leeroy-web
  taskRef:
    name: build-docker-image-from-git-source
  taskSpec: null
  trigger:
    type: manual
status:
  conditions:
    - lastTransitionTime: 2018-12-11T18:15:09Z
      status: "True"
      type: Succeeded
  podName: build-docker-image-from-git-source-task-run-pod-24d414
  startTime: 2018-12-11T18:14:29Z
  steps:
    - terminated:
        containerID: docker://138ce30c722eed....c830c9d9005a0542
        exitCode: 0
        finishedAt: 2018-12-11T18:14:47Z
        reason: Completed
        startedAt: 2018-12-11T18:14:47Z
    - terminated:
        containerID: docker://4a75136c029fb1....4c94b348d4f67744
        exitCode: 0
        finishedAt: 2018-12-11T18:14:48Z
        reason: Completed
        startedAt: 2018-12-11T18:14:48Z

型別的狀態Succeeded = True顯示Task已成功執行,您還可以驗證Docker映象是否生成。

Pipeline

Pipeline定義要按順序執行的任務列表,同時還透過使用該from欄位指示是否應將任何輸出用作後續任務的輸入,並指示執行的順序(使用runAfter和from欄位)。您在任務中使用的相同模板也可以在管道中使用。

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: tutorial-pipeline
spec:
  resources:
    - name: source-repo
      type: git
    - name: web-image
      type: image
  tasks:
    - name: build-skaffold-web # 編譯與打映象任務,上面已經介紹過
      taskRef:
        name: build-docker-image-from-git-source
      params:
        - name: pathToDockerFile
          value: Dockerfile
        - name: pathToContext
          value: /workspace/examples/microservices/leeroy-web #configure: may change according to your source
      resources:
        inputs:
          - name: workspace
            resource: source-repo
        outputs:
          - name: image
            resource: web-image
    - name: deploy-web          # 部署
      taskRef:
        name: deploy-using-kubectl # 這裡引入了一個透過k8s部署的Task,我們在下文看它是什麼
      resources:
        inputs:                    # 定義輸入,這裡的輸入其實是上個任務的輸出
          - name: workspace
            resource: source-repo
          - name: image            # 比如這個映象,就是上個任務產生的
            resource: web-image
            from:                  # from就如同管道一樣,把上個任務的輸出作為這個任務的輸入
              - build-skaffold-web
      params:                      # 留意這些引數都是傳給Task模板的,覆蓋inputs裡的引數
        - name: path
          value: /workspace/examples/microservices/leeroy-web/kubernetes/deployment.yaml #configure: may change according to your source
        - name: yqArg
          value: "-d1"
        - name: yamlPathToImage
          value: "spec.template.spec.containers[0].image"

以上Pipeline是引用一個Task被叫的deploy-using-kubectl:

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: deploy-using-kubectl
spec:
  inputs:
    resources:
      - name: workspace
        type: git
      - name: image
        type: image
    params:
      - name: path
        description: Path to the manifest to apply
      - name: yqArg
        description:
          Okay this is a hack, but I didn't feel right hard-coding `-d1` down
          below
      - name: yamlPathToImage
        description:
          The path to the image to replace in the yaml manifest (arg to yq)
  steps:
    - name: replace-image  # 第一步替換映象
      image: mikefarah/yq  # 特定功能的映象,和drone同理,這裡主要就是個模板渲染
      command: ["yq"]
      args:
        - "w"
        - "-i"
        - "${inputs.params.yqArg}"
        - "${inputs.params.path}"
        - "${inputs.params.yamlPathToImage}"
        - "${inputs.resources.image.url}"
    - name: run-kubectl                 # 第二步執行kubectl
      image: lachlanevenson/k8s-kubectl
      command: ["kubectl"]
      args:
        - "apply"
        - "-f"
        - "${inputs.params.path}"   # 這就是yaml檔案的位置

要執行Pipeline,請建立PipelineRun如下:

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: tutorial-pipeline-run-1
spec:
  pipelineRef:
    name: tutorial-pipeline
  trigger:
    type: manual
  resources:
    - name: source-repo
      resourceRef:
        name: skaffold-git
    - name: web-image
      resourceRef:
        name: skaffold-image-leeroy-web
執行與檢視pipeline
kubectl apply -f < name-of-file.yaml > kubectl獲取pipelineruns / tutorial-pipeline-run-1 -o yaml
總結

初學者會覺得有點繞,但是這種設計也是為了解耦合,我個人覺得優劣如下:

優勢

可以把k8s叢集作為任務執行引擎,這樣可以更好的利用資源,比如把線上夜間閒置資源用來跑任務,構建映象 離線分析 甚至機器學習。解耦做的比較好,任務模板可以拿來複用,而不需要大家都去重複定義,輸入輸出理念,一個任務的輸入作為另個任務的輸出不錯。

劣勢

有點過度設計,一些簡單的場景可能覺得配置起來有點繞了,輸入輸出依賴分散式系統,對比drone一個pipeline中的容器是共享了一個資料卷的,這樣上個任務產生的檔案很方便的給下個任務用,而基於叢集的任務就可能得依賴git docker映象倉庫等做輸入輸出,有點麻煩,好的解決辦法是利用k8s分佈試儲存給pipeline設定一個共享卷,方便任務間傳輸資料;總體來說路子是對的而且還是有很多場景可以用的。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2644403/,如需轉載,請註明出處,否則將追究法律責任。

相關文章