最小限の環境を作る「フォントえらび」

私は基本、4台のコンピュータを運用している。これはまんま「3部屋+携行」なのだが、それぞれの最終システムインストール日を見ると

  • ThinStation P720 (2019-01)
  • FM2A88X (2017-12)
  • Z400 Workstation (2019-07)
  • ThinkPad X1 Carbon 5thGen (2018-06)

である。ちなみに、これはjournalctlすれば分かる。

システムセットアップ時に悩ましいのがフォントだ。 ここではManjaroを前提にして語るが、日本語フォント関連のパッケージは“font japanese”で検索すると62ほどあり、うち公式パッケージは源ノ角ゴシック、源ノ明朝、IPAフォント、花園明朝、さざなみフォントである。

フォント関連のAURパッケージはあまりメンテナンスされないことが多く、多くのフォントを維持するのはかなり厳しい。インストール時間もかかるので入れるのもしんどい。 ひとつにまとめて、それを/usr/local/share/fontsなどに入れて運用する方法もあるのだが、商用フォントの除外という手間もあるし、OS側(/usr/share/fonts)との兼ね合いもディストリビューションが違ったりすると特に発生しがちなので割と難しい。

なにより、「フォントの数」と「画面の総ピクセル数」は ものすっごく 反応速度に影響するのだ。遅い遅いと思っていたマシンをまっさらにして1366*768なディスプレイをつないだら爆速になったりしている。 だから、メインマシン(もしくはフォントを使うようなアートワーク作業をするマシン)だけにフォントを積んで、他はessentialに運用したい。

ここでは私の経験に基づいてよいと判断したessentialを紹介するが、好みによることはご了承いただきたい。

先に結論

% trizen -S adobe-source-han-sans-jp-fonts adobe-source-han-serif-jp-fonts ttf-cica ttf-ume
  • 商用フォント顔負けのクオリティで出せる源ノ角ゴシック、源ノ明朝
  • zsh-theme-powerlevel9kpowerlineを入れた場合に必要になるpowerlineシンボルなどまでカバーし、日本語コーディングフォントを必要する場合に有用なCica
  • MS日本語フォントにメトリック互換の梅フォント

という構成である。

好みのちょい足し

もう少し意味を補強すると、IPAフォントがあるとLibreofficeで文書をやりとりするようなケースでは有効である。 IPAフォントは公式パッケージなのでインストールしてもいいかもしれない。

さらにいえば、コーディングフォントは日本語フォントである必要はなかったりする。 私が様々なコーディングフォントで様々なコードや文章を書いた経験で言えば、長時間使っていて快適性が高かったコーディングフォントは

  • Hermit
  • Input Mono
  • Fira Mono
  • Meslo
  • Camingo Code
  • Roboto Mono

だった。

あと、私は個人的にMiguも好きなので、

% trizen -S otf-ipafont ttf-migu otf-hermit

好みのちょい盛り

ひょっとしたらスタイリッシュな欧文フォントがないことが不満かもしれない。 定番としてはSenとかだったと思うのだけれど、今SenはGoogle Fontsから外れてしまった。 Overlockも定番。これは個人的には静凛さんのチャット欄がOverlockなので馴染みがある。

ManjaroのロゴフォントであるComfortaaは最近のManjaroはデフォルトで入っていたりする。

あと、Joseffin Sansも好き。

かっこいいSerifフォントが欲しい、とかいうと特に定番はないので、GoogleでSerifカテゴリを選択して探していただくのがよかろう。 Serifフォントに関しては私は商用のHumanist Slab 712を使っていたりするし。 どうしてもお勧めというのであれば、MartelとかCormorant Garamondとか、Abhaya Libreとかだろうか。

そして個人的には源ノ角ゴシックも良いが、やっぱりモトヤフォントが好きだ。 それにこのラインナップでは丸ゴシックがない。

そこで小杉ゴシック小杉丸ゴシックだ。 小杉ゴシックは元「モトヤ Lシーダ W3等幅」、小杉丸ゴシックは「モトヤ Lマルベリ W3等幅」のリネームである。 これらはApache Lisence 2.0でAndroidに載っていたフォントだ。

好みの盛り盛り

