NVMe over TCPによるノートPCの複製
(copyninja.in)- 新しいノートPCを最初から再設定する代わりに、既存ノートPCのディスク全体をNVMe over TCPで公開し、ネットワーク経由でそのまま複製した
- 既存環境ではフルディスク暗号化と512GBディスクを使用しており、新しいノートPCは1TB NVMeだったため、複製後にパーティション・LUKS・BTRFSの拡張が必要だった
- ディスクのエクスポートは
systemd-storagetm.serviceではなく、両方のノートPCをGRML rescue CDで起動し、nvmet-tcpと/sys/kernel/config/nvmetで構成した - 実際のコピーは
ddで行い、新しいノートPCにはイーサネットポートがなくWiFiのみを使用した結果、512GBの複製に約7時間30分、速度は約18〜20MB/sだった - 複製後は
parted、growpart、cryptsetup resize、BTRFS resizeを経て1TB全体を使えるように調整し、既存ノートPCの環境をほぼそのまま引き継げた
NVMe over TCPで既存ディスクをエクスポートする
-
新しいノートPCの設定手順を繰り返したくなかったため、同僚の提案どおり既存ノートPCのディスク全体をコピーする方法を選んだ
-
開始前の障害は2つあった
- 既存ノートPCを開けて新しいディスクをUSB接続するための道具がなかった
- 既存ノートPCはフルディスク暗号化と512GBディスクを使っており、新しいノートPCは1TB NVMeだったため、LUKSのサイズ調整が必要だった
-
作業の流れは、ディスクの公開、コピー、容量拡張の3段階に分かれていた
- 既存ノートPCで
nvmet-tcpによりディスクをエクスポートする - 新しいノートPCでそのディスクをコピーする
- パーティションを1TB全体に拡張する
- LUKSのサイズを調整する
- 最後にBTRFSルートディスクのサイズを調整する
- 既存ノートPCで
-
systemd-storagetm.serviceの代わりにGRMLを使用
- 最も簡単な方法としてはsystemd-storagetm.serviceを使えた
rd.systemd.unit=storage-target-mode.targetを指定してstorage-target-mode.targetで起動すれば呼び出せる- ただしこの方法ではdracutのinitrdイメージにネットワークサービスを含める必要があり、このモードではWiFi設定が煩雑なため除外した
- 代わりに両方のノートPCをGRML rescue CDで起動し、既存ノートPC側でLinuxの
nvmet-tcpモジュールを使ってNVMeディスクをエクスポートした
modprobe nvmet-tcp cd /sys/kernel/config/nvmet mkdir ports/0 cd ports/0 echo "ipv4" > addr_adrfam echo 0.0.0.0 > addr_traaddr echo 4420 > addr_trsvcid echo tcp > addr_trtype cd /sys/kernel/config/nvmet/subsystems mkdir testnqn echo 1 >testnqn/allow_any_host mkdir testnqn/namespaces/1 cd testnqn # replace the device name with the disk you want to export echo "/dev/nvme0n1" > namespaces/1/device_path echo 1 > namespaces/1/enable ln -s "../../subsystems/testnqn" /sys/kernel/config/nvmet/ports/0/subsystems/testnqn- この設定により、対象デバイスがNVMe over TCPとして公開される
- 新しいノートPCではエクスポートされたデバイスを検出して接続する
nvme discover -t tcp -a <ip> -s 4420 nvme connectl-all -t tcp -a <> -s 4420- その後
nvme listで新しいノートPCに接続されたデバイスを確認し、ディスクコピーを進められる
ディスクコピーとサイズ調整
-
ddで512GBをコピー- ルートディスクのコピーは
ddコマンドで実行した - 新しいノートPCにはイーサネットポートがなくWiFiのみを使用しており、512GB全体のコピーには約7時間30分かかった
- 転送速度は約18〜20MB/sだった
- 別の選択肢としては、最初にパーティションとファイルシステムを作成してから
rsyncでルートディスクをコピーする方法や、BTRFS自体のファイルシステム転送を使う方法もあった
dd if=/dev/nvme2n1 of=/dev/nvme0n1 status=progress bs=40M - ルートディスクのコピーは
-
パーティション、LUKS、BTRFSの拡張
partedはパーティションテーブルがディスクサイズと一致していないことを検出し、修正するか確認したうえで自動的に修復した- 2番目のパーティションを拡張するため、
cloud-guest-utilsをインストールしてgrowpartを使用した
growpart /dev/nvem0n1 p2- 次の段階では
cryptsetupでLUKSコンテナのサイズを拡張した
cryptsetup luksOpen /dev/nvme0n1p2 ENC cryptsetup resize ENC- その後ディスクから再起動して正常動作を確認し、ログイン後にBTRFSファイルシステムのサイズを調整した
- BTRFSはサイズ変更のためにシステムがマウントされている必要があるため、ライブ起動状態では試せなかった
btfs fielsystem resize max /- 結果として、新しいノートPCでも既存ノートPCをそのまま使い続けているような環境を得られた
- 通常、新しいノートPCに完全に慣れるには約1〜2週間かかるが、この方法でその時間を短縮できた
- 付随する成果として、NVMe over TCPでディスクをエクスポートする方法も学べた
1件のコメント
Hacker News のコメント
投稿者のシナリオでは結局
dd(1)によるシリアルなブロックコピーしかしていないので、NVMe/TCP を使う利点はほとんどない。複雑なコマンドは単純なnetcatで置き換えられる対象ノートPC:
$ nc -l -p 1234 | dd of=/dev/nvme0nX bs=1M元ノートPC:
$ nc x.x.x.x 1234対象側の
ddは、書き込みをバッファリングしてより高速かつ効率的にするためのもの。元/対象にgzip/gunzipを追加すると、ディスクが満杯ではなく 0 ブロックが多い場合にずっと速くなる。個人的にはネットワーク越しに PC のイメージを取るときに一番好きな方法で、何度もやったことがあるGigE では圧縮がボトルネックになることが多いので、
gzipには--fastを渡すのがよく、さらに良いのはgzip/gunzipの代わりに lz4/unlz4 を使うともっと速い。以前、1TB NVMe を搭載した新品の Windows ノートPCを GigE でイメージ化したときは20分ほどかかり、空き領域はほぼ 0 に近く圧縮されたため、結果のイメージは 20GB だった。普段はその lz4 イメージをバックアップしておき、数年後にノートPCを寄付するときにunlz4 | ddで復元していて、とても便利ただ Linux カーネルモジュール
nvme-tcpは知らなかったので、日々新しいことを学んでいる。これはddで生アクセスする用途よりも、リモート NVMe 上にファイルシステムをマウントするのにより有用そうだ追加で、Linux の最大パイプバッファサイズは 64kB なので、
dd bs=X引数は技術的にはそれより大きい必要はない。それでもbs=1Mは害がなく、64kB の読み取りを 1MB になるまでまとめてくれるし、将来パイプサイズが大きくなっても備えになる。一部のnetcatバージョンには入出力ブロックサイズのオプションがあるためdd bs=Xは不要だが、リカバリディスクのnetcatはたいていそのようなオプションがないバージョンだddの代わりにpvを使えば適切なブロックサイズを指定する心配がなく、進捗グラフも見やすく表示されるtestdiskでパーティションテーブルを再構築する必要があったが、その前に破損したディスクを触りたくなかったので、リカバリ用フラッシュディスク、netcat、ドライブを使って約 40TB をコピーした一部のサーバーは物理 RAID スロットがすべて埋まっていて予備ディスクスロットも使えず、おおむね
dd if=/dev/sdc bs=xxx | gzip | nc -l -p 8888と反対側の逆向きコマンドを使った。意外とうまく動いた。1つ注意点はdd bsの組み合わせをセクタサイズに合わせてみることで、適切なサイズがddのスループットに大きく影響したddの使い方は破損を引き起こす可能性がある。ブロックが切れないようにするにはiflag=fullblockが必要で、盲目的な慣習である危険はあるがconv=syncも害はない。個人的には単にnc -l -p 1234 > /dev/nvme0nXを好むパイプラインに
pvを入れると予想完了時間を見られるが、性能には多少影響する可能性があるAWS/Annapurna/Nitro/Lightbits が Linux に NVMe-over-TCP を持ち込んだことに感謝
https://www.techtarget.com/searchstorage/news/252459311/Ligh...
「NVM Express コンソーシアムは 2018年11月、NVMe/TCP をバインディング転送層として批准した。この標準はもともと Lightbits のエンジニアリングチームが NVM Express に提出したコードベースから発展した。」
https://www.lightbitslabs.com/blog/linux-distributions-nvme-...
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
次に比べるとずっと面倒そうに見える:
nbdkit file /dev/nvme0n1,nbdcopy nbd://otherlaptop localfilenbdcopyはスパースファイルを扱え、接続数とスレッド数をコア数に合わせられ、終了前に強制フラッシュもでき、進捗バーも有効にできる。暗号化されていないドライブなら TLS もサポートしている最近、新しいノートPCに xubuntu をインストールする必要があった。以前はクローンしていたが、今回は一部の設定を新しく整理したかった。
USB-Cケーブルで10Gb/s転送できるのは本当に便利だった。ほかの選択肢はWiFiしかなかったからだ。
コンピュータ同士を接続すると一時的なネットワークが形成され、あとは
rsyncで送ればよい。見たところリンクは飽和していたので、別のプロトコルを使ってもあまり意味はなさそうだった。もちろん新しいことを学ぶのは良いが、ノートPCをクローンするその瞬間ではないかもしれない。転送自体はものすごく速く、数分で1TBを移せた。今回は暗号化を使わなかったので、ずっと単純だった。
なぜネットワーク越しに btrfs をパイプしなかったのか理解できない。まずbtrfsスナップショットを作り、
btrfs send => nc => network => nc => btrfs receiveとすれば、使用中のブロックだけが転送される。btrfs send/receiveはSSH越しにいつも使っていて、とてもよく動く。GRMLのライブセッションでSSHサーバーを簡単に立てることもできただろう。ただし注意点が1つある。btrfsではスナップショットを再帰的に送れないので、再帰スナップショットが多い場合、新しいディスクに同じ構造をミラーするのは比較的難しい。Docker/LXD/Incusではそういうことが起こり得る。btrfsは好きだが、再帰的なsend/receive はZFSのほうが優れている部分だ。
最近、WiFiで約 200GBのファイル をコピーする必要があった。接続失敗時に最初からやり直さずに済むように、また損失がないように
rsyncを使ったが、少なくとも6時間かかった。もっと良い方法があったのか気になる。それと、
dd方式はどんな保証を与えてくれるのかも気になる。結果のブロックデバイスのmd5を比較すべきなのだろうか?WiFiには性能のボトルネックになる要因がはるかに多い。片方の機器だけでもケーブルでルーターに接続し、もう片方を無線のままにするだけでもかなり助けになる。
rsyncが一度に1ファイルしか転送しない点がボトルネックだった可能性が高い。xargs/parallelでファイル一覧を分割して複数のrsyncインスタンスを動かすか、独自に 並列転送 をサポートするrcloneのようなものを使える。-zで圧縮したのか気になる。イーサネットを使えたなら、ほとんどの機器で100MB/s近くになり、35分 程度だったはずだ。rsyncの転送方式がSSHだったなら、それがボトルネックになることは多い。OpenSSHには歴史的に奇妙な性能制限があり、それを回避するにはあまり知られていないパッチが必要だったこともある。CPUがボトルネックでないなら、圧縮を有効にするのも役に立つ。「コンピュータネットワークにおける衝突回避付き搬送波感知多重アクセス(CSMA/CA)は、搬送波感知を用いるが、チャネルが『アイドル』と検知された後にのみ送信を開始することで衝突を避けようとするネットワーク多重アクセス方式である。送信時には、ノードはパケットデータを全体として送信する。
これは、無線送信機がパケット送信中に受信機の感度を低下させて無効化してしまうため、衝突検出方式であるCSMA/CDを使えない無線ネットワークでは特に重要である。
CSMA/CAは隠れ端末問題のため信頼性が低い。
CSMA/CAはデータリンク層で動作するプロトコルである。」
https://en.wikipedia.org/wiki/Carrier-sense_multiple_access_...
このアプローチにも利点はあるだろうが、以前ノートPCを移行したときは、両方でインストーラーを起動してから
ddとncを組み合わせた。記憶では、大きなヌル領域をより速く転送するために gzip も追加した。新しいノートPCにイーサネットポートがなかったなら、自分のハック的な方法のほうが圧縮のおかげで少し速かったかもしれない。ネットワーク速度が、速いリンクで圧縮が追加する限界に近づけない程度だったはずだからだ。
ただ Clonezilla を使えばいいのでは? 実データブロックだけをコピーし、パーティションの自動リサイズもできる。自分はいつもそうしている。
もちろん普通は、ノートPCからNVMeディスクを取り出して高速ドックに挿す。
まだ完全に信頼して放置できるレベルではない。バックアップは、バックアップと復元を合わせたものと同じではないので、実験が推奨される。Clonezillaも、元と大きく異なるディスクにパーティションを再作成するときは問題が起きることがある。
デスクトップやノートPCにOSを実際に「インストール」してから何十年も経っており、いつもファイルをコピーして必要な部分だけ調整してきた。たいていはこの機会に、ファイルシステムの種類やブロックサイズのようなパラメータ、暗号化などを更新するため、新しいファイルシステムを作って
rsyncでファイルを移す。それでも、事前に計画するタイプなら、設定だけをコピーし、残りは自動で再インストールする NixOS のような、より宣言的な方式のほうがよさそうだ。
中継APなしでWiFiで機器同士を直接接続すれば、転送速度 を2倍にできるはずだ。この状況では試す価値があったように思う。