Knative 初體驗:CICD 極速入門

Knative 社區很早就在討論用 Tekton 替換 Build 模塊的事宜。Knative Build 官方已經正式說明不再建議使用 Knative Build 了。

如果你知道 Knative Build 是什麼相信你理解起 Tekton 就是很容易的一件事了。

  • Knative Build 對自己的一句話概述是:A Kubernetes-native Build resource.
  • Tekton 對自己的一句話概述是: A K8s-native Pipeline resource. https://tekton.dev

由上可以看到,兩者的定位非常相近,但在功能上 Tekton 的設計更加的豐富、完整,這也是社區最終採用 Tekton 的原因。接下來我們就看一下 Tekton 的核心概念。

Tekton 極速入門

Tekton 主要由如下五個核心概念組成:

  • Task
  • TaskRun
  • Pipeline
  • PipelineRun
  • PipelineResource

以上五個概念,每一個都是以 CRD 的形式提供服務的。下面分別簡述一下這五個概念的含義。

Task

Task 就是一個任務執行模板,之所以說 Task 是一個模板是因爲 Task 定義中可以包含變量,Task 在真正執行的時候需要給定變量的具體值。Tekton 的 Task 很類似於一個函數的定義,Task 通過 inputs.params 定義需要哪些入參,並且每一個入參還可以指定默認值。Task 的 steps 字段表示當前 Task 是由哪些子步驟組成的。每一個步驟具體就是一個鏡像的執行,鏡像的啓動參數可以通過 Task 的入參使用模板語法進行配置。

apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: task-with-parameters
spec:
  inputs:
    params:
      - name: flags
        type: array
      - name: someURL
        type: string
  steps:
    - name: build
      image: registry.cn-hangzhou.aliyuncs.com/knative-sample/alpine:3.9
      command: ["sh", "-c"]
      args: [ "echo ${inputs.params.flags} ; echo ${someURL}"]

TaskRun

Task 定義好以後是不能執行的,就像一個函數定義好以後需要調用才能執行一樣。所以需要再定義一個 TaskRun 去執行 Task。TaskRun 主要是負責設置 Task 需要的參數,並通過 taskRef 字段引用要執行的 Task。

apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: run-with-parameters
spec:
  taskRef:
    name: task-with-parameters
  inputs:
    params:
      - name: flags
        value: "--set"
      - name: someURL
        value: "https://github.com/knative-sample"

Pipeline

一個 TaskRun 只能執行一個 Task,當需要編排多個 Task 的時候就需要 Pipeline 出馬了。Pipeline 是一個編排 Task 的模板。Pipeline 的 params 聲明瞭執行時需要的入參。 Pipeline 的 spec.tasks 定義了需要編排的 Task。Tasks 是一個數組,數組中的 task 並不是通過數組聲明的順序去執行的,而是通過 runAfter 來聲明 task 執行的順序。

Tekton controller 在解析 CRD 的時候會解析 Task 的順序,然後依據設定的順序依次去執行。Pipeline 在編排 Task 的時候需要給每一個 Task 傳入必須的參數,這些參數的值可以來自 Pipeline 自身的 params。

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: pipeline-with-parameters
spec:
  params:
    - name: context
      type: string
      description: Path to context
      default: /some/where/or/other
  tasks:
    - name: task-1
      taskRef:
        name: build
      params:
        - name: pathToDockerFile
          value: Dockerfile
        - name: pathToContext
          value: "${params.context}"
    - name: task-2
      taskRef:
        name: build-push
	  runAfter:
        - source-to-image
      params:
        - name: pathToDockerFile
          value: Dockerfile
        - name: pathToContext
          value: "${params.context}"

PipelineRun

和 Task 一樣 Pipeline 定義完成以後也是不能直接執行的,需要 PipelineRun 才能執行 Pipeline。PipelineRun 的主要作用是給 Pipeline 設定必要的入參,並執行 Pipeline。

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  name: pipelinerun-with-parameters
spec:
  pipelineRef:
    name: pipeline-with-parameters
  params:
    - name: "context"
      value: "/workspace/examples/microservices/leeroy-web"

PipelineResource

前面已經介紹了 Tekton 的四個核心概念。現在我們已經知道怎麼定義 task、執行 task 以及編排 task 了。

但可能你還想在 Task 之間共享資源,這就是 PipelineResource 的作用。比如我們可以把 git 倉庫信息放在 PipelineResource 中。這樣所有 Task 就可以共享這份數據了。

piVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: wizzbang-git
  namespace: default
spec:
  type: git
  params:
    - name: url
      value: https://github.com/wizzbangcorp/wizzbang.git
    - name: revision
      value: master

鑑權信息

