Argo介紹
Kubeflow 作為一個 Deep Learning service on Kubernetes 的專案,自然面對最大的問題就是如何將一個 DL 中的每一個 phase 串在一起。而眾多 workflow 工具中, Kubeflow 在這邊選擇使用的便是 - Argo
。 Kubeflow 不只將 Argo 應用在 pipeline,也應用在它內部的CI/CD上,因此值得我們好好關注。
Argo 是一個基於 CRD 實作的一個 Workflow 工具,協助使用者管理與控制一系列任務的執行,
同時提供一個簡潔的UI介面觀看每一個任務的執行狀況、順序、結果與 log。
由於 Workflow 本身是一個 CRD,因此建立 workflow 的方法也是透過撰寫一個 yaml 檔,而 Argo 也針對如何描述一個 workflow 提供了許多的規則。
部署Argo
我們這邊是獨立部署,如果是直接安裝Kubeflow,以下這些components已經安裝完畢,只需另外安裝argo client即可。
首先下載安裝Argo client
Mac:1
brew install argoproj/tap/argo
Linux:
1
2curl -sSL -o /usr/local/bin/argo https://github.com/argoproj/argo/releases/download/v2.2.1/argo-linux-amd64
chmod +x /usr/local/bin/argo接下來安裝Argo Controller 與 UI
1
2kubectl create ns argo
kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo/v2.2.1/manifests/install.yamlNOTE: 因為上面的insall.yaml會需要在你的k8s中創建clusterrole。因此如果使用的是GKE,這邊需要特別開通權限。
1
kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=cluster-admin --user=YOUREMAIL@gmail.com
安裝好後就會在k8s下面的argo namespace看到以下的components
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/argo-ui 1 1 1 1 84d
deploy/workflow-controller 1 1 1 1 84d
NAME DESIRED CURRENT READY AGE
rs/argo-ui-65bb8cf7f6 1 1 1 35s
rs/argo-ui-6bb9c4485f 0 0 0 84d
rs/workflow-controller-7f4dd6bd9 0 0 0 84d
rs/workflow-controller-8fb5fb5d5 1 1 1 33s
NAME READY STATUS RESTARTS AGE
po/argo-ui-65bb8cf7f6-q2r59 1/1 Running 0 35s
po/argo-ui-6bb9c4485f-7v2d5 1/1 Terminating 0 42d
po/workflow-controller-8fb5fb5d5-spq99 1/1 Running 0 33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/argo-ui ClusterIP 10.27.255.240 <none> 80/TCP 84d在接下來使用 Argo 的過程中,default account 的權限會限制一些功能,因此我們這邊在 default account 綁上 admin privileges。
1
kubectl create rolebinding default-admin --clusterrole=admin --serviceaccount=default:default
也可以在執行的 workflow 時指定使用的是哪一個 service account
1
argo submit --serviceaccount <name>
以上即完成 Argo 的部署。
使用Argo UI
Argo UI 可以讓使用者輕鬆關觀察一個 workflow 的狀況,並檢查每一個步驟的結果與錯誤訊息。
kubectl port-forward1
kubectl -n argo port-forward deployment/argo-ui 8001:8001
透過 http://127.0.0.1:8001 使用
Method 2: kubectl proxy1
kubectl proxy
透過 http://127.0.0.1:8001/api/v1/namespaces/argo/services/argo-ui/proxy/ 使用
Expose a LoadBalancer1
2
3
4
5kubectl patch svc argo-ui -n argo -p '{"spec": {"type": "LoadBalancer"}}'
kubectl get svc argo-ui -n argo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argo-ui LoadBalancer 10.19.255.205 35.197.49.167 80:30999/TCP 1m
結果如下圖:
Argo 範例與解析
如同上面所說,Argo 也是透過自己實作一個 operator(CRD + controller) 來完成 Workflow 的功能。而所謂的在 k8s 中執行 workflow 的意思便是利用一個個 pod 來執行我們的每一個步驟。
因此我們這邊先來看幾個簡單的 argo crd,看看我們能設定哪些參數及能做到哪些事情。
首先提供一些常用的指令:1
2
3argo list #查看有哪些 workflow
argo get xxx-workflow-name-xxx #查看這個 workflow 的狀態
argo logs xxx-pod-name-xxx #查看這個 pod 的 output
coinflip
這個範例的目標是,先丟一個硬幣,如果是 head 就執行 head 的工作,如果是 tail 就執行 tail 的工作。也就是 workflow 最基礎的 if-else 功能。
首先先利用以下指令來執行coinflip worklow:1
argo submit --watch https://raw.githubusercontent.com/argoproj/argo/master/examples/coinflip.yaml
接著我們來分析中間發生了哪些事:
1 | Name: coinflip-czw7h |
這是你會看到的介面。上面呈現了一些基本的訊息,以及這個 workflow 每一個 steps 發生的事情與執行了哪個相對應得 pod。
因此問題便是,我們如何讓每一個 pod 知道上一步驟的結果,與如何傳遞結果給下一個步驟。
我們現在來細看這個coinflips到底怎麼做的,以下是他的yaml file:
1 | apiVersion: argoproj.io/v1alpha1 |
從上面可以很簡單知道:
apiVersion: argoproj.io/v1alpha1
與kind: Workflow
說明了這是一個CRDspec
從entrypoing
開始執行,在這邊即是從coinflip
這個template
開始templates
裡面的每一項描述的都是一個工作,包含- 名字
- 可以執行一個
container
或是執行script
- container
image
command
與args
steps
: 作用是排定一系列templates
執行的先後順序
- coinflip 同時作為一個
entrypoint
,特別可以看到他裡面描述的是steps
,且包含:- 每一步驟的名字
- 要執行的
template
- 什麼時候執行
將上面的 yaml 轉成 json 可以視為[[flip-coin], [heads, tails]],因此會先執行 flip-coin。而 flip-coin 透過執行的 script
會有一個 result 作為 output,表示擲出硬幣的結果。
而下面的步驟透過 NaN
來獲得特定步驟的 output 作為判斷的依據,進而可以達成 if-else 的workflow效果 。
Ref: 可另外參考 coinflip-recursive
dag-diamond
在一個 workflow 中除了 if-else
外,有時也需要能夠表達工作之間的相依性,或是有時一些工作需要可以平行執行。而 Argo 便提供 dag
來描述工作的相依性,直接看範例:
1 | apiVersion: argoproj.io/v1alpha1 |
可以注意到這邊沒有使用steps
,而是使用dag
。在dag
中的每一項步驟皆可以使用dependencies
來描述相依的工作,比方說 B,C 步驟便強迫要在 A 完成後才能執行。而當 A 完成後,B,C 滿足條件便會同時(平行)執行,最後才交由 D 執行。
透過 dag
便可以編排出工作的順序與相依性,或是讓工作平行執行。
dag 與 steps
還記得剛剛的 flip-coin 範例嗎,透過steps也可以達成某程度的平行執行或是順序執行,但是無法表達相依性。什麼意思呢?
熟悉 yaml 的人應該會知道 yaml 跟 json 是等價可以互相轉換的,而 yaml 中的
1 | steps: |
中間的 - -
表達的是 list中的list 的意思,也就是 [[flip-coin], [heads, tails]]。當 steps 再寫的時候如果是依序執行一律用- -
,若是在同一個 list 內則會平行執行。
因此以下用一個例子比較:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29spec:
entrypoint: diamond
templates:
- name: diamond
steps:
- - name: A
template: echo
arguments:
parameters: [{name: message, value: A}]
- - name: B
template: echo
arguments:
parameters: [{name: message, value: B}]
- name: C
template: echo
arguments:
parameters: [{name: message, value: C}]
- - name: D
template: echo
arguments:
parameters: [{name: message, value: D}]
- name: echo
inputs:
parameters:
- name: message
container:
image: alpine:3.7
command: [echo, "{{inputs.parameters.message}}"]
是等價於1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33spec:
entrypoint: diamond
templates:
- name: diamond
dag:
tasks:
- name: A
template: echo
arguments:
parameters: [{name: message, value: A}]
- name: B
dependencies: [A]
template: echo
arguments:
parameters: [{name: message, value: B}]
- name: C
dependencies: [A]
template: echo
arguments:
parameters: [{name: message, value: C}]
- name: D
dependencies: [B, C]
template: echo
arguments:
parameters: [{name: message, value: D}]
- name: echo
inputs:
parameters:
- name: message
container:
image: alpine:3.7
command: [echo, "{{inputs.parameters.message}}"]
如下圖透過UI看到的結果:
conditionals
了解了上面如何實現 if-else
,依序執行
, 同時執行
後,最後在看一個範例解釋了如何在 workflow 執行時動態的給予參數,並影響結果,我們直接看yaml file:
1 | apiVersion: argoproj.io/v1alpha1 |
在 spec
中可以提供 arguments
,來將參數傳進各個step
中。如上面的範例,預設的參數 should-print
為 “false” 而使得直接執行不會執行 whalesay 步驟,但是在執行 workflow 時使用如下指令,便可以動態傳進參數:
1 | argo submit examples/conditionals.yaml -p should-print=true |
而 step
可以使用 NaN
來獲取參數,whalesay這個步驟便會執行。
Summary
以上便是 Argo 的簡易使用分享,想了解更詳細的使用方法建議直接參考 example 來找到最適合自己的範例。
透過 Argo 我們便可以描述 pod 跟 pod 之間的執行順序關係,還可以在彼此之間傳遞結果。
因此 Kubeflow/pipeline 甚至是 Kubeflow 社群的 CI/CD 皆是利用 Argo來完成的。
接下來會利用我自己為 Kubeflow/tf-operator 貢獻的 e2e test 來描述 Kubeflow 如何用 Argo 實作自己的 CI/CD。