OpenShift Pipeline 是一種云原生,持續(xù)集成和交付(CI/CD)解決方案,使用Tekton構(gòu)建pipeline。
實(shí)現(xiàn)了以模塊化方式從源碼到應(yīng)用運(yùn)行態(tài)的自動(dòng)化流程, 源碼->制品->容器鏡像->應(yīng)用發(fā)布。并可自定義穿插其他模塊,如代碼掃描、鏡像安全、消息推送等。
1. 模塊介紹
OpenShift Pipeline 通過(guò)自定義資源對(duì)象(CRD)以模塊化的方式構(gòu)建pipeline。
主要使用的 CRD 有 task, pipeline, pipelinerun, taskrun,trigger

Task:
task 是在 Pipeline 中可配置的最小單元。作為 pipeline 的一部分也可獨(dú)立運(yùn)行。每個(gè)還可定義多個(gè) step,順序執(zhí)行。 比如 buildah 這個(gè) task 就有 build,push, digest-to-results 三個(gè) step。
task內(nèi)容主要由 image 和運(yùn)行腳本組成。spec.params.xx 的值由 pipeline 傳入
task 通常會(huì)設(shè)計(jì)為可重復(fù)調(diào)用。
示例
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: update-deployment
spec:
params:
- name: deployment
description: The name of the deployment patch the image
type: string
- name: IMAGE
description: Location of image to be patched with
type: string
steps:
- name: patch
image: image-registry.openshift-image-registry.svc:5000/openshift/cli:latest
command: ["/bin/bash", "-c"]
args:
- |-
oc patch deployment $(inputs.params.deployment) --patch='{"spec":{"template":{"spec":{
"containers":[{
"name": "$(inputs.params.deployment)",
"image":"$(inputs.params.IMAGE)"
}]
}}}}'
piepeline:
Pipeline 由一系列 task 組成的通用工作流模板,并會(huì)定義 task 的執(zhí)行順序。
PipelineRun:
PipelineRun 是一個(gè) Pipeline 的運(yùn)行實(shí)例。PipelineRun 啟動(dòng) Pipeline,并為 Pipeline 中執(zhí)行的每個(gè)任務(wù)管理一個(gè) TaskRun 的創(chuàng)建。
TaskRun:
PipelineRun 由 Pipeline 中每個(gè)任務(wù)的 PipelineRun 自動(dòng)創(chuàng)建。它是在 Pipeline 中運(yùn)行任務(wù)實(shí)例的結(jié)果。如果某個(gè)任務(wù)在 Pipeline 之外運(yùn)行,它也可以被手工創(chuàng)建。
Workspace:
Workspace 是一個(gè)存儲(chǔ)卷,任務(wù)(Task)在運(yùn)行時(shí)需要它來(lái)接收輸入或提供輸出。Task 或 Pipeline 會(huì)聲明 Workspace,一個(gè)TaskRun 或 PipelineRun 則會(huì)提供存儲(chǔ)卷的實(shí)際位置,存儲(chǔ)卷被掛載到聲明的 Workspace 上。這使得任務(wù)具有靈活性、可重復(fù)使用,并允許在多個(gè)任務(wù)間共享工作區(qū)。
多個(gè) pipelinerun 共享存儲(chǔ)的時(shí)候需要注意,有的 task 初始化時(shí)候會(huì)清除之前的數(shù)據(jù),多個(gè) pipelinerun 同時(shí)運(yùn)行并共用存儲(chǔ)可能存在數(shù)據(jù)被清除的情況。
Trigger:
Trigger(觸發(fā)器)捕獲外部事件,如 Git 拉取請(qǐng)求,并處理事件有效負(fù)載以獲取關(guān)鍵信息。
2. 安裝 Red Hat OpenShift Pipelines Operator
如果離線環(huán)境,需要先執(zhí)行離線部署operatorhub
https://github.com/cai11745/ocp4-userguide 可參照《離線部署operatorhub并批量導(dǎo)入》
- 在控制臺(tái)的 Administrator 視角中,Operators → OperatorHub。
- 搜索 Red Hat OpenShift Pipelines Operator。點(diǎn) Red Hat OpenShift Pipelines Operator 。
- 在 Install Operator 頁(yè)面中:
Installation Mode 選擇 All namespaces on the cluster (default)。選擇該項(xiàng)會(huì)將 Operator 安裝至默認(rèn)openshift-operators 命名空間,這將啟用 Operator 以進(jìn)行監(jiān)視并在集群中的所有命名空間中可用。
Approval Strategy(批準(zhǔn)策略)選擇 Automatic。這樣可確保以后對(duì) Operator 的升級(jí)由 Operator Lifecycle Manager (OLM) 自動(dòng)進(jìn)行。
Update Channel:Stable 頻道啟用 Red Hat OpenShift Pipelines Operator 最新穩(wěn)定版本的安裝。preview 頻道啟用 Red Hat OpenShift Pipelines Operator 的最新預(yù)覽版本,該版本可能包含 Stable 頻道中還未提供的功能。
點(diǎn)擊 Install。會(huì)看到 Installed Operators 頁(yè)面中列出的 Operator。
檢查 Status 變成 Succeeded 表示 Red Hat OpenShift Pipelines Operator 已安裝成功。
查看相關(guān)api
[root@bastion ~]# oc api-resources --api-group=tekton.dev
NAME SHORTNAMES APIVERSION NAMESPACED KIND
clustertasks tekton.dev/v1beta1 false ClusterTask
conditions tekton.dev/v1alpha1 true Condition
pipelineresources tekton.dev/v1alpha1 true PipelineResource
pipelineruns pr,prs tekton.dev/v1beta1 true PipelineRun
pipelines tekton.dev/v1beta1 true Pipeline
runs tekton.dev/v1alpha1 true Run
taskruns tr,trs tekton.dev/v1beta1 true TaskRun
tasks tekton.dev/v1beta1 true Task
相關(guān)pod
[root@bastion ~]# oc get pod -n openshift-pipelines
NAME READY STATUS RESTARTS AGE
tekton-operator-proxy-webhook-5c86d47c54-kpcvx 1/1 Running 0 6h42m
tekton-pipelines-controller-78f7f7449d-wrcvb 1/1 Running 0 6h42m
tekton-pipelines-webhook-7885bc985b-54pc5 1/1 Running 0 7h10m
tekton-triggers-controller-76c8d6bd-kwgrk 1/1 Running 0 7h10m
tekton-triggers-webhook-6d6cfb6568-gl779 1/1 Running 0 7h10m
3. 場(chǎng)景示例
使用 Red Hat OpenShift Pipelines,創(chuàng)建一個(gè)自定義的 CI/CD 解決方案來(lái)構(gòu)建、測(cè)試和部署應(yīng)用程序。
主要以下流程:
- 創(chuàng)建自定義task,或使用現(xiàn)有的可重復(fù)使用的task。
- 為應(yīng)用程序創(chuàng)建并定義pipeline。
- 使用持久化存儲(chǔ)添加到pipeline的workspace,以保存中間數(shù)據(jù),如代碼、制品。
- 創(chuàng)建一個(gè) PipelineRun 對(duì)象來(lái)實(shí)例化并調(diào)用pipeline。
- 添加tigger以捕獲源倉(cāng)庫(kù)中的事件。(本文不包含,下一篇做)
使用redhat 官網(wǎng)提供的示例, pipelines-tutorial 來(lái)演示。這個(gè)示例使用一個(gè)簡(jiǎn)單的應(yīng)用程序,它由以下部分組成:
一個(gè)前端界面 vote-ui,它的源代碼在 ui-repo Git
一個(gè)后端接口 vote-api,它的源代碼在 api-repo Git
apply-manifests 和 update-deployment 任務(wù)在 pipelines-tutorial Git
3.1 創(chuàng)建新的project
Pipelines Operator 會(huì)自動(dòng)添加并配置一個(gè)名為 pipeline 的 ServiceAccount,它有足夠的權(quán)限來(lái)構(gòu)建和推送鏡像。這個(gè) ServiceAccount 由 PipelineRun 使用。
oc new-project pipelines-tutorial
oc get serviceaccount pipeline
3.2 創(chuàng)建 task
安裝 tekton client 命令 tkn
# 下載地址
https://mirror.openshift.com/pub/openshift-v4/clients/pipeline/
wget https://mirror.openshift.com/pub/openshift-v4/clients/pipeline/0.13.1/tkn-linux-amd64-0.13.1.tar.gz
chmod +x tkn
mv tkn /usr/local/bin/
tkn version
# Client version: 0.13.1
# Pipeline version: v0.19.0
# Triggers version: v0.10.2
從 pipelines-tutorial git庫(kù)安裝 apply-manifests 和 update-deployment 任務(wù)資源,其中包含可為管道重復(fù)使用的任務(wù)列表:
oc create -f https://raw.githubusercontent.com/openshift/pipelines-tutorial/pipelines-1.3/01_pipeline/01_apply_manifest_task.yaml
oc create -f https://raw.githubusercontent.com/openshift/pipelines-tutorial/pipelines-1.3/01_pipeline/02_update_deployment_task.yaml
使用 oc get task 或者 tkn task list 命令列出創(chuàng)建的任務(wù):
[root@bastion 01_pipeline]# oc get task
NAME AGE
apply-manifests 22s
update-deployment 17s
[root@bastion 01_pipeline]# tkn task list
NAME DESCRIPTION AGE
apply-manifests 5 minutes ago
update-deployment 5 minutes ago
輸出會(huì)確認(rèn)創(chuàng)建了 apply-manifests 和 update-deployment 任務(wù)
使用 tkn clustertasks list 命令列出由 Operator 安裝的額外集群任務(wù),如 buildah 和 s2i-python-3
[root@bastion 01_pipeline]# tkn clustertasks list
NAME DESCRIPTION AGE
buildah Buildah task builds... 1 day ago
buildah-pr Buildah task builds... 1 day ago
buildah-pr-v0-19-0 Buildah task builds... 1 day ago
buildah-v0-19-0 Buildah task builds... 1 day ago
git-cli This task can be us... 8 hours ago
git-clone These Tasks are Git... 1 day ago
......
注意: 在內(nèi)網(wǎng)環(huán)境使用 buildah 集群任務(wù),您必須確保 Dockerfile 使用內(nèi)部鏡像流作為基礎(chǔ)鏡像。
創(chuàng)建存儲(chǔ),必須。
因?yàn)槊總€(gè) task 都是通過(guò)pod 執(zhí)行腳本,pod任務(wù)完成后的輸出物需要通過(guò)存儲(chǔ)流轉(zhuǎn)到下一階段,比如第一步拉取的代碼,第二步需要編譯,第三步需要做代碼掃描。
~ oc create -f https://raw.githubusercontent.com/openshift/pipelines-tutorial/pipelines-1.3/01_pipeline/03_persistent_volume_claim.yaml
~ oc get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
source-pvc Bound pvc-7c82cb22-65f1-47fb-9ed0-9c4ca5c4f992 500Mi RWO managed-nfs-storage 29s
3.3 組裝 pipeline
pipeline 由多個(gè) task 組成,設(shè)計(jì)成可以在多個(gè)場(chǎng)景下進(jìn)行復(fù)用。
Pipeline 通過(guò)使用 from 和 runAfter 參數(shù)來(lái)指定在不同任務(wù)間如何進(jìn)行交互以及它們執(zhí)行的順序。它使用 workspaces 字段指定 Pipeline 中每個(gè)任務(wù)在執(zhí)行過(guò)程中所需的一個(gè)或多個(gè)卷。
導(dǎo)入示例 pipeline,此 pipeline 一共有4個(gè)階段,是fetch-repository, build-image, apply-manifests, update-deployment,分別對(duì)應(yīng)4個(gè) task: git-clone(ClusterTask),buildah(ClusterTask),apply-manifests,update-deployment。 前兩個(gè)task 是 operator 自帶的,全局屬性,后兩個(gè)task是我們剛剛創(chuàng)建的,只在當(dāng)前 project 生效。
oc create -f https://raw.githubusercontent.com/openshift/pipelines-tutorial/pipelines-1.3/01_pipeline/04_pipeline.yaml
# 內(nèi)容解讀
[root@bastion 01_pipeline]# cat 04_pipeline.yaml
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: build-and-deploy
spec:
workspaces:
- name: shared-workspace
params:
- name: deployment-name #與下文tasks 中的params.value 對(duì)應(yīng),
#此處將來(lái)可輸入?yún)?shù),回填到tasks.params.value
#如果通過(guò)web console 運(yùn)行,params的內(nèi)容能可視化輸入與展示,類似 openshift Template
type: string
description: name of the deployment to be patched
- name: git-url
type: string
description: url of the git repo for the code of deployment
- name: git-revision
type: string
description: revision to be used from repo of the code for deployment
default: "pipelines-1.3"
- name: IMAGE
type: string
description: image to be build from the code
tasks: #tasks.name 有幾個(gè)就代表有幾個(gè)步驟,此name為自定義
- name: fetch-repository
taskRef:
name: git-clone #指定使用的task,此處使用了ClusterTask
kind: ClusterTask
workspaces:
- name: output #與clustertask git-clone 中spec.workspace.name 一致
workspace: shared-workspace #與此yaml文件 spec.workspace.name 一致
params:
- name: url #這個(gè)name 與 ClusterTask git-clone 中的 spec.params.name 一致,
#將來(lái)會(huì)把下面的value 回填到 ClusterTask 中進(jìn)行執(zhí)行
value: $(params.git-url) #與此yaml spec.params.name
- name: subdirectory
value: ""
- name: deleteExisting
value: "true"
- name: revision
value: $(params.git-revision)
- name: build-image
taskRef:
name: buildah
kind: ClusterTask
params:
- name: TLSVERIFY
value: "false"
- name: IMAGE
value: $(params.IMAGE)
workspaces:
- name: source
workspace: shared-workspace
runAfter: # 啟動(dòng)順序
- fetch-repository
- name: apply-manifests
taskRef:
name: apply-manifests #指定使用的task,沒(méi)寫(xiě)ClusterTask就說(shuō)明是當(dāng)前project的task
workspaces:
- name: source
workspace: shared-workspace
runAfter:
- build-image
- name: update-deployment
taskRef:
name: update-deployment
params:
- name: deployment
value: $(params.deployment-name)
- name: IMAGE
value: $(params.IMAGE)
runAfter:
- apply-manifests
Pipeline - spec.params.name 自定義,此name 輸入的 value 將傳輸?shù)?Pipeline - spec.tasks.params.value
Pipeline - spec.tasks.params.name 與 ClusterTask(Task)中 spec.params.name 一致,Pipeline - spec.tasks.params.value 內(nèi)容傳輸?shù)?ClusterTask(Task) 中spec.params.name 的 value。
此處是順序比較簡(jiǎn)單,4個(gè) task 一個(gè)接一個(gè)執(zhí)行。
在 Web console - Pipelines 菜單可以可視化的查看與執(zhí)行 pipeline。
可視化菜單功能為 Tech preview,stable 版本還看不到。