ドキュメントを書く上で使いやすいフォントに欠けるので、源暎フォントを追加している。 ただし、これはドキュメント生成、つまりPandocを使う端末のみ。

あと、本文フォントは「源暎ラテミン」よりも「元陽逆アンチック」のほうが人気があるので、それも入れておく

セットアップ

言葉はいらないよな?

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Re-define sans-serif, serif and monospace.</description>
    <match target="pattern">
        <test qual="any" name="family">
            <string>sans-serif</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Joseffin Sans</string>
            <string>MotoyaLCedar</string>
            <string>Source Han Sans JP</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>serif</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Overlock</string>
            <string>GenEi Koburi Mincho</string>
            <string>Source Han Serif JP</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>monospace</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Hermit</string>
            <string>Cica</string>
            <string>Migu 1M</string>
        </edit>
        -->
    </match>
</fontconfig>
<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
        <its:translateRule translate="no" selector="/fontconfig/*[not(self::description)]"/>
    </its:rules>

    <description>Substitude popular Japanese fonts</description>

    <match target="pattern">
        <test qual="any" name="family">
            <string>MS Pゴシック</string>
        </test>
        <test qual="any" name="family">
            <string>MS PGothic</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Ume P Gothic S5</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>MS P明朝</string>
        </test>
        <test qual="any" name="family">
            <string>MS PMincho</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Ume P Mincho</string>
        </edit>
    </match>
    <match target="pattern">
        <test qual="any" name="family">
            <string>MS明朝</string>
        </test>
        <test qual="any" name="family">
            <string>MS Mincho</string>
        </test>
        <edit binding="strong" name="family" mode="prepend">
            <string>Ume Mincho</string>
        </edit>
    </match>
</fontconfig>

【Manjaro/Arch Linux注意】Yaourtは廃止になりました

すごくニュースだと思うんだけれど、全然話題になっていないけれど。

AURヘルパーである YaourtはAURからなくなりました

もう随分長いこと「非推奨」とされてきたのだけれど、ついになくなった、というかたち。

AURヘルパーの中ではYaourtが最も親しまれてきたし、最も有名だった。 「Yaourtを使う」というのが当たり前になってもいた。

けれど、近年はセキュリティ上の問題があり、メンテナンスされていないことからobsolateになっていた。 で、今ついにAURからなくなった、ということ。

これに伴って、CommunityパッケージになっていたManjaroでもYaourtは廃止に。

今後はyayなり、Trizenなりを使っていくことになる。

そのうち「Yaourtを野良ビルドして使う」みたいな記事が出てきそうだけれども、 危険なのでやめましょう

Archwikiでは2019-05-20現在、日本語版はそのままであるものの、英語版はYaourtに関する記述自体が削除されている。

systemd-nspawnでManjaro LinuxからArch Linuxする

systemd nspawn

なんかSystemdを毛嫌いする人が多いのだけど、結構使いやすくて便利な機能が多いので、私は好きだ。Xサーバーみたいだと思う。

systemd-nspawnはcrgoupsを利用したLinuxコンテナである。 LXCよりもずっとシンプルな実装で、かつ簡単に使うことができる。 全然知られていないけど。

とりあえずArchする

Manjaroにもarch-install-scriptsがあるためpacstrapできたりする。 なので、初回インストール前には

# pacman -S arch-install-scripts

とやっておく。

そしたらコンテナを作る。 こちらは新規コンテナを作るときにやる作業。

# pacstrap -i -c ~/Container base base-devel

Arch Linuxをインストールしたことのある人ならわかると思うのだけど、 最低限baseがないと機能しない。そして、AURを利用する場合はbase-develも含んでおかないといけない。

あとはログインする。 これは、起動時に実行するもの。

# systemd-nspawn -b -D ~/Container

これでコンテナを起動することができる。終了する場合、コンテナ上で電源を切る。 終了は少し時間がかかる。

# poweroff

LXCと違って自動的にブリッジインターフェイスもセットアップされ、起動しただけでネットワークがちゃんと機能する状態になる。 LXCと比べても随分と話が早い。

ManjaroだとArchを構築するのは簡単だし、もちろんArchやAnterogosでも簡単だけど、そうでないディストリビューションがどうやってコンテナ上にOSをインストールするか、については各々調べて欲しい。 私はArchが使えれば満足なので、コンテナ上で他のディストリビューションを使おうとは思わないし、現状、Manjaro以外をホストにしようとも思わないからだ。

