tech.guitarrapc.cóm

Technical updates

WSL1 から WSL2 の対応

WSL1 を長い間使っていましたが、先日 Windows 10 Version2004 がリリースされて WSL2 に切り替えを行いました。

WSL2 いいのですが、WSL1 と同じように、あるいはちょっと欲張ろうと思うと少し困ったのでメモ。

目次

TL;DR

Windows 10 May 2020 Updateがリリースされてから2週間使ってますが、もう WSL1 に戻る気はないぐらいには気に入っています。おすすめです。 具体的には、

  • 👍: WSL2 にして apt/pip3 が爆速になってうれしい
  • 👍: WSL1 とおおむね使い勝手は変わらず、WSL2上のdockerでボリュームマウントが可能になってよかった(標準的なLinuxとみなせるようになった)
  • 🙅: WSL2 の Windowsボリュームのアクセスはとても遅くなった
  • 🙅: Windows のシステムボリュームは余計に食うようになったので 50GB 程度空きは欲しい (あるいはOSリセットすると減るはず)

kubernetes 周りに関しては、特段変化を感じません。

WSL1 で何をしていたのか

WSL1 では、Ubuntu 18.04 を動かして、中でアプリケーションやインフラにかかわるツールを動作させていました。 Docker でもいいのですが、普段使いのツールや、Windows でマウントしているファイルを(EOLを含めて) そのまま Linux で動作させたときの動作もサクッと確認できるのがいいのです。

  • dotnet core SDK
  • golang
  • cmake
  • Kubernetes (kubctl/helm/kubesec/sops...)
  • terraform
  • docker/docker-compose
  • aws cli/azure cli
  • jq/yq
  • sed 他

docker とWSL の使い分けはそのカジュアルさです。 WSLは、bash と入力するだけでほぼ Linux とみなせるインタラクティブな環境に行けるので、普段使いのUbuntu 環境に利用しています。多少無茶な使い方をしても、アンインストールして store から入れなおせばフレッシュになるので壊せる開発環境という感じです。 一方のdocker は、アプリ動作環境を閉じ込めるためや、特定のソフトウェアの挙動、壊れるだろうという操作やシステム設定の変更など戻すことがめんどくさいことをするときに使っています。

WSL2 で何をするのか

基本的な利用目的は変わりません。手軽にさくっと Linux 環境として Ubuntu を利用します。 WSL1 から WSL2 に変化することで期待したのは、ディスクIOです。 概ね事前にやっていた結果と Windows 10 Version 2004 における WSL2 に違いはなく、WSL1 に比べて ext4 上でのディスク書き込みの速度が上がりました。 具体的な変化は次の通りです。

  • apt update|instal が爆速になる
  • pip3 も爆速化
  • Windows マウントファイルへのアクセスは非常に低速に
  • WSL2上のDockerでボリュームマウントが可能になった

ディスクアクセスの改善は顕著です。具体的なシチュエーションだと、apt update/install に関しては、これまでUbuntu 18.04 を入れた後に実行すると10min 程度食うのを覚悟していたものが1min 程度になっています。pip3 も同様です、ansible 入れてみてください。 ただ、Windows のマウントディレクトリ ( /mnt/c など) でのファイル操作はけた違いに遅くなりました。(知ってた) そのため、例えばdocker-compose で Windows のフォルダを WSL2 からマウントするのはものを選びます。100MB を超えるdocker転送は永遠に終わらない気分になります。(node_modules とかつらい)

Windows のパス上からそのまま bash で WSL2 を起動する流れは変わらないものの、大き目なファイルサイズを伴う docker-compose に関しては Windows上で扱うか、ext4 上に git clone するのがいいでしょう。

しれっと書きましたが、WSL2ではWSL上のファイルをWSLのdockerにボリュームマウントできるようになっています。WSL1 では、WSL 上のファイルを WSL上で実行した docker にボリュームマウントできず、ふとしたdocker操作で挙動が違って無駄に時間を費やすことがありましたがなくなりました。最高です。

