2 ポイント 投稿者 GN⁺ 2024-03-13 | 1件のコメント | WhatsAppで共有
  • 新しいノート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だった
  • 複製後はpartedgrowpartcryptsetup 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ルートディスクのサイズを調整する
  • 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
    
    • 次の段階ではcryptsetupLUKSコンテナのサイズを拡張した
    cryptsetup luksOpen /dev/nvme0n1p2 ENC
    cryptsetup resize ENC
    
    • その後ディスクから再起動して正常動作を確認し、ログイン後にBTRFSファイルシステムのサイズを調整した
    • BTRFSはサイズ変更のためにシステムがマウントされている必要があるため、ライブ起動状態では試せなかった
    btfs fielsystem resize max /
    
    • 結果として、新しいノートPCでも既存ノートPCをそのまま使い続けているような環境を得られた
    • 通常、新しいノートPCに完全に慣れるには約1〜2週間かかるが、この方法でその時間を短縮できた
    • 付随する成果として、NVMe over TCPでディスクをエクスポートする方法も学べた

1件のコメント

 
GN⁺ 2024-03-13
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 はたいていそのようなオプションがないバージョンだ

    • Linux のパイプバッファは増やせるし、デフォルトの最大値は通常 1MB 程度だったと思う。コマンドラインでやるのは少し面倒だが、可能な実装例は https://unix.stackexchange.com/a/328364 にある
    • 少し泥臭いが、両側で dd の代わりに pv を使えば適切なブロックサイズを指定する心配がなく、進捗グラフも見やすく表示される
    • 9年ほど前、内部からハッキングされた会社にコンサルティングに行ったことがある。不満を持った共同創業者が、デッドマンスイッチのように全ディスクの先頭 20MB をどこかのバケットにコピーしたあと 0 で上書きするよう仕掛けていた。データを復旧するために 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 を好む
    • ほとんどの場合、ローカルネットワークは SSD の転送速度より速くないだろう。それでも、そういう環境がある人向けに同時入出力ブロックデバイス複製ツールが存在するのか気になる
      パイプラインに 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 localfile

    • この方法のほうが実際にはずっと優れていて、nbdcopyスパースファイルを扱え、接続数とスレッド数をコア数に合わせられ、終了前に強制フラッシュもでき、進捗バーも有効にできる。暗号化されていないドライブなら TLS もサポートしている
  • 最近、新しいノートPCに xubuntu をインストールする必要があった。以前はクローンしていたが、今回は一部の設定を新しく整理したかった。
    USB-Cケーブルで10Gb/s転送できるのは本当に便利だった。ほかの選択肢はWiFiしかなかったからだ。
    コンピュータ同士を接続すると一時的なネットワークが形成され、あとは rsync で送ればよい。見たところリンクは飽和していたので、別のプロトコルを使ってもあまり意味はなさそうだった。もちろん新しいことを学ぶのは良いが、ノートPCをクローンするその瞬間ではないかもしれない。

    • そのまま動いたのか気になる。イーサネットではない直接接続を最後に試したのが90年代なので、真面目に聞いている。
    • 自分もやってみたが、ネットワークとして使えるようにするには30ドル以上の Thunderbolt 4ケーブル を買う必要があった。普通のUSB3-Cケーブルだけでは足りなかった。
      転送自体はものすごく速く、数分で1TBを移せた。今回は暗号化を使わなかったので、ずっと単純だった。
    • ライブディスクで起動してファイルシステム全体を移したのか、それとも基本システムをインストールしてからファイルだけ移したのか気になる。
  • なぜネットワーク越しに btrfs をパイプしなかったのか理解できない。まずbtrfsスナップショットを作り、btrfs send => nc => network => nc => btrfs receive とすれば、使用中のブロックだけが転送される。

    • btrfsを使っていると見た瞬間、自分も真っ先にそれを思い付いた。btrfs send/receive はSSH越しにいつも使っていて、とてもよく動く。GRMLのライブセッションでSSHサーバーを簡単に立てることもできただろう。
      ただし注意点が1つある。btrfsではスナップショットを再帰的に送れないので、再帰スナップショットが多い場合、新しいディスクに同じ構造をミラーするのは比較的難しい。Docker/LXD/Incusではそういうことが起こり得る。btrfsは好きだが、再帰的なsend/receive はZFSのほうが優れている部分だ。
  • 最近、WiFiで約 200GBのファイル をコピーする必要があった。接続失敗時に最初からやり直さずに済むように、また損失がないように rsync を使ったが、少なくとも6時間かかった。もっと良い方法があったのか気になる。
    それと、dd方式はどんな保証を与えてくれるのかも気になる。結果のブロックデバイスのmd5を比較すべきなのだろうか?

    • 200GBをWiFiで移すのに6時間というのは、ローカル転送としては印象的なスループットではない。イーサネットケーブル を使うべきだったように思う。
      WiFiには性能のボトルネックになる要因がはるかに多い。片方の機器だけでもケーブルでルーターに接続し、もう片方を無線のままにするだけでもかなり助けになる。
    • ファイルが非常に多くて小さかったなら、rsync が一度に1ファイルしか転送しない点がボトルネックだった可能性が高い。xargs/parallel でファイル一覧を分割して複数の rsync インスタンスを動かすか、独自に 並列転送 をサポートする rclone のようなものを使える。
    • 6時間ならおおよそ10MB/sなので、ずっと速くできた可能性が高い。-z で圧縮したのか気になる。イーサネットを使えたなら、ほとんどの機器で100MB/s近くになり、35分 程度だったはずだ。
    • rsync の転送方式がSSHだったなら、それがボトルネックになることは多い。OpenSSHには歴史的に奇妙な性能制限があり、それを回避するにはあまり知られていないパッチが必要だったこともある。CPUがボトルネックでないなら、圧縮を有効にするのも役に立つ。
    • WiFiは、ほかのすべての無線機器と 空気という媒体 を共有している。衝突を検出すると停止し、ランダムな時間だけ待つ。
      「コンピュータネットワークにおける衝突回避付き搬送波感知多重アクセス(CSMA/CA)は、搬送波感知を用いるが、チャネルが『アイドル』と検知された後にのみ送信を開始することで衝突を避けようとするネットワーク多重アクセス方式である。送信時には、ノードはパケットデータを全体として送信する。
      これは、無線送信機がパケット送信中に受信機の感度を低下させて無効化してしまうため、衝突検出方式であるCSMA/CDを使えない無線ネットワークでは特に重要である。
      CSMA/CAは隠れ端末問題のため信頼性が低い。
      CSMA/CAはデータリンク層で動作するプロトコルである。」
      https://en.wikipedia.org/wiki/Carrier-sense_multiple_access_...
  • このアプローチにも利点はあるだろうが、以前ノートPCを移行したときは、両方でインストーラーを起動してから ddnc を組み合わせた。記憶では、大きなヌル領域をより速く転送するために gzip も追加した。
    新しいノートPCにイーサネットポートがなかったなら、自分のハック的な方法のほうが圧縮のおかげで少し速かったかもしれない。ネットワーク速度が、速いリンクで圧縮が追加する限界に近づけない程度だったはずだからだ。

    • フルディスク暗号化の状態なら、LUKSにTRIMの通過を指示していない限り、著者が説明した方式では実質的に ランダムデータ しか得られない。
  • ただ Clonezilla を使えばいいのでは? 実データブロックだけをコピーし、パーティションの自動リサイズもできる。自分はいつもそうしている。
    もちろん普通は、ノートPCからNVMeディスクを取り出して高速ドックに挿す。

    • Clonezillaは素晴らしい。やることは1つで、たいてい最初の試行で成功する。ただ、初期の学習曲線のせいでいろいろ触ってみる必要があるのが唯一の不満だ。
      まだ完全に信頼して放置できるレベルではない。バックアップは、バックアップと復元を合わせたものと同じではないので、実験が推奨される。Clonezillaも、元と大きく異なるディスクにパーティションを再作成するときは問題が起きることがある。
  • デスクトップやノートPCにOSを実際に「インストール」してから何十年も経っており、いつもファイルをコピーして必要な部分だけ調整してきた。たいていはこの機会に、ファイルシステムの種類やブロックサイズのようなパラメータ、暗号化などを更新するため、新しいファイルシステムを作って rsync でファイルを移す。
    それでも、事前に計画するタイプなら、設定だけをコピーし、残りは自動で再インストールする NixOS のような、より宣言的な方式のほうがよさそうだ。

  • 中継APなしでWiFiで機器同士を直接接続すれば、転送速度 を2倍にできるはずだ。この状況では試す価値があったように思う。