Stories

Detail Return Return

ArgoWorkflow教程(三)---使用 Artifacts 實現步驟間文件共享 - Stories Detail

argoworkflow-3-artifacts.png

上一篇我們分析了 Workflow、WorkflowTemplate、template 之間的關係。本篇主要分析如何在 argo-workflow 中使用 S3 存儲 artifact 實現步驟之間的文件共享。

<!--more-->

本文主要解決兩個問題:

  • 1)artifact-repository 如何配置
  • 2)Workflow 中如何使用

1. artifact-repository 配置

ArgoWorkflow 對接 S3 實現持久化,依賴於 artifact-repository 配置。

有三種方式設置相關配置:

  • 1)全局配置:在 workflow-controller deploy 中直接通過配置文件方式寫入 S3 相關配置,指定全局使用的artifactRepository, 該方式優先級最低,可以被後續兩種方式替換。
  • 2)命名空間默認配置:ArgoWorkflow 會在 Workflow 所在命名空間尋找當前命名空間的默認配置,該方式配置優先級第二,可以覆蓋全局指定的配置。

    • 規定:會在 Workflow 所在命名空間尋找名為 artifact-repositories 的 Configmap 作為配置。
  • 3)Workflow 中指定配置:還可以在 Workflow 中顯式指定使用哪個 artifact-repository,該方式優先級最高。

注意📢不管什麼方式指定 artifact-repository,其中存儲 S3 AKSK 信息的 Secret 都必須同步到 Workflow 所在的命名空間才行

優先級 InWorkflowConfig > Namespace > Global

全局配置

以 helm 方式部署的 ArgoWorkflow 的話默認就會以這種形式指定配置。

workflow-controller 的 deployment yaml 如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: argo-workflow-argo-workflows-workflow-controller
  namespace: argo-dev
spec:
  template:
    metadata:
    spec:
      containers:
      - args:
        - --configmap
        - argo-workflow-argo-workflows-workflow-controller-configmap
        - --executor-image
        - quay.io/argoproj/argoexec:v3.4.11
        - --loglevel
        - info
        - --gloglevel
        - "0"
        - --log-format
        - text

可以看到在啓動命令中以 --configmap argo-workflow-argo-workflows-workflow-controller-configmap 方式指定了配置文件來源的 Configmap。

這個 Configmap 的內容如下:

apiVersion: v1
data:
  # ... 省略
  artifactRepository: |
    s3:
      endpoint: minio.default.svc:9000
      bucket: argo
      insecure: true
      accessKeySecret:
        name: my-s3-secret
        key: accessKey
      secretKeySecret:
        name: my-s3-secret
        key: secretKey
kind: ConfigMap
metadata:
  name: argo-workflows-workflow-controller-configmap
  namespace: argo

包括了 S3 的 endpoint、bucket、aksk 等信息,藉助這些信息 Workflow 就可以訪問 S3 了。

命名空間默認配置

根據當前實現,ArgoWorkflow 會優先使用 Workflow 所在命名空間下的默認 artifactRepository 配置

默認會使用名為 artifact-repositories 的 Configmap 作為當前命名空間下 Workflow 的 artifactRepository 配置,Configmap 中的內容大概長這樣:

注意:Configmap 名必須是 artifact-repositories
apiVersion: v1
kind: ConfigMap
metadata:
  # If you want to use this config map by default, name it "artifact-repositories". Otherwise, you can provide a reference to a
  # different config map in `artifactRepositoryRef.configMap`.
  name: artifact-repositories
  annotations:
    # v3.0 and after - if you want to use a specific key, put that key into this annotation.
    workflows.argoproj.io/default-artifact-repository: my-artifact-repository
data:
  my-artifact-repository: |
    s3:
      bucket: lixd-argo
      endpoint: minio.argo-dev.svc:9000
      insecure: true
      accessKeySecret:
        name: my-s3-secret
        key: accessKey
      secretKeySecret:
        name: my-s3-secret
        key: secretKey
 # 可以寫多個 Repository
 my-artifact-repository2: ...