WSL2 への対応

WSL1 の環境を WSL2 にするにあたり、どのような対応をしたかメモしておきます。

Windows システムボリュームの利用が増えた

WSL1からWSL2にすると、Docker Desktop (35GB)、wsl (9GB)、Ubuntu 18.04(5GB) で 約50GB余計にシステムボリューム(C:) を利用するようになってしまいました。

デスクトップは長い間 256GB M.2 SSD (Samsung SSD 950 Pro) でやっていましたが、WSL2 にして残り 1.8MB になったためシステムボリュームを 1TB NVMe に差し替えました。 Crucial は 最近P2 が出ましたが、ちょっと試してみたかった P1 で。

https://www.crucial.jp/catalog/ssd/p1www.crucial.jp

なお、Windows.old を含めてゴミを消しても容量はすぐに埋まりきりがなくなったので仕方ない。

qiita.com

なお、Windows 10も入れなおして開発環境、WSL2を組みなおしたところ利用容量が 76.1GB になったので、まぁそんなものです。知ってた。(だから 256GB で過ごせていた) Windowsの入れ直しは、Media Creation Tool で Windows 10 May 2020 Update で USBブートを作るのが今も安定でした。

Windows Features が不要に

幸いなことに、 Docker Desktop for Windows をインストールすると WSL2 周りは一通り入ります。(Kernel のぞく) そのため、これまで Enable-WindowsOptionalFeature でインストールしていた Microsoft-Windows-Subsystem-Linux、Hyper-V は不要になりました。

https://github.com/guitarrapc/local-provisioner/compare/wsl1...604c08d7313060c681fc2ecb91d9839df7056ccf#diff-500458443dc2514ec7bec4fde7ce776eL1-L25

脱Hyper-Vは、Windows 10 Home でも利用できるようになっていますし最高ですね。(Virtual Box とかも動くし)

tech.guitarrapc.com

WSL OS

WSL2 でも、現状は Ubuntu 18.04 を使っています。 折を見て Ubuntu 20.04 に切り替えていきますが、まずは変化を見たいので変えていません。

Provisioning

WSL1 と変わらず、WSL2 においても ansible を使って環境を構築しています。 私の場合は、Windows / macOS / Ubuntu を各種環境を利用するので、全環境に対してこのリポジトリの内容を当てています。

github.com

Ubuntu 18.04 においては、WSL1/WSL2であっても ansible で当てています。 Diff は次の通りです。

https://github.com/guitarrapc/local-provisioner/compare/wsl1...724dad71fd0852173e10fbca4a961eec92db2710

いくつか初期化回りの変更をメモしておきます。

dockerの入れ直しをやめた

docker は、WSL1 においては docker.io の公式同様に入れなおしていましたが、WSL2 においてはデフォルトから変更していません。

-    - { role: "docker", tags: [docker] }
+    #- { role: "docker", tags: [docker] }

https://github.com/guitarrapc/local-provisioner/compare/wsl1...604c08d7313060c681fc2ecb91d9839df7056ccf#diff-b905abb381284c6c36b4ac2b6dc30641L24-L25

また、bashログイン時の起動も止めています。

- sudo -S cgroupfs-mount
- sudo usermod -aG docker $USER
- sudo service docker start
- # wsl1 using windows docker-compose. wsl2 don't need this line.
- # export DOCKER_HOST=tcp://localhost:2375 

https://github.com/guitarrapc/dotfiles-linux/commit/db47ddf5c1ba8400acb502b256c8a03bbcb5749b

WSL2でdocker の入れ直しをやめたのは、docker の入れ直しを行うことで Windows 上の Docker for Windows のイメージと WSL2 上のイメージ一覧が同期されなくなったためです。(Windows はWindows、WSL2 の UbuntuはUbuntu と個別にイメージを持つようになってしまった。)

# この結果を Windows と WSL で共有する
docker image ls