3.4 執(zhí)行 pipeline
上面是組裝了一個(gè) pipeline,包含了4個(gè)步驟,包括 clone代碼-制作精細(xì)-發(fā)布應(yīng)用,但是使用的代碼庫(kù)地址,應(yīng)用名稱還未定義,需要在執(zhí)行 pipeline 時(shí)候自定義。
在 pipeline 詳情頁(yè),點(diǎn) Action - Start,會(huì)彈出輸入?yún)?shù)頁(yè)面,此處展示的內(nèi)容就是 04_pipeline.yaml 中 spec.params 部分。
deployment-name: 輸入發(fā)布應(yīng)用的名稱,自定義
git-url: git 代碼庫(kù)的地址 https://github.com/openshift/pipelines-vote-api.git
git-version: 分支名稱
IMAGE: 制作鏡像使用的名稱,image-registry.openshift-image-registry.svc:5000/pipelines-tutorial/vote-api 依次是內(nèi)部倉(cāng)庫(kù)地址,project-name,deployment-name
shared-workspace: 選擇上面創(chuàng)建的 source-pvc

pipeline 執(zhí)行過(guò)程,每個(gè) task 都會(huì)通過(guò) image 運(yùn)行 pod 來(lái)執(zhí)行,如果異??梢酝ㄟ^(guò)頁(yè)面或者命令查看 taskrun 狀態(tài)或者查看在運(yùn)行pod的event 與log
第二步的日志,根據(jù) git庫(kù)目錄下的 Dockerfile 制作鏡像,并推送到內(nèi)部倉(cāng)庫(kù)

