こんにちは。
カケハシの Musubi AI在庫管理 チームにて業務委託のエンジニアをさせていただいております takanakahiko と申します。
今回はuvをGitHub Actionsに導入したらとても効果があったので、紹介することができればと思います。
uvとは
uvとはPythonのパッケージインストーラー・リゾルバーです。 その最大の特徴はRust言語で開発されており、従来のツールの100倍の速度で動作する点です。 pipやpip-toolsのdrop-in replacementが可能であることも特徴です。
開発をするのはAstralです。 AstralはRuffの開発で有名ですね。
Ruffについては、こちらの記事で紹介しています。
試しに手元で利用する
今回の目的はGitHub Actionsへの導入です。 その前に手元でひととおり使ってみます。
まずは、比較のために通常のpipを用いた場合の速度を確認しておきます。
time
コマンドはそれに続くコマンドを実行し、その実行時間を出力するコマンドです。
# 計測のためにキャッシュを削除しておく $ pip cache purge # 仮想環境作成の計測 $ time python3 -m venv venv python3 -m venv venv 0.88s user 0.15s system 41% cpu 2.480 total # インストールの計測 $ source venv/bin/activate (venv)$ time pip install -r requirements.txt (省略) pip install -r requirements.txt 30.31s user 8.66s system 40% cpu 1:36.72 total # この次に uv を試すので後片付けをしておく $ deactivate $ rm -rf venv
ではuvを利用しましょう。
計測しない場合は time
は不要です。
まずはuvをインストールします。 複数通りの方法がありますが、pip経由でインストールしてみます。
pip install uv
仮想環境の作成自体もuvから行うことが可能です。 uvを利用するならこっちの方法で仮想環境を作成した方がトラブルが少なそうですね。
$ time uv venv (省略) uv venv 0.05s user 0.05s system 7% cpu 1.407 total
次に実際にパッケージのインストールをしてみましょう。
uvはディレクトリ内に .venv
等のディレクトリがあればそれを解釈するので、 activate
は不要です。
もちろん source .venv/bin/activate
でactivateしていつも通りに開発することも可能です。
$ time uv pip install -r requirements.txt (省略) uv pip install -r requirements.txt 4.66s user 4.43s system 97% cpu 9.293 total
実行結果をまとめてみます。
とんでもなく速いですね。 これはGitHub Actionsへの導入が期待できそうです。
仮想環境の作成 | パッケージのインストール | |
---|---|---|
pip | 0.88s | 30.31s |
uv | 0.05s | 4.66s |
GitHub Actions へ導入する
uvの発表は社内でも話題になりました。
良さそうなツールであればぜひ採用したいところです。 しかし、大人数が関与する開発において、各々の環境でどのような問題が発生しうるか予想ができないので、パッケージマネージャーの移行はかなり大変そうです。
そこでまず白羽の矢が立ったのがGitHub Actionsへの導入です。 これによってGitHub Actionsの待ち時間や課金金額の削減が見込めるとともに、 uvが実際のプロダクトの開発に耐えうるものなのか検証することもできそうです。 新しいツールなので、CDの方にいきなり入れることを避けCIにだけ導入することで様子を見てみることにしました。
実際に導入する中でいくつか気をつけるポイントがあったので紹介いたします。
ポイント1: 依存のキャッシュを行う
GitHub ActionsでPythonを利用する場合は通常 actions/setup-python@v5
を利用します。
これは cache: 'pip'
のようにパッケージマネージャーを指定すれば requirements.txt
などのパッケージ管理用のファイルに基づいて ~/.cache/pip
のようなディレクトリをキャッシュしてくれます。
現状は pip
pipenv
poetry
が指定可能で、uvには対応していません。( 対応のためのPR は作成されています )
そのため、自前でキャッシュを行う必要があります。
uvはパッケージのキャッシュ用のディレクトリとして ~/.cache/uv
を利用するので、そのディレクトリをキャッシュすることにします。
GitHub Actionsの公式ドキュメントには actions/cache
というアクションが用意されており、これを利用することでキャッシュを行うことができます。
pip用のsampleをベースに、 path
key
restore-keys
を書き換えてみます。
- uses: actions/cache@v3 with: path: ~/.cache/uv key: ${{ runner.os }}-uv-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-uv-
ポイント2: 仮想環境を利用しない場合は --system
を利用する
上記のキャッシュを設定した上で、 pip install
を uv pip install
にしようとしたらエラーになってしまいました。
error: Failed to locate a virtualenv or Conda environment (checked:
VIRTUAL_ENV
,CONDA_PREFIX
, and.venv
). Runuv venv
to create a virtualenv.
記事の上記で説明した通り、uvは .venv
ディレクトリを勝手に探して仮想環境へインストールしようとします。
詳しくはこちらに書いてあります。
上記リンクでも書いてある通り、コンテナー内やCI環境ではsystemのpythonにパッケージを追加したいことが多いため、その時のために --system
というオプションが用意されています。
それを利用する形で、以下のようにします。
- run: pip install uv && uv pip install --system -r requirements.txt
実際に導入した結果
それを踏まえると最終的に以下のようなstepをworkflowに組み込むとうまく動作するでしょう
- uses: actions/cache@v3 with: path: ~/.cache/uv key: ${{ runner.os }}-uv-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-uv- - run: pip install uv && uv pip install --system -r requirements.txt
実は今回対象としているリポジトリはmonorepoなので、実際はこんな感じのcomposite actionを用意し、各ディレクトリ向けのjobから呼び出す形になっています。
- uses: actions/cache@v4 with: path: ~/.cache/pip key: v1-${{ runner.os }}-uv-${{ hashFiles(format('{0}/{1}', (inputs.working-directory || env.WORKING_DIR), inputs.file-name)) }} - shell: bash run: | cd ${{ inputs.working-directory || env.WORKING_DIR }} pip install uv && uv pip install --system -r ${{ inputs.file-name }}
実際にPRを作成し、そこで発生するとあるWorkflowの実行時間をチェックしてみました。
チェックは、 GitHub Actionsの実行結果ログ画面の左下にある Usage
から開くことができます。
GitHub ActionsはRun timeとは別にBillable timeというものがあり、それぞれのjobを分単位で切り上げしたものを実際に課金対象として請求されます。
Run time | Billable time | |
---|---|---|
pip install (cached) |
37m 7s | 48m |
uv pip install |
17m 37s | 27m |
uv pip install (cached) |
14m 2s | 22m |
1コミットごとに発生するBillable timeが1 Workflow単体で見ても26分も節約することができました! 当然ですが、アジリティにも影響する重要な要素ですので、課金の節約以上に開発速度や開発体験の向上が期待できます!
まとめ
uvは新しいPythonの新しいパッケージマネージャーで非常に高速です。 uvをGitHub Actionsへの導入にあたってポイントが2つあります。
~/.cache/uv
をキャッシュする- ワークフローで仮想環境を利用しない場合は
--system
を利用する
新しいツールなので、CDの方にいきなり入れることを避けCIにだけ導入することで様子を見ている段階です。
導入することによってGitHub Actionsの課金額の削減やアジリティの向上といった良い影響があります。 ぜひ皆さんに利用していただきたいです。