git 倉庫、鏡像倉庫這些都是需要鑑權才能使用的。所以還需要一種設定鑑權信息的機制。Tekton 本身是 Kubernetes 原生的編排系統。所以可以直接使用 Kubernetes 的 ServiceAccount 機制實現鑑權。
實例如下:

  • 定義一個保存鏡像倉庫鑑權信息的 secret
apiVersion: v1
kind: Secret
metadata:
  name: ack-cr-push-secret
  annotations:
    tekton.dev/docker-0: https://registry.cn-hangzhou.aliyuncs.com
type: kubernetes.io/basic-auth
stringData:
  username: <cleartext non-encoded>
  password: <cleartext non-encoded>
  • 定義 ServiceAccount ,並且使用上面的 secret
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pipeline-account
secrets:
- name: ack-cr-push-secret
  • PipelineRun 中引用 ServiceAccount
apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  generateName: tekton-kn-sample-
spec:
  pipelineRef:
    name: build-and-deploy-pipeline
... ...
  serviceAccount: pipeline-account

Hello World

https://github.com/knative-sample/tekton-knative 這是一個完整的 Tekton 的 Hello World。下面我們一起體驗一下這個 Hello World。

在開始實戰之前你需要有一個 Kubernetes 集羣,並還需要安裝 Knative 和 Tekton。tekton-knative 中的 release-v0.5.2.yaml 直接提交到 Kubernetes 集羣即可完成 Tekton 的安裝。下面我們開始體驗使用 Tekton 從源碼到構建再到部署的自動化過程。

clone 代碼

clone 代碼到本地。

git clone https://github.com/knative-sample/tekton-knative

##創建 PipelineResource
主要內容在 resources/picalc-git.yaml 文件中。如下所示主要是把 https://github.com/knative-sample/tekton-knative 保存在 resource 中給其他資源使用。

apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: tekton-knative-git
spec:
  type: git
  params:
    - name: revision
      value: master
    - name: url
      value: https://github.com/knative-sample/tekton-knative

創建 task
創建 task,這個例子中我們創建兩個 task:source-to-image 和 deploy-using-kubectl

  • source-to-image

    主要內容在 tasks/source-to-image.yaml 文件中。此 task 的主要功能是把源代碼編譯成鏡像。

    主要是使用 kaniko 實現容器內編譯 Docker 鏡像的能力。此 Task 的參數主要是設置編譯上下文的一些信息,比如:Dockerfile、ContextPath 以及目標鏡像 tag 等。
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: source-to-image
spec:
  inputs:
    resources:
      - name: git-source
        type: git
    params:
      - name: pathToContext
        description: The path to the build context, used by Kaniko - within the workspace
        default: .
      - name: pathToDockerFile
        description: The path to the dockerfile to build (relative to the context)
        default: Dockerfile
      - name: imageUrl
        description: Url of image repository
      - name: imageTag
        description: Tag to apply to the built image
        default: "latest"
  steps:
    - name: build-and-push
      image: registry.cn-hangzhou.aliyuncs.com/knative-sample/kaniko-project-executor:v0.10.0
      command:
        - /kaniko/executor
      args:
        - --dockerfile=${inputs.params.pathToDockerFile}
        - --destination=${inputs.params.imageUrl}:${inputs.params.imageTag}
        - --context=/workspace/git-source/${inputs.params.pathToContext}
      env:
      - name: DOCKER_CONFIG
        value: /builder/home/.docker
  • deploy-using-kubectl

    主要內容在 tasks/deploy-using-kubectl.yaml 文件中。

    如下所示這個 Task 主要的作用是通過參數獲取到目標鏡像的信息,然後執行一條 sed 命令把 Knative Service yaml 中的 __IMAGE__ 替換成目標鏡像。再通過 kubectl 發佈到 Kubernetes 中。
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: deploy-using-kubectl
spec:
  inputs:
    resources:
      - name: git-source
        type: git
    params:
      - name: pathToYamlFile
        description: The path to the yaml file to deploy within the git source
      - name: imageUrl
        description: Url of image repository
      - name: imageTag
        description: Tag of the images to be used.
        default: "latest"
  steps:
    - name: update-yaml
      image: alpine
      command: ["sed"]
      args:
        - "-i"
        - "-e"
        - "s;__IMAGE__;${inputs.params.imageUrl}:${inputs.params.imageTag};g"
        - "/workspace/git-source/${inputs.params.pathToYamlFile}"
    - name: run-kubectl
      image: registry.cn-hangzhou.aliyuncs.com/knative-sample/kubectl:v0.5.0
      command: ["kubectl"]
      args:
        - "apply"
        - "-f"
        - "/workspace/git-source/${inputs.params.pathToYamlFile}"

