44
19

More than 3 years have passed since last update.

Argo workflow を動かしてみた

Posted at

Argo workflow の言葉のイメージから、人と人が連携して仕事を熟すためのツールと間違えそうだが、そうではなく、コンテナ化されたバッチアプリケーションのジョブコントロールシステムと言っても良いと思う。このOSSの実態を掴むために、軽く動かして見ただけだけど、これは良いツールという印象だった。

Argo workflow のインストール

K8sクラスタのセットアップ

Argo workflowは、コンテナ化されたバッチジョブのステップを実行するので、コンテナのエクゼキューターを指定できるようになっている。
デフォルトの設定では、dockerになっており、ソケットのパスが決まっている。 これらをdocker以外に変更しても動くが、成果物データをストレージに保存出来ないIssueがOpenとなっている。しかし、dockerと言っても、containerdをアクセスするだけのようなので、ソケットのパスが解れば解決するかもしれない。

workflow-controller-configmap.yaml
    # Specifies the container runtime interface to use (default: docker)
    # must be one of: docker, kubelet, k8sapi, pns
    containerRuntimeExecutor: docker

    # Specifies the location of docker.sock on the host for docker executor (default: /var/run/docker.sock)
    # (available since Argo v2.4)
    dockerSockPath: /var/someplace/else/docker.sock

クラウドの環境で動かすのは、いったん保留として、パソコン環境下で Kubernetes を動かして、Argo workflow を動かすことにした。普段は触りたくないが、こういう時は、自由自在に変更できる アップストリームの Kubernetes環境は重宝する。

GitHubからクローンするが、バージョン 1.16 のブランチを使用する。いったん、Vagrantfile を編集して、ワーカーノードのコア数を 4コア、メモリを 8GB する。それから、コンテナのランタイムエンジンを docker に変更する。 リソースの増強は、パソコンにリソースがあればの話であるが....

$ git clone -b 1.16 https://github.com/takara9/vagrant-kubernetes k8s-1.16
$ cd k8s-1.16
$ vi Vagrantfile

以下の node1 と node2 となる行の cpu: 4, memory: 8192 が変更箇所

vm_spec = [
  { name: "master", cpu: 2, memory: 2048,
    box: linux_os,
    private_ip: "172.16.20.11",
    public_ip: "192.168.1.91",
    storage: [], playbook: "install_master.yml",
    comment: "Master node" },

  { name: "node1", cpu: 4, memory: 8192,
    box: linux_os,
    private_ip: "172.16.20.12",
    public_ip: "192.168.1.92",
    storage: [], playbook: "install_node.yml",
    comment: "Worker node #1" },

  { name: "node2", cpu: 4, memory: 8192,
    box: linux_os,
    private_ip: "172.16.20.13",
    public_ip: "192.168.1.93",
    storage: [], playbook: "install_node.yml",
    comment: "Worker node #2" },
]

それから、Ansible playbook の以下の部分で、コンテナエンジンを docker-ce にする。

k8s-1.16/playbook/kubernetes/defaults/main.yml抜粋
# どちらか一方を選んで、有効化してください。
# Chose either one and enable it. docker-ce or containerd
container_engine: docker-ce
#container_engine: containerd

vagrant up してから、起動後に、マスターノードにログインして、以下の結果を得られたら K8sクラスタの起動は成功である。

maho:k8s-1.16 maho$ vagrant ssh master
<中略>
vagrant@master:~$ kubectl get node
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   18m   v1.16.8
node1    Ready    <none>   15m   v1.16.8
node2    Ready    <none>   12m   v1.16.8

Argo workflow のインストール

マスターノードで引き続き、Argo workflow のインストールを実施する。 名前空間 argo を作成して、その名前空間にインストールする。

$ kubectl create ns argo
$ kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo/stable/manifests/quick-start-postgres.yaml

これは Argo workflow のクイックインストール用の構成ファイルで、UIを提供する argo-server と バッチジョブのコントロールを担う workflow-controller を起動するだけでなく、データベース postgress と 実効結果の成果物データを保存するオブジェクトストレージ minio を起動してくれる。 クラウドで動かしていれば、クラウドのデータベースサービスとオブジェクトストレージに繋ぐのだが、今回は、オブジェクトストレージだけ AWS S3 を利用ことにする。次は、起動直後のポッドの起動状況である。

$ kubectl get pod -n argo
NAME                                  READY   STATUS    RESTARTS   AGE
argo-server-787995cbf5-f7v2c          1/1     Running   3          2m8s
minio                                 1/1     Running   0          2m8s
postgres-69559bd989-9krjj             1/1     Running   0          2m8s
workflow-controller-f5958489f-gfk9x   1/1     Running   3          2m8s