WSL2 を使うにあたって、Windows の状況がそのまま利用できるメリットを手放す理由は相応のものがない限り薄く、特に docker に関しては同じイメージが使えるのが最高なのでdocker の入れ直しはやめました。

systemd/snap

当初wsl2 なら snapも行けるしと思って試していた形跡があります。が、結局 snap使っていません。(また使えるようにファイルは残しています) 実際 systemd/snapd を動かして、snap 経由でのインストールも可能になりましたが、以下の理由で辞めています。

  • kubectl は意図通り snap のほうが楽だった
  • snap で差し替えたかった pip3 の snap ファイルが欲しいものではなかった
    • 具体的には ansible が公式がなく個人のパッケージは python2 版
  • Windows から bash や wsl で WSL2 を起動したときに、$HOME に移動するようになってしまう
    • WSL2 は、wsl や bash で Ubuntu に入ると Windows のパスのまま維持しますが、snap 対応を入れたスクリプトでのログインしなおしでパスが $HOME になってしまう

snapを使うことでバージョニングを楽にインストールをしたいと思ったのですが、なかなか難しいようです。 現状あんまり snap に頑張る気もないので、やめました、はい。

Windows パスの分離

WSL2 は WSL1 同様に、標準では Windows のPATH が $PATH に入ってきます。 これにより、WSL2 上で code . とすることで Remote WSL がVS Code で使えたりします。(~/docker.cfg も Windows の docker cred のパスが入っています)

Windows PATHがWSLで使えるのはすごく便利なのですが、WSL1 で Windows のパスとWSLのパスが競合してWSLでアプリ動作がおかしくなった経験があります。 そのため、 /etc/wsl.conf でPATH を停止しています。

[interop]
appendWindowsPath = False

wsl.conf をおいて、 wsl --shutdown を実行することでWSL上で Windows のパスが入らなくなります。

$ echo $PATH
/home/guitarrapc/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/guitarrapc/.dotnet/tools

まとめ

おおむねWSL2 にして幸せになります。 ディスク容量は明らかに食うようになるので、私は割り切ってシステムボリュームを1TB まで増やしてわずらわしさを感じないようにしました。 ただ、ラップトップでなくても、PCのシステムドライブはそれほど大きくないことも多いので要注意な感じがあります。

Windows 10 Home を Windows 2019 Server on Azure で Nested Hyper-V にインストールする

Windows 10 Home の WSL2 + Docker を検証するための環境を考えた時、Windows 10 Pro の Hyper-V にいれるのが手っ取り早いのですが、CPU仮想化支援の有効化コマンドレットに気づかず Windows Server 2019 上の Windows 10 Home じゃないとダメだっけと思ってさまよった時のメモ。

結果は VMのCPU仮想化支援を有効にすればどちらも変わらず動作する。

前の記事の前段となる個人的なメモです。ローカル環境が Windows 10 Home の人が環境を汚さずやるにはいいのでは。

tech.guitarrapc.com

目次

[:contens]

TL;DR

  • Windows 10 Home を Nested Hyper-V で動かす
  • Windows 10 Home on Hyper-V と変わらなず wsl2 + Docker Edge は動作する (Hyper-V の Windows 10 Home VMのの CPU 仮想化支援を有効にしよう)
  • Insiderビルドが長すぎるのでWindows 2004、あらためWindows 10 May 2020 Update はよ、ふたたび

前提

  • Dv3 or Ev3 が必要

Azure Virtual Machines で入れ子になった仮想化を有効にする方法 | Microsoft Docs

VMの構成

久々に terraform を使わず Azure Portal を確認してみます。 いつの間にか スポットインスタンスができるようになってて感動した。

適当に Resource Group を作っておきます。

  • Windows Server Gen2 Preview のイメージで Windows Server 2019 とする
  • Spot Instance
  • D4s_v3
  • Standard SSD

全部できるとリソースこんな感じ。

Nested Hyper-V の準備

Install-WindowsFeature -Name Hyper-V -IncludeManagementTools -Restart

