はじめに
頑張れば、何かがあるって、信じてる。nikkieです。
MLOpsにやや興味があり、最近はGitHub ActionsでMLOpsという以下のブログ記事を真似しています。
ここで登場したArgoなるものが気になり、9月の Python mini Hack-a-thon で触ってみました。
目次
- はじめに
- 目次
- 勉強会の概要
- Argoとは
- 取り組んだこと
- ローカル環境構築
- Argoのexamplesで概念を掴む
- GitHub Actionsで動かしているCIワークフローをArgoで動かしてみる
- 次にやること
- おまけ:Dockerまわりのコンマリ
勉強会の概要
(第115回)Python mini Hack-a-thon(オンライン) - connpass
スプリントのゆるい版みたいな感じで各自自分でやりたいことを持ってきて、勝手に開発を進めています。
Twitterの #pyhack ハッシュタグを追うと雰囲気がつかめると思います。
集中してもくもくできて素振りが捗りました。
1日お疲れさまでした。ありがとうございました!
Argoとは
Container-native Workflow Engineを標榜するArgo。
ワークフローの各ジョブはKubernetes(k8s)上で動かせます。
今日触った範囲では、コンテナをつなげてワークフローを定義し実行できるという理解です。
ワークフローの各ジョブはコンテナ化されているので、異なるプログラミング言語で書けるというのが1つのメリットなのかなと思いました(マイクロサービスっぽい!)。
k8sクラスタをAWSやGCPに立てるのは素振りにはちょっとお高いので、minikubeを使ってローカルで動かしました。
取り組んだこと
- ローカル環境構築
- Argoのexampleで概念を掴む
- GitHub Actionsで動かしているCIワークフローをArgoで動かしてみる
先日書いたGitHub ActionsでMLOpsの記事でやっているスクリプト実行がArgoでできました!
ローカル環境構築
minikube
minikube start | minikube の手順でv1.12.3をインストール。
過去にbrewで入れたv1.9系は動かなくなっていたので、アンインストールして新しいものにしました1。
minikube
コマンド自分用メモ
$ minikube start $ minikube pause $ minikube unpause # pauseした後の再開 $ minikube stop
Argo
minikube start
してある状態で以下を進めます。
Quick Start - Argo Workflows - The workflow engine for Kubernetes
kubectl port-forward
すると、ブラウザからArgoを設定できます。
(こちらで操作もできるようです2が、今回はyamlを書いて進めていきました)
Argo CLI
ArgoのQuick startで案内されているCLIも入れます。
Release v2.11.0 · argoproj/argo · GitHub をもとにmacOSにインストールしました。
Argo CLIはkubectl
のラッパーというのがポイントでした。
argo
コマンドもkubectl
同様-n
でnamespaceが指定できます。
これを指定しないと、~/.kube/config
の指定によりminikube
namespaceを操作するので、ワークフローがうまく実行されませんでした。
Argoのexamplesで概念を掴む
examplesのREADMEで手厚く解説されています。
READMEの一部を写経
READMEの上から
- Hello World!(docker/whalesayを動かす)
- Parameters(docker/whalesayに引数を渡す)
- Steps(順次実行、並列実行)
- Artifacts(あるコンテナの出力を次のコンテナの入力へ)
を進めました。
Argoはk8sのカスタムリソースとして定義されているので、k8sと同様にyamlファイルを書けば済みます。
k8sは業務で触っているので、kind: Workflow
を指定したyamlファイルを書くというのは、結構しっくり来ました。
どんなパラメタで、また、どうファイルマウントしてDockerイメージを動かすかをyamlで書いていく感じです。
argoコマンド チートシート
※自分用まとめです
argo lint
:yamlを書いた直後に、yamlの形式に異常がないか確認するのに使いますargo list
:ワークフローの一覧argo submit
:yamlをもとにワークフローを作成して実行(--watch
を付けて実行状況を監視できます3)argo get
:指定したワークフローの詳細が見られますargo logs
:指定したワークフロー全体や各ステップ(ポッド)のログが見られますargo delete
:指定したワークフローの削除
行き着いたコマンド順(-n argo
はnamespaceの指定です)
$ argo -n argo lint argo-workflow/practice.yaml $ argo -n argo list $ argo -n argo submit argo-workflow/practice.yaml --watch STEP TEMPLATE PODNAME DURATION MESSAGE ✔ artifact-passing-v6rnm artifact-example ├---✔ generate-artifact whalesay artifact-passing-v6rnm-1548704093 5s └---✔ consume-artifact print-message artifact-passing-v6rnm-1648314195 7s # ワークフロー全体のログを見る $ argo -n argo logs artifact-passing-v6rnm # ワークフローの中の generate-artifact ステップだけのログを見る $ argo -n argo logs artifact-passing-v6rnm artifact-passing-v6rnm-1548704093 $ argo -n argo delete artifact-passing-v6rnm
GitHub Actionsで動かしているCIワークフローをArgoで動かしてみる
以下のリポジトリのGitHub Actions製ワークフロー(Pythonのunittestを実行)を
bring-script-more-users/python-unittest.yml at master · ftnext/bring-script-more-users · GitHub
Argoで動かしてみます。
参考にしたのはこちら。
パブリックリポジトリにて動作
以下の2ステップで実装しました4。
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: bringscript-ci- spec: entrypoint: bringscript-ci # templatesの中のbringscript-ciを実行する指定 arguments: # 引数をデフォルト値込みで設定 parameters: - name: repo value: https://github.com/ftnext/bring-script-more-users.git - name: revision value: bringscript0.1.0 templates: - name: bringscript-ci steps: # 順次実行する書き方 - - name: checkout template: checkout - - name: test-unit template: test-unit arguments: artifacts: # 取得したソースコードのディレクトリをバインド - name: source from: "{{steps.checkout.outputs.artifacts.source}}" - name: checkout inputs: artifacts: - name: source path: /src git: repo: "{{workflow.parameters.repo}}" revision: "{{workflow.parameters.revision}}" outputs: artifacts: - name: source path: /src container: image: python:3.8 command: ["/bin/sh", "-c"] args: ["cd /src && git status && ls -l"] - name: test-unit inputs: artifacts: - name: source path: /python/src/github.com/ftnext/bring-script-more-users container: image: python:3.8-slim-buster command: ["/bin/sh", "-c"] args: [" cd /python/src/github.com/ftnext/bring-script-more-users/bringscript && python -m pip install .[dev] && pytest "]
checkoutステップはgit pull
できればいいので、Dockerイメージはpython:3.8
を指定。
test-unitステップはpythonだけあればいいので、python:3.8-slim-buster
を指定しています。
プライベートリポジトリの場合は?
k8sのSecretsを作って、プライベートリポジトリにアクセスするための情報をワークフローから参照します。
kubectl -n argo create secret generic github-creds --from-file=ssh-private-key=<SSH秘密鍵のパス>
ssh-private-key
の部分がSecretsのキーになります。
指定していないとファイル名がキーになるという挙動でちょっとハマりました6。
# ... snip ... - name: checkout inputs: artifacts: - name: source path: /src git: repo: "{{workflow.parameters.repo}}" revision: "{{workflow.parameters.revision}}" sshPrivateKeySecret: # 追加 name: github-creds # 追加 key: ssh-private-key # 追加 outputs: artifacts: - name: source path: /src container: image: python:3.8 command: ["/bin/sh", "-c"] args: ["cd /src && git status && ls -l"] # ... snip ...
GitHub ActionsとArgoの違い
ステップの分け方が違うことに気づきました。
GitHub Actionsは1つの環境(ランナー)で複数のステップを実行します。
そのため、依存のインストールとユニットテストの実行を別ステップに分けることができます。
Argoはさまざまな環境(コンテナ)でステップを実行していきます。
そのため、依存のインストールとユニットテストの実行を分けずに、Pythonが使えるコンテナの中に押し込むことになりました。
次にやること
今回Argoを触り、例のGitHub ActionsでMLOpsブログの真似は先に進めそうです。
AWSやGCPなどクラウド上にクラスタを作り、Argoをセットアップ、そしてGitHub ActionsからArgoを呼び出すというのを今後取り組んでみようと思います。
おまけ:Dockerまわりのコンマリ
minikube
の再設定まわりでつまづき、「もしかしてDockerのDisk image size?」と見てみました(これは見当違いでした)。
macOSのDockerは定期的にコンマリする(片付けする)しかないんですね。
Docker向けに割り当てたDiskが減るたびに暫定対応として割り当てを増やしていたのですが、Docker.rawが巨大になり、ディスクを圧迫していました。
Disk image sizeを広げていくのはアンチパターンだと考えます。
上限に達したら、sizeを減らすしかなくなり、そのときにDockerイメージが全部消えます。
大量のDockerイメージの中から消してはいけないものがないか確認するよりも、定期的にコンマリしたほうがいいなと今回体験しました。
-
~/.minikube
や~/.kube/config
に残っていた古い情報のためにminikube start
に失敗したようなので、これらの削除も必要でした。↩ -
Private Repositories - Argo CD - Declarative GitOps CD for Kubernetes など(Argo CDというのは今回触ったArgoとは別物なのかな?)↩
-
spec.entrypoint
に指定したtemplateが実行されます。このtemplateの中でcheckout→test-unitと順次実行する実装です(プログラミングの関数っぽいですね)↩ -
SSH秘密鍵にパスフレーズが指定されていたためにエラーになったので、Secretsに設定する際は
ssh-keygen
で再設定して外しました。 ref: sshの秘密鍵のパスフレーズを削除する - Qiita↩