ArchLinux+btrfsでストレージを組む練習

NASていうかbtrfsを使う練習。 今は自宅内NASとして2TB*4で作ったRAID10なストレージをそのまま使っているのだけど、容量を大きくしたいというのと、組んだまま6年も使い続けているので、組み直したいという話。
同じようにRAID10で組み直すのも芸がないし、容量の変更に対応できるような構成にしたい。当初はZFSを検討していたのだけど、ライセンス的に面倒だし、Linuxのファイルシステム「Btrfs」を5年間使用した記録 – GIGAZINEとかによると、構成の変更が視野に入っているならbtrfsのほうが良さそう。 というわけでbtrfsを使う練習をしてみる。 取り敢えず4本一挙に買うお金が無いので、2本で構成→後からお金があるタイミングで4本に増やす、みたいなのを想定。
ただし、システムのパーティションは素直に組んで、NAS用ストレージだけbtrfsにする。
・ストレージ1本で構成
・1本追加してRAID1にする(メタデータもRAID1)
・1本壊れた想定で、差し替える
・2本追加して、4本で構成する
・1本壊れた想定で、差し替える
・1本を大容量のものに差し替える

ArchLinuxセットアップ

何はともあれ実験環境のセットアップ。物理マシン(物理ストレージ)を用意するのは面倒なので、仮想マシンで。
2020.04.01なISOを読ませて起動して、以下つらつらと構成。

// それっぽくパーティショニング
# fdisk /dev/sda
// マウントとpacstrap
# mount /dev/sda2 /mnt
# mkdir /mnt/boot
# mount /dev/sda1 /mnt/boot
# pacstrap /mnt base base-devel linux linux-firmware
// fstab生成とchroot
# genfstab -U /mnt >> /mnt/etc/fstab
# arch-chroot /mnt
// タイムゾーン、ロケール、ホスト名、パスワード
# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# vi /etc/locale.gen
# locale-gen
# cat hostname > /etc/hostname
# pacman -S vim
# vim /etc/hosts
# passwd
// ネットワーク
# pacman -S dhcpcd
# systemctl enable dhcpcd.service
// ブートローダ
# pacman -S grub
# grub-install --target=i386-pc --recheck /dev/sda
# grub-mkconfig -o /boot/grub/grub.cfg
// 再起動
# exit
# umount -R /mnt
# reboot

お次は一般ユーザの作成。

// 一般ユーザの作成
# useradd -m tea
# passwd tea
# ln -s /usr/bin/vim /usr/bin/vi
# visudo
# su tea
$ sudo whoami

ストレージ1本で構成

デフォルトで入ってるストレージは/dev/sdaとして認識されている。ここにストレージを追加したところ、/dev/sdbとして認識されたので、これ1本で構成してみよう。

$ sudo pacman -S btrfs-progs
$ sudo mkfs.btrfs -L tank /dev/sdb
$ sudo sh -c "echo UUID=`ls -l /dev/disk/by-uuid/ | grep sdb | awk '{print $9}'` /mnt btrfs rw,relatime 0 0 >>/etc/fstab"
$ sudo mount -a
$ btrfs filesystem df /mnt
Data, single: total=8.00MiB, used=0.00B
System, DUP: total=8.00MiB, used=16.00KiB
Metadata, DUP: total=51.19MiB, used=112.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B

取り敢えずの作成とマウントはできたっぽい。snapshotはsubvolume単位で作成するので、subvolumeも触ってみる。