定義 Pipeline

我們已經有兩個 Task 了,現在我們就用一個 PIpeline 來編排這兩個 Task:

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: build-and-deploy-pipeline
spec:
  resources:
    - name: git-source
      type: git
  params:
    - name: pathToContext
      description: The path to the build context, used by Kaniko - within the workspace
      default: src
    - name: pathToYamlFile
      description: The path to the yaml file to deploy within the git source
    - name: imageUrl
      description: Url of image repository
    - name: imageTag
      description: Tag to apply to the built image
  tasks:
  - name: source-to-image
    taskRef:
      name: source-to-image
    params:
      - name: pathToContext
        value: "${params.pathToContext}"
      - name: imageUrl
        value: "${params.imageUrl}"
      - name: imageTag
        value: "${params.imageTag}"
    resources:
      inputs:
        - name: git-source
          resource: git-source
  - name: deploy-to-cluster
    taskRef:
      name: deploy-using-kubectl
    runAfter:
      - source-to-image
    params:
      - name: pathToYamlFile
        value:  "${params.pathToYamlFile}"
      - name: imageUrl
        value: "${params.imageUrl}"
      - name: imageTag
        value: "${params.imageTag}"
    resources:
      inputs:
        - name: git-source
          resource: git-source

鑑權信息

如下所示,定義一個 Secret 和 ServiceAccount。並且給 ServiceAccount 綁定執行 Knative Service 的權限。

首先創建一個 Secret 保存鏡像倉庫的鑑權信息,如下所示:

  • tekton.dev/docker-0 換成你要推送的鏡像倉庫的地址;
  • username 換成鏡像倉庫鑑權的用戶名;
  • password 環境鏡像倉庫鑑權的密碼。
apiVersion: v1
kind: Secret
metadata:
  name: ack-cr-push-secret
  annotations:
    tekton.dev/docker-0: https://registry.cn-hangzhou.aliyuncs.com
type: kubernetes.io/basic-auth
stringData:
  username: <cleartext non-encoded>
  password: <cleartext non-encoded>

下面這些信息保存到文件中,然後使用 kubectl apply -f 指令提交到 Kubernetes。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pipeline-account
secrets:
- name: ack-cr-push-secret

---

apiVersion: v1
kind: Secret
metadata:
  name: kube-api-secret
  annotations:
    kubernetes.io/service-account.name: pipeline-account
type: kubernetes.io/service-account-token

---

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pipeline-role
rules:
- apiGroups: ["serving.knative.dev"]
  resources: ["services"]
  verbs: ["get", "create", "update", "patch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pipeline-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pipeline-role
subjects:
- kind: ServiceAccount
  name: pipeline-account

定義 PIpelineRun

ServiceAccount 對應的鑑權信息是通過和 PIpelineRun 綁定的方式執行的。參見 run/picalc-pipeline-run.yaml 文件。

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  generateName: tekton-kn-sample-
spec:
  pipelineRef:
    name: build-and-deploy-pipeline
  resources:
    - name: git-source
      resourceRef:
        name: tekton-knative-git
  params:
    - name: pathToContext
      value: "src"
    - name: pathToYamlFile
      value: "knative/helloworld-go.yaml"
    - name: imageUrl
      value: "registry.cn-hangzhou.aliyuncs.com/knative-sample/tekton-knative-helloworld"
    - name: imageTag
      value: "1.0"
  trigger:
    type: manual
  serviceAccount: pipeline-account

執行 HelloWorld

準備 PIpeline 的資源。

kubectl apply -f tasks/source-to-image.yaml -f tasks/deploy-using-kubectl.yaml  -f resources/picalc-git.yaml -f image-secret.yaml -f pipeline-account.yaml -f pipeline/build-and-deploy-pipeline.yaml

執行 create 把 pipelieRun 提交到 Kubernetes 集羣。之所以這裏使用 create 而不是使用 apply 是因爲 PIpelineRun 每次都會創建一個新的,kubectl 的 create 指令會基於 generateName 創建新的 PIpelineRun 資源。

kubectl create -f run/picalc-pipeline-run.yaml

查看一下 pod 信息可能是下面這樣:

└─# kubectl get pod
NAME                                                        READY   STATUS      RESTARTS   AGE
tekton-kn-sample-45d84-deploy-to-cluster-wfrzx-pod-f093ef   0/3     Completed   0          8h
tekton-kn-sample-45d84-source-to-image-7zpqn-pod-c2d20c     0/2     Completed   0          8h

相關文章:

《初識 Knative:跨平臺的 Serverless 編排框架》
《Knative 初體驗:Serving Hello World》
《Knative 初體驗:Eventing Hello World》
《Knative 初體驗:Build Hello World》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章