おまけ。この環境からPowerlevel9kするために

ちょっとつまずいたのでおまけ。 標準ロケールがen_US.utf8になっているため、Powerlevel9kのPowerline記号が出ない。

そこで、/etc/locale.genを編集してja_JP.UTF-8 UTF-8をアンコメントし、

# locale-gen

そして、/etc/locale.confを編集してLANGja_JP.UTF-8にしてから

# localectl set-locale LANG=ja_JP.UTF-8

これでちゃんとPowerlevel9kのアイコンが出るようになる。

(Manjaro Linux) KDE PlasmaでXFce4通知が使われる

先日のAdaptaのアップデートからManjaro XFce4からインストールした環境で使用しているKDE Plasma上で通知が黒背景黒文字になるという問題が発生していた。

KDE Plasmaの通知を設定しても全く改善されないためどうしたものかと非常に困っていたのだが、 よく見てみるとKDE Plasmaの通知ではなく、XFce4 Notifyになっていた。

そこでxfce4-notifydを止めたいと考えたのだが…

xfce4-notifydはsystemdユーザーユニットとして存在していて、/usr/lib以下にコマンド本体がある。 だからsystemctl --user stop xfce4-notifydで一応止まるように見える。 (場合によってはkillする必要がある)

ところが、ここでnotify-sendするとふたたび起き上がってきてしまう。

これを止めるジェントルな方法を模索したのだが、見つからなかったので、仕方なく/usr/share/dbus-1/services/org.xfce.xfce4-notifyd.Notifications.serviceを削除(というか外へ移動)した。 これは恐らく意図以上の影響を及ぼすだろうが、とりあえず当面の問題は解消できた。

Arch / Manjaro open-iscsiのサービスユニット名が変更

Manjaro Linux Stable Update 2018-10-25でopen-iscsiのサービスユニットがopen-iscsi.serviceからiscsi.serviceに変更になった。 これはArch Linux側でも行われた変更である。

結果的に、open-iscsiに依存しているユニットが正常に起動できなくなった(特に自作したサイトローカルユニットは)。 それに加え、従来open-iscsi.serviceをenableにしていた場合でも起動されなくなった。

必要な対応は以下の通り。

まず、open-iscsi.serviceという名前を用意する場合

  • /usr/lib/systemd/system/iscsi.serviceAlias=open-iscsi.serviceを書いておいた上でenableする
  • または/usr/lib/systemd/system/open-iscsi.service -> /usr/lib/systemd/system/iscsi.serviceというシンボリックリンクを用意する

iscsi.serviceという名前に合わせる場合

  • 他のユニットでopen-iscsi.serviceとなっている箇所を全てiscsi.serviceに修正する
  • 必要ならばiscsi.serviceをenableする

これはイニシエータの話だけれども、ターゲット側もopen-iscsid.serviceからiscsid.serviceに変更されているので同様である。

AMD APU (A10-7870K Godavari) * Radeon VCE * AMDGPU * VA-API * ffmpeg

理屈としては解説してきたものの、実際にVA-APIでVCEを叩いたことがなかったのでやってみた。 ついでなので、qsvやnvenc、あるいはlibx264などでも応用できるウェブカメラとスクリーンキャスティングの話もしておく。

基本的な手順は単純で、AMDGPU(事実上現在唯一となったAMDビデオドライバ)を選択した上で、 VA-APIを有効にし、VA-API経由でエンコーディングを行う。

注意点としては古くなったプロプライエタリドライバ(Catalyst)ではなく、AMDGPUドライバーを使用することと、 MESA VAドライバを使用することである。

RadeonはVA-API/VDPAUの両方をサポートしており、NvidiaのようにVDPAUドライバをインストールし、VA VDPAUアダプタを使用するという方法(libva-dvpau-driver)も成立してしまう。 しかし、この場合は動作しなくなるので、必ずMESA VAドライバ(libva-mesa-driver)を使用する必要がある。

その上で基本はこんな感じ。 (Arch/ManjaroのffmpegはVA-APIを含んでいるのでffmpeg云々の話はない)

$ ffmpeg -vaapi_device /dev/dri/renderD128 -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy outfile.mp4

