スクエニ ITエンジニア ブログ

VS Code devcontainer で disk が遅すぎるのをなんとかしたい

開発作業を中心に様々な用途で非常に便利な devcontainer 機能ですが、container 内 workspace の disk 性能が遅すぎる問題のために実用に耐えないといったことがあります。
devcontainer において disk が遅いと感じるのはおそらく、host 側にある folder を開いて devcontainer を起動した際に、その folder が性能が低い filesystem で bind mount されるからです (と思っています)。

かんたんな作業であれば気にならないのですが、身近なものでは npm install したようなときでもわりと気になりますし、大きな project の build となるとかなりの問題となることもあります。

公式: Improve disk performance にも専用の項目があったりします。named volume を使って解決をしよう、という内容です。

計測してみる

では、bind mount と named volume でどのくらい違うのでしょうか? devcontainer.json に mount を追加して検証してみます。named volume nv-proj を mount し、user vscode から利用できるようにしています。bind mount は、devcontainer で自動的に mount される workspace (devcontainer.json を含む場所) を使用します (ので以下の設定には明示されていません)。

{
  "name": "Ubuntu",
  "build": {
    "dockerfile": "Dockerfile",
  },
  "remoteUser": "vscode",
  "mounts": [
    "source=nv-proj,target=${containerWorkspaceFolder}/named-volume,type=volume"
  ],
  "postCreateCommand": "sudo chown vscode:vscode named-volume"
}

mount で確認します。それぞれ fuse.grpcfuseext4 で mount されています。

$ mount 
  ...
grpcfuse on /workspaces/devcont-min type fuse.grpcfuse (rw,nosuid,nodev,relatime,user_id=0,
  ...
/dev/vda1 on /workspaces/devcont-min/named-volume type ext4 (rw,relatime)
  ...

dd で単純な書き込み性能のみを測ってみます。

$ dd if=/dev/zero of=benchfile bs=4k count=2000
2000+0 records in
2000+0 records out
8192000 bytes (8.2 MB, 7.8 MiB) copied, 1.96436 s, 4.2 MB/s
$ dd if=/dev/zero of=named-volume/benchfile bs=4k count=2000
2000+0 records in
2000+0 records out
8192000 bytes (8.2 MB, 7.8 MiB) copied, 0.0134171 s, 611 MB/s

簡単な検証ですが、4.2 MB/s 対 611 MB/s (100 倍以上…) と出ました。すごい差です… 本当でしょうか… 何度かやりましたがだいたい同じくらいでした。
体感では、npm install や C project の make で 5 倍〜 くらいの時間がかかるかな? という印象でしたが、単純な書き込み性能はもっと下がっていそうです。
ちなみに host OS (の disk) でおなじ計測をすると 600MB/s 前後でしたので、named volume ではほとんど遜色ない数値が出ていると言えます。

ちなみに上記は Macbook Pro で試した結果です。別マシンなので spec は揃っていませんが、Windows 10 PC でも試した結果、そこまで大きくは変わらず 17.0 MB/s 対 634 MB/s (37 倍) という差でした。検証環境として Windows PC のほうがハードウェア性能が良いものなので単純な直接比較はできませんが、これだけを見ると Windows のほうが問題になりにくいのかもしれません。

解決策は?

大きめの C project を build するなど disk 的にしんどい workspace を扱う場合は、named volume を使うのがよさそうです。

host OS 側の volume (Windows であれば C: や D: ドライブなど) に git clone してそれを開くのではなく、command palette から “Remote-Containers: Clone Repository in Container Volume…” を選択し、直接 container 内に clone します。

公式: Quick start: Open a Git repository or GitHub PR in an isolated container volume

ただしこの場合、host 側から直接 workspace が見えない点に注意が必要です。この手順で clone した場合、開いた workspace の名前がついた named volume が生成されるようなので、それを devcontainer の外から扱うことはできます。

❯ docker volume ls
  :
  :
local     vscode-remote-try-node-6789fd329eb29bc56aab44eb27506206

これで devcontainer 内でも高速な disk で作業ができるようになりました。

別の解決策: macOS の場合

macOS でのみですが、Docker Desktop で bind mount 方式に VirtioFS が使えるようになった (GA になった) と聞き、これも試してみました。

前提条件・計測方法

  • MacBook Pro (2019) macOS Monterey 12.6.2
  • Docker Desktop 4.15.0
    • file sharing に VirtioFS を使うよう設定 (これにより “Use Virtualization framework” も強制される)

テストしてみる

bind mount の設定を VirtioFS に変更します。fakeowner という見え方に変わっています。

$ mount
  ...
/host_mark/Users on /workspaces/devcont-min type fakeowner (rw,nosuid,nodev,relatime,fakeowner)
  ...
/dev/vda1 on /workspaces/devcont-min/named-volume type ext4 (rw,relatime)
  ...

同様に dd で計測してみます。

$ dd if=/dev/zero of=benchfile bs=4k count=2000
2000+0 records in
2000+0 records out
8192000 bytes (8.2 MB, 7.8 MiB) copied, 0.504002 s, 16.3 MB/s
$ dd if=/dev/zero of=named-volume/benchfile bs=4k count=2000
2000+0 records in
2000+0 records out
8192000 bytes (8.2 MB, 7.8 MiB) copied, 0.0150964 s, 543 MB/s

冒頭の検証から設定を変更しているので比較のために VirtioFS のみでなく named volume も計測しています。
16.3 MB/s 対 543 MB/s (33 倍) という結果になりました。かなり… となんとか言えるくらいには差が縮まっています。bind mount の性能差で言うと 3 倍近く早くなっていると言ってよさそうです。

fio でも計測しました。

$ fio -filename=test -direct=1 -rw=randwrite -bs=4k -size=8M \
  -numjobs=4 -group_reporting -name=test-bind
  ...
Run status group 0 (all jobs):
  WRITE: bw=14.3MiB/s (15.0MB/s), 14.3MiB/s-14.3MiB/s (15.0MB/s-15.0MB/s), io=32.0MiB (33.6MB), run=2231-2231msec
$ fio -filename=named-volume/test -direct=1 -rw=randwrite -bs=4k -size=8M \
  -numjobs=4 -group_reporting -name=test-nv
  ...
Run status group 0 (all jobs):
  WRITE: bw=82.3MiB/s (86.3MB/s), 82.3MiB/s-82.3MiB/s (86.3MB/s-86.3MB/s), io=32.0MiB (33.6MB), run=389-389msec

こちらでは 15.0MB/s 対 86.3MB/s (5.7 倍) と、dd のときほどの差はありません。
実際の用途によっては大きく使用感に差がありそうです。

まとめ

以上のように、VirtioFS では確実に bind mount の性能向上は見られました。が、依然として OS native での利用や named volume 使用と比較すると大きな差があり、用途によっては引き続き bind mount の利用を避けるべきシーンがありそうです。

かたや、これまでも特に意識せず bind mount で使用していて問題がなかった場合は、VirtioFS が利用可能になったことでさらに快適に使えるようになりそうです。Windows でも同様に使えるようになるといいですね。

ということで、これからも用途に合わせて devcontainer を快適に使っていきましょう!

この記事を書いた人

記事一覧
SQUARE ENIXでは一緒に働く仲間を募集しています!
興味をお持ちいただけたら、ぜひ採用情報ページもご覧下さい!