nikkie-ftnextの日記

イベントレポートや読書メモを発信

Kubeflow Pipelines素振りの記:ローカルのクラスタにインストールして、チュートリアルの簡単なPipelineを動かす

はじめに

「お疲れさまでーす」
「あっ、ご丁寧にありがとうございます」
「kfpさんですか。私はにっPといいます。仕掛け人です」
「kfpさんのご担当は?」

思わせぶりな書き出しでしたがミリアニの記事ではなく、技術者nikkieがお送りする技術記事です。
Kubeflow Pipelinesを触り出しました。

目次

Kubeflow Pipelinesとは

こちらのブログが大変分かりやすかったです。

Kubeflow Pipelines は機械学習パイプラインを実装するための OSS のひとつです。

余談:(同じ意味か精査していませんが)『機械学習デザインパターン』にも「デザインパターン25:ワークフローパイプライン(Workflow Pipeline)」がありますね

Kubeflow Pipelinesのゴール
https://www.kubeflow.org/docs/components/pipelines/v1/introduction/ より

  • End-to-end orchestration
  • Easy experimentation
  • Easy re-use
    • 再利用簡単になる、結構興味

Kubeflow Pipelinesのインストール

M1 MacでDocker Desktopを使っています。
Docker Desktopの機能でKubernetesを立て、そこにKubeflow Pipelinesをインストールしました。

% docker --version
Docker version 24.0.2, build cb74dfc
% kubectl version
Client Version: v1.28.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.27.2

インストール手順

KubeflowにはPipelines以外の要素もあるのですが、Kubeflow Pipelinesだけをインストールする手順です。
https://www.kubeflow.org/docs/components/pipelines/v1/installation/localcluster-deployment/#deploying-kubeflow-pipelines

このドキュメントはkind, k3s, k3aiのいずれかで進めていますが、Docker DesktopのKubernetesでも動作しました!

export PIPELINE_VERSION=2.0.3
kubectl apply -k "github.com/kubeflow/pipelines/manifests/kustomize/cluster-scoped-resources?ref=$PIPELINE_VERSION"
kubectl wait --for condition=established --timeout=60s crd/applications.app.k8s.io
kubectl apply -k "github.com/kubeflow/pipelines/manifests/kustomize/env/platform-agnostic-pns?ref=$PIPELINE_VERSION"

kubectl -n kubeflow get poで全てのPodがRunningになるのを見守ります。
CrushLoopBackoffになるPodもありましたが、おそらく順序の依存関係が満たされないためではないかと思っています。
自動でリスタートするので、放っておいたら全部READY(1/1)になりました

Podが立ち上がったらポートフォワードです。
kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8080:80
Docker Desktopの場合は http://localhost:8080/ でWeb UIが見られました🙌

チュートリアルに沿ってPipelineを作ってRun!

Web UIには2つのチュートリアルPipelineがあります。
今回は「DSL - Control structures」に沿って(途中まで)手を動かしていきます。
https://github.com/kubeflow/pipelines/blob/sdk/release-1.8/samples/tutorials/DSL%20-%20Control%20structures/DSL%20-%20Control%20structures.py

仮想環境を作って、SDKをインストールしました。

  • Python 3.11.4
  • pip install 'kfp<2'

ライブラリバージョン

absl-py==1.4.0
attrs==23.1.0
cachetools==5.3.2
certifi==2023.7.22
charset-normalizer==3.3.2
click==8.1.7
cloudpickle==2.2.1
Deprecated==1.2.14
docstring-parser==0.15
fire==0.5.0
google-api-core==2.14.0
google-api-python-client==1.12.11
google-auth==2.23.4
google-auth-httplib2==0.1.1
google-cloud-core==2.3.3
google-cloud-storage==2.13.0
google-crc32c==1.5.0
google-resumable-media==2.6.0
googleapis-common-protos==1.61.0
httplib2==0.22.0
idna==3.4
jsonschema==4.19.2
jsonschema-specifications==2023.7.1
kfp==1.8.22
kfp-pipeline-spec==0.1.16
kfp-server-api==1.8.5
kubernetes==25.3.0
oauthlib==3.2.2
protobuf==3.20.3
pyasn1==0.5.0
pyasn1-modules==0.3.0
pydantic==1.10.13
pyparsing==3.1.1
python-dateutil==2.8.2
PyYAML==6.0.1
referencing==0.30.2
requests==2.31.0
requests-oauthlib==1.3.1
requests-toolbelt==0.10.1
rpds-py==0.12.0
rsa==4.9
six==1.16.0
strip-hints==0.1.10
tabulate==0.9.0
termcolor==2.3.0
typer==0.9.0
typing_extensions==4.8.0
uritemplate==3.0.1
urllib3==1.26.18
websocket-client==1.6.4
wrapt==1.16.0

Pipelineを作ってRunする手順(現時点の理解)

  1. kfpが提供するDSLでpipelineを定義したPythonファイルを作る
    • Pythonの関数を書けばよい
    • 関数はタスクをつなぎ合わせる
    • タスクはContainerOpインスタンス
  2. Pythonファイルをpipelineの定義のYAMLファイルにコンパイル
  3. Kubeflow PipelinesのWeb UIでYAMLファイルをUpload(Pipeline作成!)
  4. Web UIでPipelineをRun

Hello World

複数のタスクを繋いで動かす単純な例です。
DSL - Control structures」は複数の例が組み合わさっているので、一番簡単なものを切り出しました

dsl.pipelineで定義した関数hello_world_pipelineがパイプラインの定義です。
func_to_container_op1でデコレートした関数を呼び出すと、タスク(ContainerOpインスタンス)を返します。
afterを使ってタスクの依存関係を定義し、パイプラインの定義を完成させています。

if __name__ == "__main__":のブロックにコンパイルするコードを書いています。
python hello_world_example.pyと実行すると、コンパイルされてhello_world_example.py.yamlができます。
中はk8sのリソース定義です。
これをKubeflow Pipelines Web UIにアップロードしてPipelineを作ります。

Pipelineを作った後は実行します(=Runを作ります)。
クラスタにPodができて、Pipelineの実行が進んでいきました

ExitHandler

タスクがfailしたとき、そこでPipelineのRunが落ちないようにできます。
https://kubeflow-pipelines.readthedocs.io/en/1.8.22/source/kfp.dsl.html#kfp.dsl.ExitHandler

fail_opが絶対に異常終了するタスクです。
Hello Worldと同様にコンパイルしてYAMLファイルを作り、それをWeb UIにアップロードしてPipelineを作ります。

Runは最後まで実行されますが、途中のタスクがfailなのでRunとしてはfail扱い(赤)です

比較として、ExitHandlerを使わない場合は続くタスクが実行されません。
https://gist.github.com/ftnext/9dd64bd49bb1443c0eda4734a2a18a7f

終わりに

ローカル環境にKubeflow Pipelinesをインストールし、SDK(kfpライブラリ)を使って簡単なPipelineを作って実行してみました。
なんだかよくわからない巨大な存在でしたが、環境構築して簡単な例を動かし、最初のハーケンが差せました!(完全に理解はまだまだ先です)

Kubeflow Pipelinesにはv1とv2があり、冒頭で引いたReproさんのブログが詳しいです。
私は今回参照するバージョンを誤り2@dsl.componentでデコレートしていて動きませんでした。
解決にはGPT-4の力を借りています。ありがとうございます!