ffmpeg上でのVA-APIは公式にドキュメントがある

ソースファイルがビデオアクセラレーションが効くのであればUVDをVA-API経由で叩いてデコードすることもできる。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy outfile.mp4

ところがこれではうまくいかなかった。 一件成功しているように見えるのだが、フレームの全くないビデオファイルが出来上がってしまい再生できない。

多分、新しいRadeonだとそんなことはないのだろうと思うけれども、Godavari(2015年)のR7グラフィックスでは問題があったため、-profile 578を指定すると解決した。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -bf 0 -qp 24 -c:a copy outfile.mp4

ウェブカムからキャプチャする場合はエンコードのみ、入力はv4l2:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f v4l2 -i /dev/video0 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 outfile.mp4

さらにマイクをPulseAudio経由で拾う場合。音声は192k AAC:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f v4l2 -i /dev/video0 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

X11のスクリーンキャスティング 音声つき。 A10-7870Kだとh264_vaapiは34fpsくらいなので、60fpsはフレーム落ちばかりになる。30fpsも無理で24fpsがドロップしない限界。 ultrafastにした場合は30fpsは可能だけれど60fpsは無理。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 24 -video_size 1920x1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

ultrafastで30fps:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size 1920x1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

なお、-video_size-iよりも先に指定することが必須である。基本的にffmpegはオプションは順番に厳しい。

300×300のウィンドウを左上から200×200のオフセットで録画する場合

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size 300x300 -i $DISPLAY+200,200 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

-video_sizeの指定方法は色々あって、公式ドキュメントで解説されている。 なので、-video_size 1920x1080ならば-video_size hd1080とも書ける。

録画領域を表示するには-show_region 1

$ ffmpeg -show_region 1 -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size hd1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

NVENCだとmkvにもできるので音声はFLACやOpusで撮ることもできるのだけど、AMDGPU VA-APIはmp4だけ

使ってみた感想としては、QSVと違ってCPUがあくのは良いけれど、R7の速度自体がCPUと大差ない(libx264でやったのと同程度)であるため、ちょっと微妙かもしれない。 A10でもスクリーンキャスティングしながら配信みたいなことができるというメリットはあるけれども。

Linux: 特定のアドレスに到達しないことを明示する (route/ipコマンド)

open-iscsiを用いたiSCSIイニシエータの場合、iSCSIターゲットが複数のIPアドレスを持っているとMultipathによってその全てのアドレスで接続しようとする。

だが、例えば192.168.1.0/24に属するコンピュータで、192.168.1.0/24, 192.168.2.0/24の両方に属しているNASを使おうとすると、192.168.2.0/24に対する経路がなければタイムアウトするまでひどく待たされることになる。 デフォルトゲートウェイ経由で192.168.2.0/24に対するパケットを投げ続けるためだ。

そこで、このコンピュータは192.168.2.0/24には通じていないことを明示して、即座に失敗させたい。

これはネットワークマネージャの設定では行うことができない。 コマンドで行う必要がある。

routeコマンドに関してはManpageに書いてあるのでわかりやすい。

# route add 192.168.2.0 netmask 255.255.255.0 reject

だが、Arch Linux系列のディストリビューションで標準採用されるipコマンド (iproute2) のほうは1Manpageがものすごく読みにくい上に日本語訳もされていないのでちょっと大変だ。 ipコマンドの場合は次のようにする。

# ip route add prohibit 192.168.2.0/24

これにより192.168.2.0/24に対する接続はそもそも禁止されることになる。

% ping 192.168.2.64
Do you want to ping broadcast? Then -b. If not, check your local firewall rules.
% telnet 192.168.2.64
Trying 192.168.2.64...
telnet: Unable to connect to remote host: 許可がありません

  1. そもそもrouteやifconfigなどを使わず、iproute2(ip)を使うということをどれくらいの人が知っているのだろう? arp, ifconfig, iwconfig, nameif, netstat, route を兼ねる仕組みになっており、Manjaro Linuxではこれらのコマンドは標準では入っていない。 digやnslookupも含まれておらず、getentを使用する。

【注意】 Arch/Manjaro 最新 open-iscsi パッケージにバグ