Data 中的每一個 Key 對應一個 Repository, 然後使用 workflows.argoproj.io/default-artifact-repository annotation 來指定默認使用哪個 artifactRepository

比如這裏就指定了 my-artifact-repository 為默認 artifactRepository.

Workflow 中指定配置

除此之外,還可以直接在 Workflow 中指定具體要使用哪個 artifactRepository。

spec:
  artifactRepositoryRef:
    configMap: my-artifact-repository # default is "artifact-repositories"
    key: v2-s3-artifact-repository # default can be set by the `workflows.argoproj.io/default-artifact-repository` annotation in config map.

需要指定 Configmap 以及具體的 Key 來找到唯一的 artifactRepository。

只會在當前命名空間下找,因此需要確保這個 Configmap 存在。

或者直接把 S3 配置寫到 Workflow 裏(不推薦),就像這樣:

  templates:
  - name: artifact-example
    inputs:
      artifacts:
      - name: my-input-artifact
        path: /my-input-artifact
        s3:
          endpoint: s3.amazonaws.com
          bucket: my-aws-bucket-name
          key: path/in/bucket/my-input-artifact.tgz
          accessKeySecret:
            name: my-aws-s3-credentials
            key: accessKey
          secretKeySecret:
            name: my-aws-s3-credentials
            key: secretKey
    outputs:
      artifacts:
      - name: my-output-artifact
        path: /my-output-artifact
        s3:
          endpoint: storage.googleapis.com
          bucket: my-gcs-bucket-name
          # NOTE that, by default, all output artifacts are automatically tarred and
          # gzipped before saving. So as a best practice, .tgz or .tar.gz
          # should be incorporated into the key name so the resulting file
          # has an accurate file extension.
          key: path/in/bucket/my-output-artifact.tgz
          accessKeySecret:
            name: my-gcs-s3-credentials
            key: accessKey
          secretKeySecret:
            name: my-gcs-s3-credentials
            key: secretKey
          region: my-GCS-storage-bucket-region
    container:
      image: debian:latest
      command: [sh, -c]
      args: ["cp -r /my-input-artifact /my-output-artifact"]
只會在當前命名空間下找,因此需要確保這個 Configmap 存在。

小結

包括三種方式:

  • 1)全局配置
  • 2)命名空間默認配置
  • 3)Workflow 中指定配置

注意📢:由於 S3 AKSK 以 Secret 方式存儲,因此三種配置方式都需要將該 Secret 同步到 Workflow 所在命名空間,否則無法在 Pod 中使用,導致 Workflow 無法正常運行。

如果 ArgoWorkflow 能自動接管就好了,可以使用 https://github.com/mittwald/kubernetes-replicator 來自動同步

三種方式的區別

  • 全局配置全局只需要一個 Configmap 來指定 S3 信息即可,所有 Workflow 都使用該 S3 配置,簡單,但是不夠靈活。
  • 命名空間默認配置:該方式可以為不同命名空間配置不同的 S3,但是需要在每個命名空間都創建一個 Configmap。
  • Workflow 中指定配置:這種方式最靈活,可以為不同 Workflow 指定不同 S3,但是需要創建很多 Configmap。

使用場景

如果全局只有一個 S3 配置,那就使用 全局配置方式,最簡單。

如果租户間使用命名空間隔離,使用不同 S3,那使用命名空間默認配置方式就剛好

以上都不滿足的時候,才建議使用 Workflow 中指定配置方式。

2. Workflow 中使用 artifact

key-only-artifacts

當 Workflow 中不顯式指定 S3 配置信息時,argo 會按照前面的優先級自動尋找 artifact-repository 配置。

優先使用 Namespace 下的配置,沒有則使用全局配置

