mike-neckのブログ

Java or Groovy or Swift or Golang

Hera をためしに使ってみただけ

こんにちは。

仕事で argo-workflows を使っていますが、いくつか不満点があります。 argoproj-labs が提供する Hera はその不満点を解消できそうな気がしたので、少しだけ試してみました。

argo-workflows.readthedocs.io


不満点

もともとの不満点としては、以下の通り。

  • Yaml なのでチェックの精度が高くない
    • 引数の受け渡しのチェックはある(argo lint を使う)ものの、変数の有効性(スコープ等)や評価方法(変数として評価する or 評価式として評価するか)等が実行時までわからないため、実行時エラーが多く、開発の速度があがらない
  • Yaml なのでテンプレートの呼び出し元への移動や呼び出し先への移動、宣言への移動といった IDE が従来もっている機能がほとんど利用できない
  • Helm で具体的な値を埋めているが、 Helm のテンプレート(Goテンプレート)が使いづらく、また複雑なワークフローを作っていることも相まって Helm の型システムがたまにバグる(再現ケースを作れなくて報告できてない)

不満を持つのはいいものの、代替ソリューションについてほとんど知識がなかったので、気長に調べてたところ、 Hera というのを Argo Project 公式が出しているようだったので、試してみることにしました。なお、以前に Apple の Pkl というのも試していたものの、まだ Argo Workflows の型定義がなく、一から作る必要があっていろいろやって云々…

github.com


インストール

以下の通りでインストールできた

uv init \
    --directory "${PWD}" \
    --name "${PWD##*/}" \
    --vcs git \
    --python "cpython-3.13.3-macos-aarch64-none"

uv add "hera[yaml]"

プログラム

これは Hera のページのほぼコピペ

from hera.workflows import script, Steps, Workflow

@script()
def echo_message(message: str):
    print(message)

with Workflow(
    generate_name="example-hera-",
    entrypoint="echo_message",
    namespace="argo",
    service_account_name="argo-sa"
) as wk:
    with Steps(name="echo_message"):
        echo_message(arguments={"message": "Hello from Hera!"})

def main():
    yaml = wk.to_yaml()
    print(yaml)


if __name__ == "__main__":
    main()

実行結果

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: example-hera-
  namespace: argo
spec:
  entrypoint: echo_message
  serviceAccountName: argo-sa
  templates:
  - name: echo_message
    steps:
    - - name: echo-message
        template: echo-message
        arguments:
          parameters:
          - name: message
            value: Hello from Hera!
  - name: echo-message
    inputs:
      parameters:
      - name: message
    script:
      image: python:3.9
      source: |-
        import os
        import sys
        sys.path.append(os.getcwd())
        import json
        try: message = json.loads(r'''{{inputs.parameters.message}}''')
        except: message = r'''{{inputs.parameters.message}}'''

        print(message)
      command:
      - python

少しだけ試してみた感じだと、よさそうではあった。

ただ、期待の引数周りの型チェックや複雑なワークフローの組み込みを実現できるかはまた未知数…