Arch / Manjaro Linux の最新 open-iscsi パッケージをインストールすると、 libopeniscsiusr.so.0.1.0 というライブラリが欠如しているためにiSCSIが動作しなくなる。

システム構成の中核部に採用している場合はシステムが利用できなくなるため要注意。

有志がAURのgitバージョンからビルドした2.0.876-2をアップロードしており、このパッケージはManjaroでもそのまま動作する。

Manjaro 16.08 Preview

Manjaro 16.08 ELLADA

Manjaro LinuxはArch Linux派生のLinux Mint的なディストリビューションである。
初心者向けを標榜してはいるが、あんまり初心者向けではなく、Archから一般的用途においてこだわりよりも簡便であることを優先したものと思えば良いだろう。

その最新バージョンであるManjaro Linux 16.08 ELLADA。
8月31日に正式リリースされたが、今回のストレージクラッシュによる長時間の利用不能を利用してシステムのクリーンナップを兼ねて256GB SSDへの移行を再インストールで行い、Manjaro Linux 16.08 Pre5を試した。

Manjaro LinuxはArch Linux同様のローリング・リリースであり、どのバージョンからインストールしても常に最新のバージョンが保たれる。
しかし、新パッケージに含まれない変更も存在するため、インストールしたバージョンによって少し環境が異なってくる。
(なお、Arch Linuxではほとんど差が出ない)

これまでManjaro Linux 16.06ベースまでは試していたが、16.08は試していなかった。その変更点が重要だったため、少し言及する。

Calamaresインストーラ

これまでManjaroのGUIインストーラはThusとCalamaresのふたつがあった。

Thusが旧来のもので、ずっと「ベータ版です」と警告されていた。
そして、Thusは正式版になることなく開発停止され、ManjaroはCalamaresに移行していた。

Calamaresは汎用インストーラであり、Manjaro/NetRunnerのほか、FedoraやopenMandrivaも協力している。

だが、その完成度は低く、

  • ファイルシステム指定が十分に機能しない
  • LUKSが使用できない
  • LVMの利用もうまくいかない場合が多い
  • UEFIインストールもうまくいかない
  • 要は手動パーティショニングでは何もできず、自動インストールでもなんの選択肢もない

というもので、事実上Thusを使うしかなかった。

ところが、16.08からThusが削除され、Calamaresだけになった。
「当面は最新ISOは無理か!?」と思いきや、長年の問題とされてきた手動パーティショニングの問題をついに解決したというだけあって、LUKS暗号化を含めちゃんと機能するようになっていた。

今回は

  • SSD
  • GPT+BIOS
  • 2パーティション(/boot=EXT3, /=XFSonLUKS)

という構成にした。
XFS on LUKSはXFSを選択して「暗号化する」という選択だけなので難しさはない。LVMはインターフェイスがないので、LVM PVを選んでもどうだろう?

/bootはdefaults,noatime, /はdefaults, noatime, discardオプションとなった。
ルートファイルシステムに対するnoatimeはパフォーマンスは向上するが、セキュリティ的には決して推奨できないので注意(ただし、調査・検証を行う人に限る)。SSDに対するdiscardはきちんと認識されてオンにされる。

アートワーク

アートワークの改善に力を注いでいるそうで、/usr/share/backgournds以下に大幅にファイルが追加された。

これによりManjaroを活かした壁紙を設定する場合の選択肢が増えた。ただし、初期設定の背景フォルダとして指定されていないため、多くの人は気づいていないだろう。

VLC

標準で採用VLCがextravlcではなく、vlc-nightlycommunityとなり、VLC3系となった。

ディスク故障でbtrfsの機能を使い倒す

対応方法

ディスク容量が逼迫しているので何らかの対処が必要である。
とりあえず考えられる方法としては

  • ディスクを大容量のものに交換する
  • USBあるいはeSATA接続のディスクを追加する
  • NASを追加してディスクを追加する
  • AoEを使って他ホストのディスクを追加する
  • 内蔵ディスクを追加する

のいずれかだ。そもそも取り扱うデータ量が多いため、削減ということは考えられない。
もちろん、削減自体は行っているが、その精査にあてる時間のほうが重要で、無効な対策であると考えられる。それほど引き延ばすこともできない。

大容量への交換は効果的だが、現在3TBを使用しており、4TBの場合は33%の容量増となり、不足である。
6TB以上は高額すぎるため却下された。