再起動後に VM Swtich の構成

New-VMSwitch -Name "InternalNAT" -SwitchType Internal
$ifIndex = (Get-NetAdapter |where Name -match InternalNAT).ifIndex
New-NetIPAddress -IPAddress 192.168.0.1 -PrefixLength 24 -InterfaceIndex $ifIndex

NAT Network の構成

New-NetNat -Name "InternalNat" -InternalIPInterfaceAddressPrefix 192.168.0.0/24

Hyper-V を開いてVMの構築。この時Network は Internal NAT を向ける

Hyper-V はサクッと。NAT 指定だけ忘れずに

Windows 10 Home ISO を用意

MediaCreationTool1909 を入れる。IE がアレなので curl で落とす。

https://www.microsoft.com/ja-jp/software-download/windows10

curl -L  https://go.microsoft.com/fwlink/?LinkId=691209 -o MediaCreationTool1909.exe

ISO を設定

Boot Order を修正して ISO 起動できるようにする

あとは Windows 10 Home を入れる。

DHCP Server を Azure VM に用意

Azure VM 上の Nested Hyper-V ということは DHCP ないので、適当に Windows Server 2019 から DHCPを Internal NAT に配布します。

Install-WindowsFeature -Name DHCP -IncludeManagementTools

DHCP ツールを起動して、IPv4に新規スコープを追加し、 192.168.0.100-200/24 を設定

デフォルトゲートウェイに InternalNAT の 192.168,0.1 を指定

これで Hyper-V の VM を起動したり、ネットワークアダプターの無効/有効でIPが取得される。

残り

Windows 10 Home on Hyper-V (Windows 10 Pro) と同じ。

tech.guitarrapc.com

用が済んだら Resource Group ごとぐっぱい。Terraform 以外で作るの久々で相変わらずめんどくさかった。

Windows 10 Home を Hyper-V にインストールする

Windows 10 Home の WSL2 + Docker を検証するための環境を考えた時、Windows 10 Pro の Hyper-V にいれるのが手っ取り早いのですが久々に Hyper-V 触ったので改めてメモ。

前の記事の前段となる個人的なメモです。ほしい内容は自分で書くしかない。

tech.guitarrapc.com

目次

[:contens]

TL;DR

  • Windows 10 Home を Hyper-V で動かす
  • Windows 10 Home on Hyper-V でも wsl2 + Docker Edge は動作する (Hyper-V の Windows 10 Home VMのの CPU 仮想化支援を有効にしよう)
  • Insiderビルドが長すぎるのでWindows 2004、あらためWindows 10 May 2020 Update はよ

Windows 10 のISO を入手する

Media Creation Tool で Windows 10 の ISO を生成する。

Windows 10 のダウンロード

2020/4/17 時点では、Windows10 1909 の生成ができる。

この記事では最新のMediaCreationTool1909 を用います

Hyper-V でマウントするためISO を作る

Single Language Windows でISOが作成されるので、Language を選んでおく。 今回は English (United Kingdom)

日本語でもなんでもお好きに

これでISOが生成される。

Windows 10 を Hyper-V にインストール

Hyper-V で新規VM を作成する

この辺りはコマンドでもいいけど GUI でいいや気分

先ほどのISO を指定して起動する

Local Installation source から Change Install source で ISO を指定

VM名を付けて生成したら起動する。

Windows 10 Home を選ぶ

ライセンスを入れる。

ここでライセンスを入れないとエラーになるので注意。

ライセンスを skip しようとするとエラー

Custom でインストールする。

Upgrade でも Custom でもどちらでもいい

Custom だとパーティションが設定できるけど Hyper-V なのでどうでもよし

インストールが実行される

何度か再起動がかかる

起動してきたら Region を選択

Keyboard を選択

Second Keyboard は不要なので skip

起動を待つ

再起動が走り、ユーザー選択になる。

Local User でのセットアップはできず、起動後に削除しろと言われる。

