Plan 9とGo言語のブログ

主にPlan 9やGo言語の日々気づいたことを書きます。

Plan 9を別の環境に移行する

この記事では、手元で動いているPlan 9環境をそのままGCPに移行する手順を紹介します。移行する一連のなかで、

  • Fossilだけで動いている環境にVentiを設定する
  • VentiからFossilを復旧する

といった、日本語だと情報があまりないものを扱います。移行先はGCPを選んでいますが、これはCompute Engineがシリアルコンソールをサポートしていて何かあった場合でも対応しやすいからなだけで、他の環境でもそれほど違いはありません。

ベル研Plan 9のファイルサーバは、3rd editionまで利用されていたKen Thompsonのfs(dumpfs)からFossil+Ventiに移り変わっています。Fossil+Ventiは管理が複雑などの理由から、9frontなどではken fsと同じように扱えるcwfsが人気ですが、複雑なところを差し引いてもFossil+Ventiの方が便利だと思うので個人的にはこちらを使っています。

Ventiはディスクブロックの内容をハッシュ化して、決まった場所に書き込むストレージです。これ自体はただのストレージで、ファイルシステムではありません。FossilはVentiを利用したファイルシステムです。Fossil単体でも動作しますがVentiと連携するように設定しておくと、デフォルトでは1日1回、差分をVentiへ書き込みます。VentiがあればFossilはいつでも再構築できるため、これを使って移行するわけですね。

Ventiについては以下のリンクを参照ください。

移行先Ventiの用意

Ventiディスクの作成

まずVentiのデータを先にGCPへ移行する必要があるので、GCPでディスクを作成しましょう。ここで作るディスクはそのまま移行後のVentiディスクとなります。後から追加も可能ですが管理が煩雑になるので、必要な分のサイズを用意しておいてください。

% gcloud compute --project=$GCP_PROJECT disks create venti \
    --type=pd-standard --size=200G --zone=asia-northeast2-a

% gcloud compute --project=$GCP_PROJECT disks list
NAME   LOCATION           LOCATION_SCOPE  SIZE_GB  TYPE         STATUS
venti  asia-northeast2-a  zone            200      pd-standard  READY

上記では標準のディスクで200GB用意しました。Ventiへのアクセス頻度はそれほど多くないので、ディスクの読み書き速度はそれほど必要ありません。

データのコピー

次に、移行したいホストのVentiから、上記で作成したディスクへデータをコピーします。ここではreadwriteを使う方法で行いますが、コピー方法は以下のエントリにいくつか挙げているので好みの方法を選んでもらって構いません。

また、以下の例では作業用のPlan 9端末(fsという名前)を使っていますが、こちらもplan9portで代用できます。古い記事ですがplan9portでVentiを構築する場合は以下を参考にしてください。

というわけで、GCP上の移行先ディスクをインスタンスに接続して、Ventiをサービスするところまでやりましょう。ファイアウォールventiのポートも通しておきます。

% gcloud compute --project=$GCP_PROJECT instances attach-disk fs \
    --disk=venti --zone=asia-northeast2-a
% gcloud compute --project=$GCP_PROJECT instances start fs \
    --zone=asia-northeast2-a
% gcloud compute --project=$GCP_PROJECT connect-to-serial-port fs \
    --zone=asia-northeast2-a

% gcloud compute --project=$GCP_PROJECT firewall-rules create default-allow-venti \
    --direction=INGRESS --network=default \
    --action=ALLOW --rules=tcp:17034 --source-ranges=0.0.0.0/0

ここからは作業用のPlan 9端末でVentiディスクを初期化します。いくつかパーティションを切っていますが、arenaが実際のファイル内容を保存する場所、isectはindex sectionの略でハッシュ値とデータが保存されているディスクのブロックを特定するための領域、bloomはなくても動きますが、速度改善のためのものです。

# did not find master boot recordエラー対策
term% disk/mbr /dev/sd02/data

term% disk/fdisk -bawp /dev/sd02/data
part plan9 63 419425020

term% disk/prep -bw -a arenas -a isect -a bloom /dev/sd02/plan9
arenas 398453696
isect 19922685
bloom 1048576

これで必要なパーティションが揃いました。

% ls -lp /dev/sd02
--rw-r----- S 0 glenda glenda 204008292352 Mar 12 03:47 arenas
--rw-r----- S 0 glenda glenda    536870912 Mar 12 03:47 bloom
--rw-r--r-- S 0 glenda glenda            0 Mar 12 03:47 ctl
--rw-r----- S 0 glenda glenda 214748364800 Mar 12 03:47 data
--rw-r----- S 0 glenda glenda  10200414720 Mar 12 03:47 isect
--rw-r----- S 0 glenda glenda 214745577984 Mar 12 03:47 plan9
-lrw------- S 0 glenda glenda            0 Mar 12 03:47 raw

Ventiディスクをフォーマットしていきます。

% venti/fmtarenas arenas /dev/sd02/arenas
fmtarenas /dev/sd02/arenas: 380 arenas, 204,007,497,728 bytes storage, 524,288 bytes for index map

% venti/fmtisect isect /dev/sd02/isect
fmtisect /dev/sd02/isect: 1,245,070 buckets of 215 entries, 524,288 bytes for index map

% venti/fmtbloom /dev/sd02/bloom
fmtbloom: using 512MB, 32 hashes/score, best up to 95,443,717 blocks

% cat >venti.conf
index main

isect /dev/sd02/isect
arenas /dev/sd02/arenas
bloom /dev/sd02/bloom
^D