USB/eSATAを最も有力な候補としていたが、台数搭載するためには金額的にも高く、またいずれの製品も信頼性に劣るようだ。

多数搭載のケースを使用するのであればReadyNASも有力な候補だった。ReadyNASはiSCSIに対応するが、「ReadyNASに搭載されているディスクを指定する」ことはできない。何台搭載しても、btrfs的に見れば1台にしかならないのだ。

そのため、btrfsで管理するためにはReadyNASを複数台追加する必要がある。ReadyNAS全体でbtrfsから見て1台のディスクであり、ReadyNASの台数=ディスク台数になる。
btrfsは不均等なRAID1をサポートするため、例えばReadyNASに12TBを搭載すれば12TB RAID1を構成することが可能だが、あまりうれしくはない状態になる。

AoEを使うのは追加費用のかからない方法だ(ディスクとホストはあるため)。
だが、問題はAoEを使う方法は常に

  • マウント前にターゲットホストを起動していなければならない
  • アンマウント前にターゲットホストを終了してはいけない
  • ネットワークを切断してはいけない

と結構厳しい条件になる。
ターゲットホストが消費電力が大きく、また冗長系システムであり、日常稼働しているものであることを考えるとこれは厳しい。

そこで内蔵ディスク追加を選択した。

Z400の3.5inchシャドウベイの数は2、SATAポート数は6である。
現在、iStarUSAの5.25inchベイ*2を3.5inch HDD*3に変換するリムーバブルラックを使用してシステムSSDを含む計5台を搭載している。
そのため、2台追加となると、マウント的にもSATAポート的にも足りない。

採用した方法はエアリアのSATA*2 PCI-e 1xカードによりポートを2増設し、DVDドライブを除去してiStarUSAの5.25inch*3をHDD*5に変換するリムーバブルラックを搭載するというもの。

かなり無茶だが、さらに無茶なのが、そもそもビデオカードがGeForce GTX750Tiに変更されているために、隣のPCI-e 4xが埋まってしまっており、逆側のPCI-e 4xは使用済みなので、PCI-e 16xに接続した、ということか。

ディスク追加手順

ディスクの追加は、ディスクを装着した状態で

# btrfs device add /dev/sdx /path/to/volume
# btrfs device add /dev/sdy /path/to/volume
# btrfs balance /path/to/volume

のようになる。
balanceの所要時間は果てしなく、うちのケースでは40時間ほどかかった。

そして、balanceがまもなく終わろうという頃に、もともとあったほうのディスクが壊れた。

故障ディスクの除去と交換

故障ディスクが正常にアクセスできない状態にあるとき、btrfsファイルシステムへのアクセスはシステム全体を止めてしまう。
この状態ではbtrfs device deleteもできない。

もしこれが可能な状態であればdeleteよりも新規ディスクも装着した状態でのreplaceのほうが早い。

故障ディスクはオフラインの状態でまず除去してしまい、その上で新規ディスクに交換する。
そして、新規ディスクに対して

# btrfs device add /dev/sdx /path/to/volume

したあと、

# btrfs device delete missing /path/to/volume

するとreplaceに近い挙動になる。

しかし、実際にやるとシステムが死んでしまった。ログにがっつりRIPが残っていた。

ファイルシステム新規作成

もはや修復は不可能なので、ファイルシステムを再作成してバックアップから書き戻す。

dm_crypt上に作成するのであれば、dmデバイスを用意したうえで

$ sudo mkfs.btrfs -L labelname -d raid1 -m raid1 /dev/mapper/crypt_dev_*

こうしてみると気づくのだが、btrfsのミラーリングはミラーレッグの指定ができない。
ジャーナリングの強化版というコンセプトなので当然なのかもしれないが、結構不安。本物のRAID1がほしい人はLVMを使うほうが良さそう。LVM+Btrfsであれば、2台ずつ容量を揃える必要があるが、容量の異なるディスクを混在できる。

バックアップのbtrfsファイルシステムからのリストア

btrfsにはsend/receive機能があり、簡単にバックアップができる。

btrfs sendは差分も可能でストリームで送られる。つまりファイルとして保存することもできる。
この場合復元はcatによって行うことになるだろう。差分だとどうなるのかはわからない。