一個完整的 Demo 如下:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: artifact-passing-
spec:
  entrypoint: artifact-example
  templates:
  - name: artifact-example
    steps:
    - - name: generate-artifact
        template: whalesay
    - - name: consume-artifact
        template: print-message
        arguments:
          artifacts:
          # bind message to the hello-art artifact
          # generated by the generate-artifact step
          - name: message
            from: "{{steps.generate-artifact.outputs.artifacts.hello-art}}"

  - name: whalesay
    container:
      image: docker/whalesay:latest
      command: [sh, -c]
      args: ["cowsay hello world | tee /tmp/hello_world.txt"]
    outputs:
      artifacts:
      # generate hello-art artifact from /tmp/hello_world.txt
      # artifacts can be directories as well as files
      - name: hello-art
        path: /tmp/hello_world.txt

  - name: print-message
    inputs:
      artifacts:
      # unpack the message input artifact
      # and put it at /tmp/message
      - name: message
        path: /tmp/message
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["cat /tmp/message"]

第一個步驟,通過

第一個步驟,通過 tee 命令創建了一個文件並通過 outputs 進行輸出,由於指定的是 artifacts,因此這個文件會被存儲到 S3。

然後第二個步驟指定 inputs.artifacts 從 S3 讀取名為 message 的 artifact 並存儲到 /tmp/message 目錄。

問題來了第二步中讀取的 artifact 是從哪兒來的呢,就是 steps 中通過 arguments.artifacts 指定的,通過 name 進行關聯。

整個邏輯和 parameter 基本一致
  • 1)whalesay template 通過 outputs.artifacts 來申明當前 template 會輸出一個 artifact。
  • 2)print-message 中通過 inputs.artifacts 申明需要一個 artifact,並指定存儲位置
  • 3)steps 在使用該 template 時,通過 arguments.artifacts 來指定一個 artifact,這個 artifact 來源就是 1 中的 output,通過{{steps.generate-artifact.outputs.artifacts.$name}} 語法引用。
    artifact-passing-vzp2r-1469537892:
      boundaryID: artifact-passing-vzp2r
      displayName: generate-artifact
      finishedAt: "2024-03-29T08:42:34Z"
      hostNodeName: lixd-argo
      id: artifact-passing-vzp2r-1469537892
      message: 'Error (exit code 1): You need to configure artifact storage. More
        information on how to do this can be found in the docs: https://argo-workflows.readthedocs.io/en/release-3.5/configure-artifact-repository/'
      name: artifact-passing-vzp2r[0].generate-artifact

artifact 壓縮

默認情況下,所有的 artifact 會被打成 tar 包並 gzip 壓縮,可以通過archive 字段來配置壓縮情況:

  • 默認行為:tar + gzip
  • 可選關閉 tar+ gzip
  • 或者配置 gzip 壓縮等級
<... snipped ...>
    outputs:
      artifacts:
        # default behavior - tar+gzip default compression.
      - name: hello-art-1
        path: /tmp/hello_world.txt

        # disable archiving entirely - upload the file / directory as is.
        # this is useful when the container layout matches the desired target repository layout.   
      - name: hello-art-2
        path: /tmp/hello_world.txt
        archive:
          none: {}

        # customize the compression behavior (disabling it here).
        # this is useful for files with varying compression benefits, 
        # e.g. disabling compression for a cached build workspace and large binaries, 
        # or increasing compression for "perfect" textual data - like a json/xml export of a large database.
      - name: hello-art-3
        path: /tmp/hello_world.txt
        archive:
          tar:
            # no compression (also accepts the standard gzip 1 to 9 values)
            compressionLevel: 0
<... snipped ...>

Artifact 垃圾回收

所有 Artifact 都會上傳到 S3,為了保證 S3 不被填滿,垃圾清理是個問題。

好消息是,argo-workflow 3.4 開始,可以在 Workflow 中添加配置來實現自動刪除不需要的 Artifacts。

