paild tech blog

法人カードのクラウド型発行・管理サービスpaild

RustにおけるGitHub Actionsベストプラクティス

こんにちは大櫛です。Travis CIがオープンソースプロジェクトで使いづらくなったり、Azure PipelinesからGitHub Actionsになった途端*1爆発的な流行が生まれたりと、CIサービスにおいてもここ数年で色々な動きがありました。 特に技術記事・ブログのトレンドや企業のリクルート向け資料を見ていると、GitHub Actionsの利用が進んでいるような印象を受けます。 今回はそんなGitHub Actionsについて、Rust projectで使う際に知っておいた方がいいことやactionを紹介していきます。 以下の情報は執筆時点(2023-02-19)のものに基づいています。閲覧時には無効・誤ったものになっている可能性がありますので、必ず最新の情報・状態を確認するようにしてください。

actions-rs(非推奨)

まずはじめに、執筆時点では使用を控えた方がいいaction群であるactions-rsについて紹介します。

GitHub Actions黎明期にtoolchainやClippy、code coverage部分を簡単に扱うための存在として、actions-rsが登場しました。 特にClippy actionは該当部分にアノテーションをつけてくれるなど体験がよいため、rust-lang organizationをはじめ多くのRust projectで採用されていきました。

ただしactions-rsのメンテナはsvartalf氏ただ一人であり、氏が2022年以降インアクティブになっていることでいくつかの問題が発生しています。 GitHub Actionsは現在いくつかのdeprecation noticeを出しており、それらの影響をactions-rsが受けているのです。

issue trackerに起票されPRも提出されていますがmergeされる気配はありません。 - https://github.com/actions-rs/toolchain/issues/221 - https://github.com/actions-rs/cargo/issues/216

これらは今後動作しなくなることが決定・検討されているため、利用者は該当actionの利用をやめるか、動かなくなる前にメンテナが帰ってくることを祈るほかありません。 前者の一つとして、forkしたものに自分たちで手を入れるというのも考えられますが、本当に必要なのだっけという検討をするのも手でしょう。 例えば actions-rs/toolchain でnightly toolchain+Clippyをインストールしている場合、以下のように書き換えることができます:

run: |
  rustup set profile minimal
  rustup install nightly
  rustup override set nightly
  rustup component add clippy

GitHub hosted runnerにはrustupがpre-installされているため、インストールステップを追加することなく書き換えが可能です。 useswith を組み合わせてconfigを用意する方が見栄えよく管理できるという話もありそうですが、runベタ書きでも目的を達成できる部分はそのようにしておくと下手に依存関係をつくらずに済むので、一考の余地があるでしょう。

注意すべき点として、先に述べたようにRust communityで広く使われていた背景があるため、いろいろなactionのexample usageとしてactions-rsのactionが記載されている場合があります。 コピペする際には留意しておくべきでしょう。

dtolnay/rust-toolchain

それでもシュッとtoolchainをインストールしたいんだという方には https://github.com/dtolnay/rust-toolchain がおすすめです。 serdeのライブラリのコア開発者・Rust projectのライブラリチームメンバーとして知られるdtolnay氏謹製で、例えばstable toolchainをインストールしたい場合には以下のようにone-lineで記述できます:

- uses: dtolnay/rust-toolchain@stable

各versionやrelease channelなどのブランチをそれぞれ用意するという荒業でone-lineでの記述を可能にしています。componentの追加やtargetの指定ももちろん可能です。 また、以下のような記述も可能です:

# Installs the stable toolchain which preceded the most recent one by
# the specified number of minor versions.
- uses: dtolnay/rust-toolchain@master
  with:
    toolchain: stable minus 8 releases

これはビジネスユースでは特に必要な場面が思いつきませんが、ライブラリメンテナがMinimum Supported Rust Version(MSRV)を設定する際には有用そうです。

Swatinem/rust-cache

