tech.guitarrapc.cóm

Technical updates

GitHub Actions の setup-dotnet と ホストランナーの .NET SDK

GitHub Actions で .NET Core ビルドを行いたいときに利用するものといえば、setup-dotnet があります。

github.com

今回は Ubuntu-latest な環境で setup-dotnet がいる場合と、そうでない場合について考えてみます。

tl;dr;

  • GitHub Actions ホストランナーのデフォルト環境で .NET はビルドでき、最新が1-2週で入ってくるのでOSS はsetup-dotnet なしで十分。
  • プロダクトなど .NET SDK バージョンを厳密に制御する場合は、setup-dotnet を使うとよい。
  • setup-dotnet は global.json を読んでくれるので、バージョン固定するなら global.json 便利

GitHub Actions と ホストランナー

GitHub Actions のホストランナーは環境ごとに特定のツールがインストールされた状態になっています。 例えば、ubuntu-latest である Ubuntu 20.04 LTS 環境 なら、以下のツールが入っています。

github.com

2021年5月13日時点で .NET SDK は次のバージョンが入っており、かなり網羅されていることがわかります。 2.1 / 3.1 / 5.0 に関してはおおむね困らないでしょう。

2.1.300 2.1.301 2.1.302 2.1.401 2.1.402 2.1.403 2.1.500 2.1.502 2.1.503 2.1.504 2.1.505 2.1.506 2.1.507 2.1.508 2.1.509 2.1.510 2.1.511 2.1.512 2.1.513 2.1.514 2.1.515 2.1.516 2.1.517 2.1.518 2.1.519 2.1.520 2.1.521 2.1.522 2.1.523 2.1.602 2.1.603 2.1.604 2.1.605 2.1.606 2.1.607 2.1.608 2.1.609 2.1.610 2.1.611 2.1.612 2.1.613 2.1.614 2.1.615 2.1.616 2.1.617 2.1.700 2.1.701 2.1.801 2.1.802 2.1.803 2.1.804 2.1.805 2.1.806 2.1.807 2.1.808 2.1.809 2.1.810 2.1.811 2.1.812 2.1.813 2.1.814 2.1.815 3.1.100 3.1.101 3.1.102 3.1.103 3.1.104 3.1.105 3.1.106 3.1.107 3.1.108 3.1.109 3.1.110 3.1.111 3.1.112 3.1.113 3.1.114 3.1.200 3.1.201 3.1.202 3.1.300 3.1.301 3.1.302 3.1.401 3.1.402 3.1.403 3.1.404 3.1.405 3.1.406 3.1.407 3.1.408 5.0.100 5.0.101 5.0.102 5.0.103 5.0.104 5.0.200 5.0.201 5.0.202

このため、わざわざ setup-dotnet を使わずともdotnet cli は参照できますし、ビルドも可能です。 つまり、setup-dotnet を使わない場合、GitHub Actions のホストランナーに事前インストールされた複数の .NET SDK から必要なバージョンが参照されます。

setup-dotnet

setup-dotnet がやっていることは、「特定のバージョンの .NET SDK を azure feed からダウンロード、展開して参照できるようにする」ということです。

GitHub ホストランナーは Prerelease の .NET SDK には未対応で、ホストランナーの環境更新も 1週間に一度程度なので待ってられないというケースが稀にあります。 そんなときsetup-dotnet は Prerelease にも対応しており、まだfeed に乗っていないリリース直後の .NET SDK バージョンを利用するときに便利です。

f:id:guitarrapc_tech:20210520024025p:plain
GitHub Actions ホストランナーUbuntu 20.04 LTS の環境更新頻度

また、setup-dotnet はバージョン省略時にglobal.json があればそのバージョンを読む機能もあります。global.json と CI のバージョン固定なら global.json でいいというのはあるので、これはこれで便利です。(global.json の配置場所がリポジトリルートではない場合は少しアレってなりますが)

    if (!version) {
      // Try to fall back to global.json
      core.debug('No version found, trying to find version from global.json');
      const globalJsonPath = path.join(process.cwd(), 'global.json');
      if (fs.existsSync(globalJsonPath)) {
        const globalJson = JSON.parse(
          // .trim() is necessary to strip BOM https://github.com/nodejs/node/issues/20649
          fs.readFileSync(globalJsonPath, {encoding: 'utf8'}).trim()
        );
        if (globalJson.sdk && globalJson.sdk.version) {
          version = globalJson.sdk.version;
        }
      }

setup-dotnet/setup-dotnet.ts at bf3c3eb1fdba530a22805f082a2dcebc125d6ce4 · actions/setup-dotnet · GitHub

setup-dotnet の副作用

さて、この記事をここまで読んでいる人は「setup-dotnet を使うとインストールした以外の SDK が使えなくなる」という状況になったことがあるのではないでしょうか? ホストランナーの環境には、複数の .NET SDK が入っているにも関わらず、です。

これは setup-dotnet が、SDKのインストール時に .NET SDK の参照ルートパスを ホストランナーのデフォルトパス /usr/bin/dotnetから setup-dotnet で入れたSDK のパス $HOME/.dotnetに切り替えているために起こります。 結果、 setup-dotnet でインストールした以外のSDK バージョンは参照できなくなります。 .NET SDK のルートパスは、環境変数 DOTNET_ROOT に任意のパスを設定することでサクッと切り替えることができます。というのが気付きでした。便利。

setup-dotnet は installer.ts でこれを設定しています。

        // 184 行目
        core.exportVariable(
          'DOTNET_ROOT',
          path.join(process.env['HOME'] + '', '.dotnet')
        );

setup-dotnet/installer.ts at bf3c3eb1fdba530a22805f082a2dcebc125d6ce4 · actions/setup-dotnet · GitHub

実際に GitHub Actions で .NET SDK の参照パスと利用可能バージョン一覧を見てみましょう。 setup-dotnet を利用する前は、標準の/usr/bin/dotnetが利用されています。

f:id:guitarrapc_tech:20210520025106p:plain
GitHub Actions ホストランナーデフォルトの .NET SDK 状態

setup-dotnet を利用すると、パスが /home/runner/.dotnet/dotnet になり、利用可能な SDK も限定されていることがわかります。

f:id:guitarrapc_tech:20210520025301p:plain
setup-dotnet利用後の.NET SDK の参照パスと利用可能バージョン一覧

まとめ

一見すると、setup-dotnetを使うとめんどくささが増えてメリットがスポイルされているように見えます。 しかし、プロダクトなど厳密に .NET SDK のバージョンを管理したい場合は、setup-dotnet を使うのは合理的でしょう。 一方で、基本的にホストランナーには最新バージョンの.NET SDKが入っているので、OSS では 脆弱性情報などの対応を除き ホストランナーのデフォルトで十分というのは言えそうです。

  • setup-dotnet を使うと、.NET SDK preview や任意の.NET SDK をインストールができる。
  • setup-dotnet を使うと、デフォルトの .NET SDK のパスから、setup-dotnet でインストールした .NET SDK のパスに変更されるため、ホストランナーのデフォルト .NET SDK 達はパス省略で使えなくなる。

今日の学びでした。