第三步的日志,導(dǎo)入 git庫(kù) k8s目錄的 deployment.yaml 和 service.yaml

第四步,把 deployment 的 image, 更新成第二步生成的image
除了通過(guò)頁(yè)面,也可以通過(guò) tkn 命令執(zhí)行 pipeline ,會(huì)提示依次輸入內(nèi)容
[root@bastion 01_pipeline]# tkn pipeline list
NAME AGE LAST RUN STARTED DURATION STATUS
build-and-deploy 51 minutes ago build-and-deploy-54nl08 12 minutes ago --- Running
[root@bastion 01_pipeline]# tkn pipeline start build-and-deploy
? Value for param `deployment-name` of type `string`?
我這是在線環(huán)境,離線環(huán)境會(huì)遇到鏡像拉取的問(wèn)題,參照官網(wǎng)。
https://access.redhat.com/documentation/zh-cn/openshift_container_platform/4.7/html/cicd/creating-applications-with-cicd-pipelines#op-mirroring-images-to-run-pipelines-in-restricted-environment_creating-applications-with-cicd-pipelines
過(guò)程中可以通過(guò) oc get 及 tkn taskrun list 等查看狀態(tài)。
[root@bastion 01_pipeline]# oc get pipelineruns.tekton.dev
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
build-and-deploy-extr7w Unknown Running 3m12s
[root@bastion 01_pipeline]# oc get taskruns.tekton.dev
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
build-and-deploy-extr7w-build-image-vr96v Unknown Running 61s
build-and-deploy-extr7w-fetch-repository-7kpxj True Succeeded 3m19s 61s
[root@bastion 01_pipeline]# oc get pod
NAME READY STATUS RESTARTS AGE
build-and-deploy-extr7w-build-image-vr96v-pod-hljx8 3/3 Running 0 63s
build-and-deploy-extr7w-fetch-repository-7kpxj-pod-dbjsh 0/1 Completed 0 3m21s
完成后,vote-api 后端服務(wù)發(fā)布完成
[root@bastion 01_pipeline]# oc get pod
NAME READY STATUS RESTARTS AGE
build-and-deploy-47rwhl-apply-manifests-z9mv6-pod-sq5rg 0/1 Completed 0 8m39s
build-and-deploy-47rwhl-build-image-h8kbl-pod-ztwc2 0/3 Completed 0 11m
build-and-deploy-47rwhl-fetch-repository-c5gjx-pod-f95w8 0/1 Completed 0 11m
build-and-deploy-47rwhl-update-deployment-ztzm5-pod-zm4vl 0/1 Completed 0 7m31s
vote-api-c458c6d4f-52xm2 1/1 Running 0 7m26s
[root@bastion 01_pipeline]# tkn taskrun list
NAME STARTED DURATION STATUS
build-and-deploy-47rwhl-update-deployment-ztzm5 13 minutes ago 4 seconds Succeeded
build-and-deploy-47rwhl-apply-manifests-z9mv6 14 minutes ago 1 minute Succeeded
build-and-deploy-47rwhl-build-image-h8kbl 16 minutes ago 2 minutes Succeeded
build-and-deploy-47rwhl-fetch-repository-c5gjx 17 minutes ago 13 seconds Succeeded
接著按照同樣方法發(fā)布前端 vote-ui ,這次用 tkn 命令發(fā)布
tkn pipeline start build-and-deploy \
-w name=shared-workspace,volumeClaimTemplateFile=https://raw.githubusercontent.com/openshift/pipelines-tutorial/pipelines-1.3/01_pipeline/03_persistent_volume_claim.yaml \
-p deployment-name=vote-ui \
-p git-url=https://github.com/openshift-pipelines/vote-ui.git \
-p IMAGE=image-registry.openshift-image-registry.svc:5000/pipelines-tutorial/vote-ui
volumeClaimTemplateFile 參數(shù)會(huì)創(chuàng)建一個(gè)隨意名稱的pvc,和后端使用的不同,如果圖形界面去 start vote-ui pipeline,也要提前手動(dòng)創(chuàng)建不同的pvc。
查看前端域名,訪問(wèn)測(cè)試
[root@bastion 01_pipeline]# oc get route vote-ui --template='http://{{.spec.host}}'
http://vote-ui-pipelines-tutorial.apps.ocp4.example.com