$ sudo btrfs subvolume create /mnt/sv1
$ sudo chown tea:tea /mnt/sv1
$ cd /mnt/sv1
// てきとうにファイルを作成
$ dd if=/dev/zero of=/mnt/sv1/data bs=10M count=1
$ ls -l
-rw-r--r-- 1 tea tea 10485760 Apr 28 03:56 data
$ btrfs filesystem df /mnt
Data, single: total=100.62MiB, used=10.06MiB
System, DUP: total=8.00MiB, used=16.00KiB
Metadata, DUP: total=51.19MiB, used=128.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B
// snapshotを作成する
$ sudo btrfs subvolume snapshot /mnt/sv1 /mnt/sv1.snap
$ btrfs filesystem df /mnt
Data, single: total=100.62MiB, used=10.06MiB
System, DUP: total=8.00MiB, used=16.00KiB
Metadata, DUP: total=51.19MiB, used=144.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B
// subvolume内をいじる
$ rm data
// snapshotは残っている
$ ls /mnt/sv1.snap/
data
$ btrfs filesystem df /mnt
Data, single: total=100.62MiB, used=10.06MiB
System, DUP: total=8.00MiB, used=16.00KiB
Metadata, DUP: total=51.19MiB, used=144.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B
// 弄ったsubvolumeにsnapshotを差し替える
$ sudo btrfs subvolume delete /mnt/sv1
$ sudo btrfs subvolume snapshot /mnt/sv1.snap /mnt/sv1
$ ls /mnt/sv1/
data

subvolumeのsnapshotをとって、それからまるっと書き戻す、みたいなことができるようになった。

1本追加してRAID1にする(メタデータもRAID1)


$ sudo btrfs device add /mnt/sdc /mnt
$ sudo btrfs filesystem show /mnt
Label: 'tank'  uuid: ~略~
        Total devices 2 FS bytes used 10.20MiB
        devid    1 size 1.00GiB used 238.38MiB path /dev/sdb
        devid    2 size 1.00GiB used 0.00B path /dev/sdc
// まずbalance
$ sudo btrfs balance start /mnt
// metadataがDUPなのでRAID0に変更ついでにbalance
$ sudo btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt
$ btrfs filesystem df /mnt
Data, RAID1: total=416.00MiB, used=10.12MiB
System, RAID1: total=32.00MiB, used=16.00KiB
Metadata, RAID1: total=208.00MiB, used=160.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B
$ sudo btrfs filesystem show /mnt
Label: 'tank'  uuid: ~略~
        Total devices 2 FS bytes used 10.30MiB
        devid    1 size 1.00GiB used 656.00MiB path /dev/sdb
        devid    2 size 1.00GiB used 656.00MiB path /dev/sdc

usedが増えすぎてる気がしてならない…が、dconvertmconvertを外してbalanceしても240.00MiBと448.00MiBなので、似たようなものか?raid1指定して再度balanceすると使用量が同じになったので間違っていなさそう(ふんいき)

1本壊れた想定で、差し替える

仮想マシンの設定でHDDを1本取り除いておく(そのままだと起動できないので、fstabから自動マウントしないようにしておくか、マウントオプションにdegradedを追加しておく)

$ sudo btrfs filesystem show
warning, device 1 is missing
Label: 'tank'  uuid: ~略~
        Total devices 2 FS bytes used 10.30MiB
        devid    2 size 1.00GiB used 656.00MiB path /dev/sdc
        *** Some devices missing
// 強引にmount
$ sudo mount -o degraded /dev/sdb /mnt
// デバイスを取り除く
$ sudo btrfs device delete missing /mnt
ERROR: error removing device 'missing': unable to go below two devices on raid1

RAIDを組んでいる時に、必要台数を下回ることはできないエラー。RAID1なら2台を下回ってはいけない。Using Btrfs with Multiple Devices – btrfs Wikiによると、とにかく1台追加してからdeleteしろとのこと。

$ sudo btrfs device add /dev/sdb /mnt
$ sudo btrfs device delete missing /mnt
$ sudo btrfs balance start /mnt
$ sudo btrfs filesystem show
Label: 'tank'  uuid: ~略~
        Total devices 2 FS bytes used 10.27MiB
        devid    2 size 1.00GiB used 416.00MiB path /dev/sdc
        devid    3 size 1.00GiB used 416.00MiB path /dev/sdb

2本追加して、4本で構成する

あとはもう同じようにやるだけ。