少し昔話をしましょう。 GitHub Actionsは現在cachingをサポートしていますが、当初はサイズリミットが厳しくRust projectで利用するのは現実的ではありませんでした。 が、リミットが緩和されたり圧縮形式が改善されたりしたことにより、今では多くのプロジェクトで支障なく利用できるまでになっています。有難い話ですね。閑話休題

さてそんなcachingですが、actions/cacheのexampleでは直接いくつかのパスを対象とするやり方が紹介されています。この他に、より高度なcaching strategyを持つactionが存在します。

それがSwatinem/rust-cacheです。 cache keyを特に気にしないのであれば- uses: Swatinem/rust-cache@version一行の記述でcachingを行えます。 cache keyを指定しない場合はworkflowのjob_idや使用しているtoolchainのrelease channelからkeyを自動生成してくれます。 またcacheする前に使用されなくなった依存関係をはじめとする不要な成果物のclean upを行ってくれるため、キャッシュサイズの不要な肥大化を防いでくれます。 caching strategyはプロジェクトごとにfine-tuneする余地もあるでしょうが、最適まではいかずともコスパよくcachingしたいという場合には有効なactionです。

giraffate/clippy-action

https://github.com/actions-rs/clippy-check はannotationを付与してくれるため、PR上でClippy warningsを確認するのに有用です。 ですが先ほど紹介したようにこのactionにはいくつか問題があるため、新しいプロジェクトで使うには向いていません。 その代替として、giraffate/clippy-actionを紹介します。

機能的にはactions-rs/clippy-checkと似ているのですが、reporting部分にreviewdogを使用しておりannotationだけでなくreview commentとしてwarningを表示することが可能です。annotationよりも直接的にreportしてくれるので、optionとしてとても便利そうです。

taiki-e/install-action

binary cratesをインストールする際にはcargo install foo-crateをすれば簡単にビルド・インストールできます。開発ツールとして何らかのCargo subcommandとなるbinary crateをインストールする機会も多いでしょう。 ただしcargo installはビルドを自前で行うため、pre-built binaryさえあればいい場合などには不必要にCI時間をかけてしまうことになります。 https://github.com/cargo-bins/cargo-binstall はこれをCargo subcommandとして解決してくれます。とても便利です。 そしてそれをGitHub Actions上で使いやすくしたものが https://github.com/taiki-e/install-action です。とてもとても便利です。

このactionはsupported toolsについては事前に定義された方法で、それ以外のtoolの場合はbinstallにフォールバックしてインストールを行います。 supported toolsについてですが、binstallはcrate metadataをパースして最適なインストール処理を見つけ実行するという設計になっている都合上、インストール手順が常に同じではありません。supported toolsを設けることでこの問題をある程度解消しているのだと推察できます。

例えばmdBookをインストールしたい場合には以下のように記述できます:

- uses: taiki-e/install-action@mdbook

また、特定のバージョンがほしい場合には以下のように記述できます:

# You can also omit the minor version if the major version is 1 or greater.
- uses: taiki-e/install-action@v2
  with:
    tool: cargo-hack@0.4.27

taiki-e/install-actionの嬉しいポイントの一つとして、tlsv1.2+の利用やデフォルトでchecksumの確認を行ってくれるというものがあります。 サプライチェーン攻撃への懸念が叫ばれる昨今ですから、(上記だけですべての心配を払拭できるわけではないにせよ)この辺が意識されているのは有難いものです。

まとめ

以上、個人的におすすめする・しないactionについて紹介しました。

Rustまわりに限った話ではありませんが、actions-rsの一件にあるようにサードパーティのものを使用する際は定期的に様子を見ておくのがよさそうです。 特にCI/CDはcredentialsを直に触る機会が多いため、個人的には注意してもしすぎることはないと思っています。 また、actionを使用すると体験が向上する一方他CIサービスへの移行を難しくしてしまう恐れもあります。 この辺りの兼ね合いを考慮しつつ設計を行うのはプロジェクトによりけりで悩ましい部分もあるでしょうが、生産性向上のため避けては通れない道であることも多々あります。

今回の記事を参考にしつつ、皆様が快適なCI/CDライフを過ごせることを祈っております。