當前提供兩種回收策略,分別是:

  • OnWorkflowCompletion:工作流運行完成後就刪除
  • OnWorkflowDeletion:工作流被刪除時才刪除

同時可以統一為 Workflow 中的所有 artifact 配置回收策略,也可以單獨為每一個 artifact 配置回收策略。

Demo 如下:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: artifact-gc-
spec:
  entrypoint: main
  artifactGC:
    strategy: OnWorkflowDeletion  # default Strategy set here applies to all Artifacts by default
  templates:
    - name: main
      container:
        image: argoproj/argosay:v2
        command:
          - sh
          - -c
        args:
          - |
            echo "can throw this away" > /tmp/temporary-artifact.txt
            echo "keep this" > /tmp/keep-this.txt
      outputs:
        artifacts:
          - name: temporary-artifact
            path: /tmp/temporary-artifact.txt
            s3:
              key: temporary-artifact.txt
          - name: keep-this
            path: /tmp/keep-this.txt
            s3:
              key: keep-this.txt
            artifactGC:
              strategy: Never   # optional override for an Artifact

核心部分如下:

spec:
  entrypoint: main
  # 為 Workflow 中的所有 artifact 統一配置
  artifactGC:
    strategy: OnWorkflowDeletion  # default Strategy set here applies to all Artifacts by default
# 單獨指定 artifact 的回收策略
            outputs:
        artifacts:
          - name: temporary-artifact
            artifactGC:
              strategy: Never   # optional override for an Artifact

注意事項:為了避免相同工作流併發運行時,artifact 被誤刪除的問題,可以為不同工作流配置不同的 artifact repository。

forceFinalizerRemoval

argo-workflow 會啓動一個 <wfName>-artgc-* 格式命名的 Pod 來執行垃圾回收工作,如果執行失敗,整個 Workflow 也會被標記為失敗。

同時由於finalizers 沒有被刪除掉

apiVersion: argoproj.io/v1alpha1
kind: Workflow
  finalizers:
  - workflows.argoproj.io/artifact-gc

會導致這個 Workflow 無法刪除,可以執行以下命令移除

kubectl patch workflow my-wf \
    --type json \
    --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'

為了優化體驗,argo-workflow 3.5 版本新增了 forceFinalizerRemoval 參數

spec:
  artifactGC:
    strategy: OnWorkflowDeletion 
    forceFinalizerRemoval: true

只要forceFinalizerRemoval 設置為 true,即時 GC 失敗也會移除 finalizers。

常用 Artifacts 擴展

除了 S3 Artifacts 之外,為了便於使用, argo-workflow 還內置了 git、http 方式來獲取 artifact。

可以直接從指定 git 倉庫 clone 代碼,或者從指定 url 下載文件,就像這樣:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: hardwired-artifact-
spec:
  entrypoint: hardwired-artifact
  templates:
  - name: hardwired-artifact
    inputs:
      artifacts:
      # Check out the main branch of the argo repo and place it at /src
      # revision can be anything that git checkout accepts: branch, commit, tag, etc.
      - name: argo-source
        path: /src
        git:
          repo: https://github.com/argoproj/argo-workflows.git
          revision: "main"
      # Download kubectl 1.8.0 and place it at /bin/kubectl
      - name: kubectl
        path: /bin/kubectl
        mode: 0755
        http:
          url: https://storage.googleapis.com/kubernetes-release/release/v1.8.0/bin/linux/amd64/kubectl
      # Copy an s3 compatible artifact repository bucket (such as AWS, GCS and MinIO) and place it at /s3
      - name: objects
        path: /s3
        s3:
          endpoint: storage.googleapis.com
          bucket: my-bucket-name
          key: path/in/bucket
          accessKeySecret:
            name: my-s3-credentials
            key: accessKey
          secretKeySecret:
            name: my-s3-credentials
            key: secretKey
    container:
      image: debian
      command: [sh, -c]
      args: ["ls -l /src /bin/kubectl /s3"]