recieveはsendによって出力されるストリームを元にファイルへと書き出す。

ネットワーク越しのバックアップ手段として行う場合は、権限的な難しさがある。send/receiveはroot権限が必要なためだ。
rsyncであればユーザー権限でのバックアップが可能だが、send/receiveを使う場合はそうはいかない。
受け渡しをssh経由で行おうとすると、rootでのsshアクセスを許していなかったりして結構なネックになる。
別に鍵を作れば良い話ではあるが。

sudoを用いたコマンドラインで行うのであれば、socatを使用する方法がある。receive側は

$ socat tcp-listen:30000 | sudo btrfs receive /path/to/volume

send側は

$ sudo btrfs subvolume snapshot -r /path/to/volume /path/to/snapshot
$ sudo btrfs send /path/to/snapshot | socat stdin tcp-connect:receiverhost:30000

経路安全性を問題にするのであれば、openssl-listenを使うか、ssh -Lを使うなどの方法がある。
インターフェイスを限定できないのが問題なら、rubyワンライナーを使う方法や、もうひとつプログラムを増やし、ソケットで読んで書き込む仕様として、ssh経由でソケットに出力するプログラムを起動するという方法もある。

例えば次のようなスクリプトである。

#!/usr/bin/zsh
zmodload zsh/net/socket

zsocket -l /tmp/btrfs-syncer
sock=$REPLY
while zsocket -a $sock
do
  (
    btrfs receive /path/to/volume <&$REPLY
  ) &
done

こちらはrootで実行する。対してsshで実行すべきは

#!/usr/bin/zsh
zmodload zsh/net/socket
zsocket /tmp/btrfs-syncer
cat >&$REPLY
exec {REPLY}>&-

あとは

$ sudo btrfs subvolume snapshot -r /path/to/volume /path/to/snapshot
$ sudo btrfs send /path/to/snapshot | ssh receivinghost.locadomain btrfs-syncer-client

注意点として、例えばsubvolというサブボリュームに書き戻したい場合、subvolというサブボリューム上にreceiveすると結構困ってしまう。
その場合はそのペアレントボリュームにreceiveした上で(snapshotの名前になってしまうので)mvするのが正しい。

なお、mvしてもreadonlyのままになるため、ロールバックするためには属性変更が必要。

$ sudo btrfs property set -ts subvol ro false

ro trueでreadonly。
IDによるマウントを使っているのであれば、set-default

追加のクリティカルヒット

しかし、またも/dev/sdgの大量エラーという結果になった。一見すると正常だが、ログを見ると1.77TiBの書き込みの間に71456ものblk_update_requestが発行されている。

2度続けてsdgだったため、ケーブル、ラック、ボードのいずれかが問題である可能性も考えられたため、ディスクを入れ替えて(/dev/sdfの位置にあるディスクと入れ替えた)試したところエラーはなく、ディスクの不良と断定。初期不良を申請し、翌日回答、翌々日到着となった(NTT-Xの対応は早い)。

ちなみに、NTT-Xにディスクの初期不良対応を申請したところ、

  • メーカーに確認→メーカー回答を得て応答(交換or返金)→交換の回答を得て発送→到着時に集荷として引き渡し

という手順だった。

交換ディスクは

# dd if=/dev/zero of=/dev/sdf bs=512M

として全域書き込みを行い、

# journalctl --no-pager | grep -F blk_ | tail

としてblk_update_requestが発生していないことを確認した。

そして前述の通り、新規ファイルシステム作成、マスターボリュームのマウント、socatと連動したsend/receive、リネーム、プロパティ変更と行い、エラーがないことを確認した。
なぜか全域でデータ量が5.30TiBまで減少していた。

しかしtopで、kworker/3:2及びksoftirqd/3が張り付いたままになっている。
kworkerはおそらくbtrfs絡みだろうし、ksoftirqdが固まっているということはディスク処理だろうから、しばらく待つことにする。特にkworkerはずっとS欄がR(Running)であり、明らかに忙しくしているので安全を考えて待つ。

結局kworderがしずまらなかったので、syncしてunmountし、それが問題なくunmountされたことを確認してからreboot。

エラーが何もないことを確認して、おそらくこれで完了。
とてもとてもとても大変だった。