$ sudo btrfs filesystem show
Label: 'tank'  uuid: ~略~
        Total devices 2 FS bytes used 10.27MiB
        devid    2 size 1.00GiB used 416.00MiB path /dev/sdc
        devid    3 size 1.00GiB used 416.00MiB path /dev/sdb
$ sudo btrfs device add /dev/sdd /dev/sde /mnt
$ sudo btrfs balance start /mnt
$ sudo btrfs filesystem show
Label: 'tank'  uuid: ~略~
        Total devices 2 FS bytes used 10.27MiB
        devid    2 size 1.00GiB used 288.00MiB path /dev/sdc
        devid    3 size 1.00GiB used 288.00MiB path /dev/sdb
        devid    4 size 1.00GiB used 416.00MiB path /dev/sdd
        devid    5 size 1.00GiB used 416.00MiB path /dev/sde

同じ使用量のセットが2つあるのでうまくいってそう。

1本壊れた想定で、差し替える

今や4台あるので、btrfs device delete missingして、差し替えのストレージをbtrfs device addするだけ。

1本を大容量のものに差し替える


$ btrfs filesystem usage /mnt
WARNING: cannot read detailed chunk info, per-device usage will not be show, run as root
Overall:
    Device size:                   4.00GiB
    Device allocated:              1.38GiB
    Device unallocated:            2.62GiB
    Device missing:                4.00GiB
    Used:                         20.66MiB
    Free (estimated):              1.71GiB      (min: 1.71GiB)
~以下略~
$ btrfs device delete /dev/sdc /mnt
$ btrfs device add /dev/sdf /mnt
$ btrfs filesystem usage /mnt
WARNING: cannot read detailed chunk info, per-device usage will not be show, run as root
Overall:
    Device size:                  11.00GiB
    Device allocated:              1.69GiB
    Device unallocated:            9.31GiB
    Device missing:               11.00GiB
    Used:                         20.78MiB
    Free (estimated):              5.21GiB      (min: 5.21GiB)
~以下略~

Device missingは何を表しているのだろうかな~ 取り敢えず使うぶんにはこんくらいあればいいんだろうかな、実際に使うときには、定期的にsnapshotとるとか、色々とメンテが必要なんだろうなとは思いつつ、今回はおしまい どうでも良いが、モニタの液晶とパネルの間に、小さい虫が入ってしまったようで、ず~~~っと画面中でうろうろ動き回っていてつらい。分解するのもしんどいしなぁ。どうするかなぁ

3変数の鶴亀算

唐突だが、3変数の鶴亀算を解けるようにしておきたい。ぶっちゃけ数学は苦手科目だが、それっぽく言葉で表現できるようにしたい。完全に自分用メモである。 よく聞く、つまり2変数の鶴亀算は、例えば次のようなもの。
鶴と亀が合計10匹いる。足の本数は合計34本である。鶴と亀はそれぞれ何匹ずついるだろうか?
但し、鶴の足は2本、亀の足は4本とする。