ローカルユーザーを作成するには、ネットワークを切って新規でユーザーを作ろうとすることで作成できる。(分かりにくい)

まずネットワークを切ろう。

VM の Settings から Network Adator を開く

Virtual switch を Not Connected に変更する。

Create account から ユーザーを適当に作ろうとすると Womething went wrong となる。

ここで Skip を選択すると ローカルアカウントで作成できる。

Insider Preview でどのみち Microsoft アカウントが必須なのでローカルアカウントの意味は薄い

あとはセットアップをしていく

これで起動する。

起動後の設定

  • ネットワークを戻す
  • Language で日本語を入れておく
  • システムロケールの日本語設定とUTF8化
  • Image の Checkpoint を作っておく
  • ホストマシンからVMのCPU 仮想化支援機能を有効にする

ネットワークを戻す

日本語を入れる

OSは英語だけど日本語ほしい人はストアからどうぞ

表示を日本語に切り替える

サインアウトして完了

システムロケールの日本語設定とUTF8化

Hyper-V Image の Checkpoint を作る

後でやり直せるようにしておく。

ホストマシンからVMのCPU 仮想化支援機能を有効にする

Hyper-V ホストマシンで Set-VMProcessor コマンドレットを使って、ExposeVirtualizationExtensions を $true にする。 これで、Hyper-V 上の対象VM で wsl2 + Docker Desktop for Windows が利用可能になる。

Set-VMProcessor -VMName "VMName" -ExposeVirtualizationExtensions $true

Windows 10 Home で WSL2 と Docker Desktop for Windows を動かす

開発環境では Docker で DB や各種バックエンドを動かすことが多いのですが、WFH が広がる中で自宅が Windows 10 Home で Docker Desktop for Windows 起動できないんだけど、何か手がないかと相談があったりなかったり。

以前試したときは問題なかったのですが、改めて最新の状況で試します。 また、wsl2 の仕組みから言って Hyper-V でホストしたWindows 10 Home でも動作するはずなのでそこも確認です。

Hyper-V に Windows 10 Homeをインストールしているのでその検証結果も知りたい人にも向けていいのではということで。

目次

更新履歴

  • 2020/5/17: Docker Stable に WSL2 対応がきたのを確認したのでEdge限定の記述を修正
  • 2020/5/28: Windows 10, version 2004 がきたので、Insider Preview の記述を修正

TL;DR

  • Windows 10 Version 2004 (2020 May Update)がGA されました。るまでは Insider Preview (Slow Ring でok) が必要
  • Docker Desktop fo Windows は Stableでok Edge が必要(Stableはよ)
  • wsl2 上の Linux ディストロで Docker を動かすのはまた別に

WSL2について

Docker Desktop for Windows をインストールする

* Insider Preview を有効にする (Slow Ring)

  • Windows Update で Windows 10 2004 にあげる
  • Windows Subsystem for Linux の有効化をしてWSL2を使う
  • Docker Desktop for Windows をインストール (Edge)

この時点で Windows バージョンは 1909

Insider Preview 前の Windows 10 バージョンは 1909

Insider Preview を Slowring で有効にする

2020/5/28 以降は、Windows Update で降りてくるので Insider Preview が不要です。

Insider PreviewをSlow Ring で有効化

適当に Microsoft アカウントを作成

Insider Preview の有効化 (ここでずっと変わらない場合がある)

Slow Ring を選択

Windows Update で Windows 10 2004 にあげる

Docker Desktop を Windows Home に入れるには、19018 以上である必要があるのでWindows Update をかける。 2時間近く時間がかかるので注意。

Windows Update を実行して Windows 10 Version 2004 にアップデート

これで Windows 10 Version 2004 となる。

Windows 10 バージョン 2004 を確認

Windows Subsystem for Linux の有効化をしてWSL2を使う

Docker for Desktop で実施されるので実行する必要がありません。もしもDocker Desktop for Windows をインストール後に間違って無効にした場合にぐらいしか使わない。