ArgoのCLIコマンドのインストール

本格的に活用する時には、CLIで操作できるのが便利だと思うので、インストールしておく。

$ curl -sLO https://github.com/argoproj/argo/releases/download/v2.9.2/argo-linux-amd64
$ chmod +x argo-linux-amd64
$ sudo mv ./argo-linux-amd64 /usr/local/bin/argo
$ argo version
argo: v2.9.2
  BuildDate: 2020-07-08T23:54:33Z
  GitCommit: 65c2bd44e45c11e0a0b03adeef8d6800b72cd551
  GitTreeState: clean
  GitTag: v2.9.2
  GoVersion: go1.13.4
  Compiler: gc
  Platform: linux/amd64

CLIコマンドからのジョブのサブミット

Argo workflow の構成ファイルを指定して、サブミットすれば、バッチ処理を実行して、結果をオブジェクトストレージに保存してくれる。
Kubernetes Job を本格的に利用する場合には、いろいろなツールを手作りする必要があったが、Argo workflow は便利である。

ジョブ(ワークフロー)のサブミット

$ argo submit -n argo --watch https://raw.githubusercontent.com/argoproj/argo/master/examples/hello-world.yaml

結果表示

$ argo list -n argo
NAME                STATUS      AGE   DURATION   PRIORITY
hello-world-qbsfr   Succeeded   1m    42s        0

$ argo get -n argo @latest
Name:                hello-world-qbsfr
Namespace:           argo
ServiceAccount:      default
Status:              Succeeded
Conditions:          
 Completed           True
Created:             Sun Jul 12 13:54:39 +0000 (1 minute ago)
Started:             Sun Jul 12 13:54:39 +0000 (1 minute ago)
Finished:            Sun Jul 12 13:55:21 +0000 (58 seconds ago)
Duration:            42 seconds
ResourcesDuration:   22s*(1 cpu),22s*(100Mi memory)

STEP                  TEMPLATE  PODNAME            DURATION  MESSAGE
 ✔ hello-world-qbsfr  whalesay  hello-world-qbsfr  40s         

次はログ表示で、これは、オブジェクトストレージにも保存される。