10匹全て鶴だったとすると、足の総数は以下の通り。 $$10[匹]\times2[本/匹] = 20[本]$$ これだと本数が不足しているため、数匹を鶴ではなく亀に変更したい。足の本数は、1匹変更するごとに2→4[本]になるので、1匹変更ごとの増分は2[本/匹]である。 合計本数に辿り着くまで鶴→亀に変更するとき、必要匹数は以下の通り計算できる。 $$\frac{34[本]-20[本]}{2[本/匹]}=7[匹]$$ よって、亀が7匹、鶴は3匹いるということがわかる。 これくらいなら大して考えずノリで計算できる。 さて、問題は3変数のとき。
10000円札、5000円札、1000円札が手元に合計1000枚あり、その総額は1234000円である。各お札は何枚ずつあるのだろうか?
3変数の場合は、図を使うと表現しやすい。
各頂点の名前は利用有無に関わらずてきとうに付けている
突然階段状の図を掲載したが、横軸が枚数、縦軸が1枚あたりの金額、そして面積が総額を表現している。
全て書き連ねてみると、以下の感じ。
AB:10000円札の枚数
DE:5000円札の枚数
HI:1000円札の枚数
AJ:10000円
DK:5000円
HL:1000円
AJKB:10000円札の総額
DKLE:5000円札の総額
HLMI:1000円札の総額 手順は全部で4段階。
10000円札、5000円札、1000円札の枚数をそれぞれa, b, cとする(当然全て0か自然数である)。また、煩雑になるため、以降の金額は全て3桁落として記述する。 1. どのお札であろうと、必ず1円はかかるため、その分を取り除く。つまり全体の面積から、FJMIの面積を引く。 $$1234 – (1\times1000) = 234$$ 2. 多角形AFHEDBについて考える。これはAFGBとDGHEの和のため、以下の式で表現できる。 $$9\times a + 4\times b = 234$$ $$4\times b = 234 – 9\times a$$ $$b = \frac{234 – 9\times a}{4}$$ 3. 試しに値を入れてみて、それっぽい数字が出るか試す。 $$a=0のとき、b=\frac{234}{4}であり不適$$ $$a=2のとき、b=\frac{216}{4}=54であり適当$$ 4. 以下の通り、全ての未知数の候補が見つかる(他にも条件を満たす組み合わせがあるため「候補」)。 $$c=1000-(a+b)=944$$ ※試しに計算してみると以下の通り、確かに満たしている。 $$10\times2 + 5\times54 + 1\times944 = 1234$$ いやー、数学って難しいね(しみじみ)

mirakurun-serverのCPUが100%で止まる

PX-Q3PE4で録画機の新調 – お茶漬けぶろぐで組んだ録画鯖なのだけど、最近録画ミスが増えてて、データが作られないまま、録画中リストに残り続けるという感じ。以前もたまにあったのだけど、再起動で直っていた。ところが、ここ数日は、再起動では直らず、リアルタイム視聴も数分で止まってしまう。chinachuのWebフロントも、まともに操作できない(応答が返ってこない)。 なんだろーと思って、録画機でpm2 statusを見ると、どうもmirakurun-serverのCPU使用率がぐんぐん上がっていって、100%になったときに死んでいるみたいだ。 ぐぐるとまず見つかったのがこちら。mirakurun-serverがおかしい – yotayota diary
契機はともかく、IPv6を殺せという事のようだ。mirakurun-serverのログ(/usr/local/var/log/mirakurun.stderr.logとか/usr/local/var/log/mirakurun.stdout.log)を見ていても、同じようなログが出ているわけではないのだけど、ダメ元で入れてみた…が直らず(違う現象だろうし、そりゃそうだろ感しかない) 次に見つかったのはこちら。Liuxでテレビ総合スレ 避難所 2 – 5ちゃんねる
違う構成だけど、ログにとくに怪しいものが出てこないというのも、ブラウザも繋がらないってのも共通。
同スレの>>287-288を見ながら、/usr/local/lib/node_modules/mirakurun/node_modules/aribts/lib/char.jsをてきとうに書き換えてみると、取り敢えずCPUの使用率がぐんぐん上がっていくことはなくなった。 rndomhack/node-aribtsにあるchar.jsを見に行くと、全く同じ修正が入っていたっぽい事がわかる。
確かに、システム組み上げた後、一切触っていなかったしなぁ。一旦動き始めたシステムでも、それなりに更新する必要性を感じた一件でした。

Nuxt.jsを使ってみる

参考:nuxtjsでtodo アプリケーションを作成 – Qiita
ま、内容自体はほぼ焼き直しだけど、自分の解釈を加えるって感じ。環境はてきとうなArchLinuxだよ。 まずは環境構築。

# pacman -S nodejs npm
# npm install -g vue @vue/cli @vue/cli-init

プロジェクトの作成。

$ vue init nuxt-community/starter-template todos