Windows Subsystem for Linux と Vitrual Machine Platformを有効にするため、Windows PowerShell を管理者で起動して、コマンドを実行。

Get-WindowsOptionalFeature -Online | where FeatureName -match linux | Enable-WindowsOptionalFeature -Online -NoRestart
Get-WindowsOptionalFeature -Online | where FeatureName -match virtual | Enable-WindowsOptionalFeature -Online

Windows 10 の機能を有効化

再起動される。

再起動される

wslコマンドが利用可能になっている。ディストロはインストール不要。

$ wsl -l
Linux 用 Windows サブシステムには、ディストリビューションがインストールされていません。
ディストリビューションは Microsoft Store にアクセスしてインストールすることができます:
https://aka.ms/wslstore

Docker Desktop for Windows をインストール

https://hub.docker.com/editions/community/docker-ce-desktop-windows/

記事公開時点は Edgeが必須でしたが、Stable にきたので Stableでokです。

リンクからDocker アカウントなしでEdgeをダウンロード

Edge なら Windows 10 Home でも 19018+ でインストール可能

もしWindows Update をかけていないと、Docker Desktop のインストールがコケる。

Docker Desktop requires Windows 10 Pro/Enterprise (15063+) or Windows 10 Home (19018+)

Windows 10 2004 になっていれば、WSL2 の有効化を効かれるのでそのままOK。

Enable WSL 2 Features は必ず有効にする

インストール後は再起動する。

再起動後に wsl2 のインストールが完了していないことが言われる。

wsl2 の有効化

Linux カーネル更新プログラムパッケージを入れる。

https://aka.ms/wsl2kernel のダウンロードから。

これで wsl2 が有効になる。

PC を再起動して、docker-desktop が見えるようになる。

$ wsl -l

左が Windows 10 Home on Hyper-V on Windows Server 2019 on Azure VM、右が Windows 10 Home on Hyper-V on Windows 10 Pro

ついでに wsl2 をデフォルトバージョンにしておく。

$ wsl --set-default-version 2

Docker の実行確認

実行できるか確認する

docker run --rm hello-world

どちらの環境でも docker run が可能

ボリュームマウントも問題ない

ボリュームマウントも問題なし

Docker の設定

ドライブ共有が不要になった

従来の Docker Desktop for Windows では ホストマシンとコンテナのドライブ共有が必要だったが、これは不要になった模様。 実際、なにもしなくてもボリュームマウントされた。Firewall や アンチマルウェアとのバトルがなくなってめでたい。

ボリュームマウントメニューがなくなった

Hyper-V 上の Windows 10 Home はだめなの?

問題なく動作する。 Windows 10 Pro 上の Hyper-V で Windows 10 Home をいれても wsl2 + Docker 動かすこともできるし、Azure 上のWindows Server 2019 上で Nested Hyper-V の上に Windows 10 Home をいれても wsl2 + Docker を動かすことができる。

もし CPU 側の 仮想化支援を有効にしていない場合、Windows 10 Home on Hyper-V on Windows Pro も Windows 10 Home on Nested Hyper-V on Windows Server 2019 (Azure) も動作しない。

Hyper-V や 物理マシンの Windows 10 Home で Dockerの起動が失敗する例

これが出た場合は、Hyper-V ホストマシンで Set-VMProcessor コマンドレットを使って、ExposeVirtualizationExtensions を $true にし忘れている。

Set-VMProcessor -VMName "VMName" -ExposeVirtualizationExtensions $true

物理マシンなら UEFI で CPU のAdvance メニューあたりに設定があるはず。

CircleCI 上で dotnet test の verbosity がオーバーライドできない問題とその対処

CircleCI で dotnet test、妙な挙動をすることは前回1つ紹介しました。

tech.guitarrapc.com

が、まさかまた1つネタが見つかるとは思わなかったです。

今回は dotnet test がこけた時の出力について。

更新

2020/6/17 本件の修正がマージされて修正されました。やったね。