其他 tkn 命令
# 查看已運(yùn)行的 pipeline
[root@bastion 01_pipeline]# tkn pipelinerun list
NAME STARTED DURATION STATUS
build-and-deploy-run-56kzg 15 minutes ago 5 minutes Succeeded
build-and-deploy-47rwhl 5 hours ago 4 minutes Succeeded
# 持續(xù)跟蹤運(yùn)行日志
[root@bastion 01_pipeline]# tkn pipelinerun logs build-and-deploy-run-56kzg -f
# 將最后運(yùn)行的pipelinerun 再運(yùn)行一次
tkn pipeline start build-and-deploy --last
也可以通過(guò)頁(yè)面,對(duì) pipelinerun 選擇 Action -> rerun,再次運(yùn)行。
總結(jié)
1.通過(guò) operator 自帶的 clustertask及自編task 組成 pipeline 模板,將常用參數(shù)提取為輸入項(xiàng)。pipeline配合輸入?yún)?shù)形成 pipelinerun 執(zhí)行流水線工作。
每個(gè)task類似jenkins的stage。
2.每個(gè)task 都會(huì)用到獨(dú)立的鏡像,在離線環(huán)境需要提前準(zhǔn)備好鏡像,或通過(guò) image mirror 方式。
3.demo中應(yīng)用發(fā)布所使用到的yaml,存放在了git,便于管理。其實(shí)也可以通過(guò) task 傳遞,可視化效果更好一些,就是參數(shù)會(huì)略顯繁雜。
4.當(dāng)前在頁(yè)面通過(guò)start pipeline時(shí)候,pipelinerun的名稱不能自定義,不利于區(qū)分pipelinerun屬于哪個(gè)應(yīng)用。
4. FAQ
4.1 task build-image 在 STEP-BUILD 失敗,workspace目錄找不到代碼
啟動(dòng)pipeline 的時(shí)候,在Workspace->shared-workspace 沒(méi)有指定存儲(chǔ)。
需要指定已有pvc存儲(chǔ),因?yàn)槊總€(gè)task都是獨(dú)立的pod。第一步拉取的代碼的pod完成后,在第二步 build-image 的pod時(shí)候無(wú)法獲取到。需要通過(guò)存儲(chǔ)流轉(zhuǎn)。
4.2 task build-image 在 STEP-PUSH fail,denied: requested access to the resource is denied
step-push
+ buildah --storage-driver=vfs push --tls-verify=false --digestfile /workspace/source/image-digest vote-api docker://vote-api
Getting image source signatures
Getting image source signatures
Getting image source signatures
Getting image source signatures
error copying layers and metadata from "containers-storage:[vfs@/var/lib/containers/storage+/var/run/containers/storage]localhost/vote-api:latest" to "docker://vote-api:latest": Error trying to reuse blob sha256:bd3ef8fb78ac28071075811b988706f81ea7f2be36c875592e87287921209862 at destination: Error checking whether a blob sha256:bd3ef8fb78ac28071075811b988706f81ea7f2be36c875592e87287921209862 exists in docker.io/library/vote-api: errors:
denied: requested access to the resource is denied
error parsing HTTP 401 response body: unexpected end of JSON input: ""
level=error msg="exit status 125"
step-digest-to-results
2021/04/14 06:00:23 Skipping step because a previous step failed
這是啟動(dòng) pipeline 時(shí)候 IMAGE name 寫(xiě)的不對(duì),如果IMAGE 只寫(xiě) vote-api 就會(huì)出現(xiàn)上面的鏡像,鏡像就會(huì)默認(rèn)推送到docker.io 當(dāng)然會(huì)沒(méi)有權(quán)限。
把IMAGE 寫(xiě)完整即可 image-registry.openshift-image-registry.svc:5000/pipelines-tutorial/vote-api
5. 參考鏈接
https://blog.csdn.net/weixin_43902588/article/details/103269747