3. Demo

測試點:

  • 1)創建到 Workflow 對應 Namespace 是否能正常使用
  • 2)將S3 配置創建到 Argo 部署的 Namespace 是不是可以不需要進行同步了。

Configmap:

  • Name:argo-workflow-argo-workflows-workflow-controller-configmap
  • Namespace:argo-dev
  • Key:artifactRepository

Minio 準備

部署一個 local-path-storage csi,如果有別的 csi 也可以跳過這一步

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml

然後部署 minio

helm install minio oci://registry-1.docker.io/bitnamicharts/minio
    my-release-minio.default.svc.cluster.local
   
   export ROOT_USER=$(kubectl get secret --namespace default my-release-minio -o jsonpath="{.data.root-user}" | base64 -d)
   export ROOT_PASSWORD=$(kubectl get secret --namespace default my-release-minio -o jsonpath="{.data.root-password}" | base64 -d)

配置 artifact-repository

cm.yaml 完整內容如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: artifact-repositories
  annotations:
    workflows.argoproj.io/default-artifact-repository: my-artifact-repository
data:
  my-artifact-repository: |
    s3:
      bucket: argo
      endpoint: minio.default.svc.cluster.local:9000
      insecure: true
      accessKeySecret:
        name: my-s3-secret
        key: accessKey
      secretKeySecret:
        name: my-s3-secret
        key: secretKey

secret.yaml 完整內容如下:

apiVersion: v1
stringData:
  accessKey: admin
  secretKey: minioadmin
kind: Secret
metadata:
  name: my-s3-secret
type: Opaque

創建 artifact repository 配置

kubectl apply -f cm.yaml
kubectl apply -f secret.yaml

Workflow 中使用artifact

兩個步驟:

  • generate:生成一個文件,並通過 outputs.artifact 寫入 S3
  • consume:使用 inputs.artifact 從 S3 讀取文件並打印內容

workflow.yaml 完整內容如下:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: key-only-artifacts-
spec:
  entrypoint: main
  templates:
    - name: main
      dag:
        tasks:
          - name: generate
            template: generate
          - name: consume
            template: consume
            dependencies:
              - generate
    - name: generate
      container:
        image: argoproj/argosay:v2
        args: [ echo, hello, /mnt/file ]
      outputs:
        artifacts:
          - name: file
            path: /mnt/file
            s3:
              key: my-file
    - name: consume
      container:
        image: argoproj/argosay:v2
        args: [cat, /tmp/file]
      inputs:
        artifacts:
          - name: file
            path: /tmp/file
            s3:
              key: my-file

創建 Workflow

kubectl create -f workflow.yaml 

等待運行完成

[root@lixd-argo artiface]# kubectl get wf
NAME                                  STATUS      AGE     MESSAGE
key-only-artifacts-9r84h              Succeeded   2m30s

S3 查看文件

到 S3 中查看文件是否存在

可以看到,在 argo bucket 下有一個名為 my-file的文件存在,而且 context-type 是 application/gzip,這也驗證了 argo 會對 artifact 執行 tar+gzip。

argo-artifact-s3

4. 小結


【ArgoWorkflow 系列】持續更新中,搜索公眾號【探索雲原生】訂閲,閲讀更多文章。


本文主要分析了 argo 中的 artifact 使用,包括如何配置 artifact-repository:

包括三種方式:

  • 1)全局配置
  • 2)命名空間默認配置
  • 3)Workflow 中指定配置

以及如何在 Workflow 中使用 artifact 並通過一個 Demo 進行演示。

user avatar changqingdeyema_cy7lds Avatar portlouis Avatar 2018 Avatar cloudace Avatar liberhome Avatar syntaxerror Avatar aihejiudejiqiren_bjjawt Avatar huankuaideliushu Avatar jihu_gitlab Avatar
Favorites 9 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.