github.com

目次

TL;DR

  • dotnet test< /dev/null を付けると出力も正常になる

まさかのこれと同じ対策で解消します。

tech.guitarrapc.com

問題

問題は2つあります。

  • CircleCI 上で dotnet test をしたときに、verbosity が quiet として実行される。(dotnet test のデフォルトverbosity は minimal)
  • CircleCI 上で dotnet test のConsole Logger の verbosity をオーバーライド指定して実行しても quiet から変わらない

dotnet test のおさらい

問題を把握するためには、dotnet test の基本的な挙動を把握しておく必要があります。 ざっくり説明します。

ローカルで適当に xUnit のプロジェクトを作って、適当に失敗する Factを作りdotnet test で実行すると、テストの失敗個所が表示されます。 このテストの失敗個所が表示されるのは、verbosity レベルが minimal 以上の時で、dotnet test はデフォルトで minimal に設定されています。

$ dotnet test

Test run for C:\git\guitarrapc\dotnet-test-lab\tests\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v3.1)
Microsoft (R) Test Execution Command Line Tool Version 16.3.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:01.61]     XUnitTestProject1.UnitTest1.BoolFailTest [FAIL]
  X XUnitTestProject1.UnitTest1.BoolFailTest [7ms]
  Error Message:
   Assert.False() Failure
Expected: False
Actual:   True
  Stack Trace:
     at XUnitTestProject1.UnitTest1.BoolFailTest() in C:\git\guitarrapc\dotnet-test-lab\tests\XUnitTestProject1\UnitTest1.cs:line 33

Test Run Failed.
Total tests: 4
     Passed: 3
     Failed: 1
 Total time: 2.9317 Seconds

この結果の解像度をオーバーライドすることは、dotnet test 自体、あるいは Test Loggerごとに設定可能です。

  • dotnet test 自体のverbosity をオーバーライドするなら--verbosity 引数を使って dotnet test --verbosity [quiet|minimal|normal|detailed] を指定します
  • dotnet test の特定のテストロガーをオーバーライドするなら --logger:ロガー名;verbosity=[quiet|minimal|normal|detailed] を指定します

dotnet test 自体のverbosity を上げると、ビルドログなど見たくないログも増えてしまうのであまり好まれないと思います。 そのため通常は、Consoleロガーのverbosity だけ挙げて対処するでしょう。

たとえばConsoleLoggerのverbosity を normal にするならこのように指定します。 normal にしてお手元で実行すると、今まで dotnet test で出力されていなかった1つ一つのテストが成功、失敗にかかわらず出力されるはずです。

dotnet test "--logger:Console;verbosity=normal"

このことから、押さえておくべきは2つです。

  • dotnet test をverbosity 指定なしに実行したときは minimal を期待している
  • もし verbosity がちがった場合でも、--logger:console;verbosity=minimal などでオバーライドできることを期待している

何が問題なのか

CircleCI 上でローカルと同じように dotnet test を実行すると、失敗したテストの詳細が表示されないことに気がつきます。 これは verbosity が quiet の時の表示と合致し、ローカルでも dotnet test --verbosity quiet とすると再現します。 つまり、指定していないのになぜか verbosity がminimal ではなく quiet になっています。

$ dotnet test -c Debug

Test run for /root/project/tests/XUnitTestProject1/bin/Debug/netcoreapp3.1/XUnitTestProject1.dll(.NETCoreApp,Version=v3.1)
VSTest: Starting vstest.console...
VSTest: Arguments: dotnet exec /usr/share/dotnet/sdk/3.1.100/vstest.console.dll --testAdapterPath:/root/.nuget/packages/coverlet.collector/1.2.0/build/netstandard1.0/ --framework:.NETCoreApp,Version=v3.1 --logger:Console;verbosity=minimal --Diag:/root/project/bin/default/log.txt /root/project/tests/XUnitTestProject1/bin/Debug/netcoreapp3.1/XUnitTestProject1.dll
Microsoft (R) Test Execution Command Line Tool Version 16.3.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.49]     XUnitTestProject1.UnitTest1.BoolFailTest [FAIL]
Test run in progress.VSTest: Exit code: 1