$ argo logs -n argo @latest
hello-world-qbsfr: 2020-07-12T13:55:19.44861898Z  _____________ 
hello-world-qbsfr: 2020-07-12T13:55:19.448653193Z < hello world >
hello-world-qbsfr: 2020-07-12T13:55:19.4486569Z  ------------- 
hello-world-qbsfr: 2020-07-12T13:55:19.448659054Z     \
hello-world-qbsfr: 2020-07-12T13:55:19.448661275Z      \
hello-world-qbsfr: 2020-07-12T13:55:19.448663282Z       \     
hello-world-qbsfr: 2020-07-12T13:55:19.448665338Z                     ##        .            
hello-world-qbsfr: 2020-07-12T13:55:19.448667331Z               ## ## ##       ==            
hello-world-qbsfr: 2020-07-12T13:55:19.448669252Z            ## ## ## ##      ===            
hello-world-qbsfr: 2020-07-12T13:55:19.448671178Z        /""""""""""""""""___/ ===        
hello-world-qbsfr: 2020-07-12T13:55:19.448673284Z   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~   
hello-world-qbsfr: 2020-07-12T13:55:19.448675217Z        \______ o          __/            
hello-world-qbsfr: 2020-07-12T13:55:19.448677205Z         \    \        __/             
hello-world-qbsfr: 2020-07-12T13:55:19.448679348Z           \____\______/   

書き込み先を minio から AWS S3 へ変更

AWS S3 にバケットを作成して、アクセス権を付与して、結果の書き込みができるようにする。

$ export mybucket=argo-tkr-bucket249
$ cat > policy.json <<EOF
> {
>    "Version":"2012-10-17",
>    "Statement":[
>       {
>          "Effect":"Allow",
>          "Action":[
>             "s3:PutObject",
>             "s3:GetObject"
>          ],
>          "Resource":"arn:aws:s3:::$mybucket/*"
>       }
>    ]
> }
> EOF

バケットの作成

$ aws s3 mb s3://$mybucket
make_bucket: argo-tkr-bucket249

権限の付与

$ aws iam create-user --user-name $mybucket-user
$ aws iam put-user-policy --user-name $mybucket-user --policy-name $mybucket-policy --policy-document file://policy.json
$ aws iam create-access-key --user-name $mybucket-user > access-key.json

アクセスキーとシークレットキーの表示

$ cat access-key.json 
{
    "AccessKey": {
<以下省略>

これらは、以下の設定ファイルには、オブジェクトストレージをアクセスするためのシークレット my-minio-cred が設定されているので、my-s3-cred を作って参照先を変更する。

$ kubectl get configmap -n argo
NAME                            DATA   AGE
artifact-repositories           1      9h
workflow-controller-configmap   4      9h

それから、エンドポイント、バケット名、リージョンもセットする。minioではTLSが使わないが、S3は暗号化されるので、それに合わせて変更もしておく。

workflow-controller-configmap抜粋
    artifactRepository:
      archiveLogs: true

      s3:
        endpoint: s3.amazonaws.com
        bucket: bucket-tkr-9949
        region: us-west-2
        insecure: false
<中略>
        accessKeySecret:
          name: my-s3-cred
          key: accesskey
        secretKeySecret:
          name: my-s3-cred
          key: secretkey

それぞれのコンフィグマップは適用するだけで、それぞれのポッドは、新しい設定で動作するので、特にポッドの再起動は必要ない。

それから、参照先のシークレットも作成する。

my-s3-cred.yaml
apiVersion: v1
kind: Secret
metadata:
  labels:
    app: s3
  name: my-s3-cred
stringData:
  accesskey: access-key.jsonから該当の値をコピペ
  secretkey: 同上
type: Opaque

これで、オブジェクトストレージ minio から S3 への切り替えが完了した。

Argo UI のアクセス

本格的に動かすならば、SSOや認証環境の考慮も必要であるが、パソコンの中で完結して動かすので、認証なしで簡単にアクセスできるようにする。

次のコマンドで、実行中のオブジェクトを直接編集して、nodeport としてアクセスできるようにする。

$ kubectl edit svc argo-server -n argo

編集箇所は、2つで、nodePort の行を追加、typeの値を NodePort へ変更する。

spec:
  clusterIP: 10.32.0.124
  externalTrafficPolicy: Cluster
  ports:
  - name: web
    nodePort: 30007
    port: 2746
    protocol: TCP
    targetPort: 2746
  selector:
    app: argo-server
  sessionAffinity: None
  type: NodePort

これで、Argo workflow のブラウザ画面を表示できるようになった。

ブラウザ画面のアクセス

サービスをNodePortで公開したので、マスターノードやワーカーノードのIPアドレス:30007 でブラウザ画面を開ける。

http://172.16.20.12:30007 にアクセスすれば、以下のワークフローの結果リストにアクセスできる。

workflow-top.png

この画面の左上、「+SUBMIT NEW WORKFLOW」からサンプルのワークフロー構成ファイルを指定してジョブを実行できる。サンプルは、
https://github.com/argoproj/argo/tree/master/examples に沢山あるので、試してみると良い。

ワークフローの実行結果

ワークフローを確認してみる。最初に実行した Hello-world は、タスクが一つしか無いので、一個だけが表示されている。このミドリのアイコンをクリックすると、右側に概要、コンテナ、出力成果物を選択して参照することができる。

workflow-job-1.png

次のステップが沢山あり並列処理があるサンプルも見ておく。

workflow-job-2.png

このジョブの構成ファイルが次である。ここでは、A,B,C,D のタスクがネストされて実行されている。
テンプレート、依存関係、受け渡す値などが表現されている。

dag-nested.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: dag-nested-
spec:
  entrypoint: diamond
  templates:
  - name: echo
    inputs:
      parameters:
      - name: message
    container:
      image: alpine:3.7
      command: [echo, "{{inputs.parameters.message}}"]
  - name: diamond
    dag:
      tasks:
      - name: A
        template: nested-diamond
        arguments:
          parameters: [{name: message, value: A}]
      - name: B
        dependencies: [A]
        template: nested-diamond
        arguments:
          parameters: [{name: message, value: B}]
      - name: C
        dependencies: [A]
        template: nested-diamond
        arguments:
          parameters: [{name: message, value: C}]
      - name: D
        dependencies: [B, C]
        template: nested-diamond
        arguments:
          parameters: [{name: message, value: D}]
  - name: nested-diamond
    inputs:
      parameters:
      - name: message
    dag:
      tasks:
      - name: A
        template: echo
        arguments:
          parameters: [{name: message, value: "{{inputs.parameters.message}}A"}]
      - name: B
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: "{{inputs.parameters.message}}B"}]
      - name: C
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: "{{inputs.parameters.message}}C"}]
      - name: D
        dependencies: [B, C]
        template: echo
        arguments:
          parameters: [{name: message, value: "{{inputs.parameters.message}}D"}]

まとめ

Argo workflow の言葉のイメージから、人と人が連携して仕事を熟すためのツールと間違えそうだが、ジョブコントロールシステムと言っても良いと思う。いろいろ課題もあるが、深層学習などのデータ前処理、学習処理などにも便利なツールであるが、バッチ中心の業務システムなどでも使えそうに思う。

参考資料

44
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
19