nuxt-community/starter-templateはテンプレート名。nuxt-community/starter-template: DEPRECATED: use create-nuxt-app insteadがネタ元か?templateとして使えるリポジトリを指定すれば良いのだろうか。このtemplateはDeprecatedらしいので今やるならリンクが張られているnuxt/create-nuxt-appをどうにかして使うのが良いのかな。

$ cd todos && npm install && npm run dev

起動完了したら、http://localhost:3000にアクセスしてそれっぽい画面が出ればおk。今後はソースを編集すると自動でリロードされるっぽい。 つぎ。ルーティングの追加。pages以下にディレクトリを作成すれば、それがそのままルーティングの設定になる。

$ mkdir pages/todos
$ vi pages/todos/index.vue


<template>
  <div>
    todos
  </div>
</template>

<script>
export default {}
</script>

<style>
</style>

そのままhttp://localhost:3000/todosにアクセスすればpages/todos/index.vueの内容が見れる。 さて、Vuexの話。まずは有効化。nuxt.config.jshead:の次に以下の記述を追加。

$ vi nuxt.config.js


  build: {
    vendor: [
      'vuex',
    ]
  },

storeの作成。

$ vi store/todos.js


export const state = () => ({
  list: []
})

export const mutations = {
  add (state, text) {
    state.list.push({
      text: text,
      done: false,
      id: state.list.length + 1,
    })
  },
  remove (state, { todo }) {
    state.list.splice(state.list.indexOf(todo), 1)
  },
  toggle (state, todo) {
    todo.done = !todo.done
  }
}

ところでVuexとかStoreとかってなんなのだ。 Vuexは状態管理パターン+ライブラリとかいう記述が公式サイトにある。ここでの状態管理とは、ページ上の見た目(内容)・状態・アクション(それぞれView, State, Actions)の管理のことのようだ。単純な場合は利用しなくても良いけれど、複数のViewがStateを共有したりとか、異なるViewのActionsから同一のStateを変更したりとかすると、脳みそで管理するのはしんどいので、使ってくれという事みたい。 Storeは、VuexでのStateを保持するためのコンテナらしい。これはstatemutationsから成っている。mutationsは英単語としての意味は「変化」であり、これを使って状態を変更する。 最後に、index.vueから機能を利用するように変更する。

$ vi pages/todos/index.vue


<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input type="checkbox" :checked="todo.done" @change="toggle(todo)">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">remove</button>
    </li>
    <li><input placeholder="What needs to be done?" @keyup.enter="addTodo"></li>
  </ul>
</template>

<script>
import { mapMutations } from 'vuex';

export default {
  computed: {
    todos () { return this.$store.state.todos.list }
  },
  methods: {
    removeTodo (todo) {
      this.$store.commit('todos/remove', todo);
    },
    addTodo (e) {
      this.$store.commit('todos/add', e.target.value);
      e.target.value = '';
    },
    ...mapMutations({
      toggle: 'todos/toggle'
    })
  }
}
</script>

<style>
.done {
  text-decoration: line-through;
}
</style>

mapMutationsを使っている意味はよくわからない。

toggle (todo) {
  this.$store.commit('todos/toggle', todo);
}

でも意図した動作はするのだけど…何か意味があるんかな? このままだとremoveがどのボタン押しても最新のやつからしか削除されないのでつらい。store/todos.jsの13行目にある{ todo }todoにすれば、押したものから削除されるが、寧ろ波括弧でくくったこの記述はどんなときに使うのだろう?VuexのMutationsについてのガイドを見ると、複数のデータを渡したい場合には、オブジェクトにして送れというような内容が書かれている。あんまり気にしないで良さそうかな。 以上。てきとうにイジればそれっぽく使える気配がしてきた。Node.js+ExpressでWebアプリを作って遊んでいたのだけど、それを作り直してみようかな?と思ったりもする。それか、まるっきり別のものを作ってみるのも良いかもね。
何にしろ、ろくすっぽ勉強せず取り敢えず触ってみるのは、手探りつらいってのもあるけど、やっぱり楽しいね。