Exited with code exit status 1

また、このverbosityをオーバーライドしようとしても minimal から変更されず quiet 時の出力のままです。

#!/bin/bash -eo pipefail
dotnet test -c Debug "--logger:Console;verbosity=minimal"

Test run for /root/project/tests/XUnitTestProject1/bin/Debug/netcoreapp3.1/XUnitTestProject1.dll(.NETCoreApp,Version=v3.1)
VSTest: Starting vstest.console...
VSTest: Arguments: dotnet exec /usr/share/dotnet/sdk/3.1.100/vstest.console.dll --testAdapterPath:/root/.nuget/packages/coverlet.collector/1.2.0/build/netstandard1.0/ --framework:.NETCoreApp,Version=v3.1 --logger:Console;verbosity=minimal --Diag:/root/project/bin/default/log.txt /root/project/tests/XUnitTestProject1/bin/Debug/netcoreapp3.1/XUnitTestProject1.dll
Microsoft (R) Test Execution Command Line Tool Version 16.3.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.49]     XUnitTestProject1.UnitTest1.BoolFailTest [FAIL]
Test run in progress.VSTest: Exit code: 1

Exited with code exit status 1

これはもちろん、dotnet test -c Debug --verbosity=minimal でも変わらず quiet のままです。

再現リポジトリ

再現リポジトリを組んであります。

github.com

ワークアラウンド

dotnet test< /dev/null を付けると、dotnet test のデフォルトverbosityが minimal に正常化されます。

また、verbosity のオーバーライドも正常に機能するようになります。

進捗

microsoft/vstest に報告してあるので、根本対処されるかはIssueの結果次第です。

github.com

まとめ

知らないとこれはまるのでは。

英語含めて記事が全然ないところみると、.NET で CircleCI やはり利用少ない気配があります。 知ってたけど。

前なら Azure Pipeline、今なら GitHub Actions を使う人が多くなっていくんだろうなぁと感じます。 これは Microsoft のdocs などでの露出に誘導されてるのも多分にあるんですかね? と思ったり思わなかったり。

余談: 調査する

当初、CircleCI ではなく ubuntu か何か環境問題か? と思ったのですが、ローカルで dotnet test したり、Docker 上でCircleCI と同じ dotnet-sdk:3.1 イメージを使ってテストを実行しても再現せず正常に指定した verbosity でオーバーライドができます。 この時点で環境問題の可能性は消えます。Dockerさいこー。

コードを確認すると、--Logger:"Console;verbosity=minimal" を渡せば解釈されることがわかります。

            var verbosityExists = parameters.TryGetValue(ConsoleLogger.VerbosityParam, out string verbosity);
            if (verbosityExists && Enum.TryParse(verbosity, true, out Verbosity verbosityLevel))
            {
                this.verbosityLevel = verbosityLevel;
            }

vstest/ConsoleLogger.cs at 5ef1f3b60404588b91fabb4fab22304ac88b108a · microsoft/vstest

他に何か原因があるのかといろいろ調べたけど、ことごとく該当せず...。

そういえば自分のプロジェクトで、この問題が出ず正常にできているものがあるのでなぜかを見てみると、まさかの < /dev/null をしていて前のIssueと同じ対処で解決できています。

tech.guitarrapc.com

ということで、原因はよくわからないけど < /dev/null で出力まで改善されるという謎結果に...。

なお、Diagnostics Logを --diag:diag.txt で出してみてみると、<dev/null を指定しなくてもちゃんと verbosity が設定した値になっているので、 < /dev/null で治るのは make sense といえばそうですが、謎い。

しかし、なんで /dev/null で出力というか挙動が変わるんだ.... stdin なんて何か色ない限りhandleしないと思うんだけど....?