% venti/conf -w /dev/sd02/arenas venti.conf

% venti/fmtindex /dev/sd02/arenas
fmtindex: 380 arenas, 1,244,919 index buckets, 204,001,271,808 bytes storage

上記コマンドのventi/fmtindexは、それぞれ個別にフォーマットしたパーティションをまとめてひとつのVentiで扱うためのコマンドです。また、最後にあるventi/confは設定をarenasパーティションの先頭に埋め込んでいます。venti/ventiは起動する時に、ここから設定を読んでパーティションを扱います。

これで準備ができたので起動しましょう。

% venti/venti -c /dev/sd02/arenas
2020/0818 17:13:14 venti: conf...
venti/venti: bloom filter bigger than mem pcnt; resorting to minimum values (9MB total)
venti/venti: mem 1,048,576 bcmem 2,097,152 icmem 6,291,456...init...icache 6,291,456 bytes = 98,304 entries; 4 scache
sync...queue...announce tcp!*!venti...serving.

ここまで正常に終われば外から接続できるようになっています。

% nc -v <移行先インスタンスのIPアドレス> 17034

readwriteでデータをコピーします。9legacyのスクリプトを移行元にダウンロードして、以下の値を書き換えます。

# 移行元IPアドレス(通常はこのまま)
venti=127.0.0.1

# 移行先IPアドレスとポート番号
host=tcp!<移行先インスタンスのIPアドレス>!17034

これで実行するとVentiのデータをコピーします。移行元Ventiの容量によっては数時間かかるので、途中で切断されないように気をつけてください。

% >info
% rc ./readwrite

終わったら、移行元のvacスコアを使って、移行先Ventiからファイルが読めるか確認します。

% venti=127.1
% echo vac:xxx >score.vac
% vac score.vac
% lc /n/vac

% unmount /n/vac

またはreadwriteの代わりにventi/copyも使えます。この場合はvacスコアから辿れる範囲内しかコピーしませんが、fossilと一緒に運用しているなら一般的には最後のスコアから全て辿れるので十分です。

% fossil/last /dev/sdC0/fossil
vac:xxx

% venti/copy -f localhost:17034 <移行先インスタンスのIPアドレス>:17034 vac:xxx

VentiからFossilの再構築

次に、Ventiの最終スコアを使ってFossilを構築します。これまで使っていたディスクはレスキュー用に残しておいて、代わりに新しいディスクを使うことにします。Fossilは速度が必要なのでpd-ssdで作ります。

% gcloud compute --project=$GCP_PROJECT disks create fossil \
    --type=pd-ssd --size=20GB --zone=asia-northeast2-a
% gcloud compute --project=$GCP_PROJECT instances attach-disk fs \
    --disk=fossil --zone=asia-northeast2-a

これで新しいディスクは/dev/sd03に接続されました。後はこれを初期化していきます。

term% disk/mbr -m /386/mbr /dev/sd03/data
term% disk/fdisk -baw /dev/sd03/data
term% disk/prep -bw -a 9fat -a nvram -a fossil -a cache -a swap /dev/sd03/plan9

term% venti=127.1
term% venti/venti -c /dev/sd02/arenas
term% fossil/flfmt -v xxx /dev/sd03/fossil  # xxxはvacスコアだけどハッシュ値だけ

FossilとVentiの連携

fossil/flfmt -vで初期化したFossilは、起動時にVentiが動いていることを必須とします。そのためFossilのopenコマンドで-Vオプションを使ってはいけません。

# 今は/dev/sd03/fossilだけど最終的にブートディスクとなるので/dev/sd01/fossilとして書き込む
term% cat >fossil.conf
fsys main config /dev/sd01/fossil
fsys main open -c 3000
^D

term% fossil/conf -w /dev/sd03/fossil fossil.conf

また、Fossilよりも前にVentiが起動している必要があります。このためにplan9.iniventi=の追加が必要です。カーネルventi=エントリがplan9.iniに書かれている場合にVentiを起動するようになっています。

bootfile=sdC0!9fat!9pccpuf
bootargs=local!#S/sdC0/fossil
bootdisk=local!#S/sdC0/fossil
venti=#S/sdC0/arenas

# *debugload=1
# *noahciload=1
# *nodumpstack=1
# *noetherprobe=1
# *nousbprobe=1
# [debug]
# baud=9600
# config for initial cd booting
# console=0
# this would disable ether and usb probing.
# very cautions settings to get started.
# will defeat booting from usb devices.
*nobiosload=1
*nomp=1
debugboot=1
dmamode=ask
partition=new
mouseport=ps2
monitor=xga
vgasize=1024x768x32

console=0 b115200 l8 pn s1

また、このディスクはブートディスクとなるのでカーネルやローダなども入れる必要があります。ただし標準配布されているカーネルvirtioが有効になっていません。Compute Engineで動かすためにvirtioを組み込んだカーネルを使っているはずなので、現行のディスクからカーネルなどを新しいディスクに移行します。

term% 9fat:
term% cd /n/9fat
term% disk/format -b /386/pbslba -d -r 2 /dev/sd03/9fat 9load 9pcf plan9.ini

これで、ブートディスクを新しいFossilに変更して再起動すれば以前の環境そのまま移行できます。

トラブル事例

vacスコアを紛失した

arenasが残っていれば/sys/src/cmd/venti/words/dumpvacrootsで取り出せます。Unixの場合はそのままだと動かないので、Windows Azure上でLinuxをventiバックアップ先にするに変更したものを載せています。