Thinkpad x220にUbuntu 16.04をbcache付きでインストール

 昨年入手した中古Thinkpad x220にUbuntu 16.04をインストールしました。インストール自体は中古で入手したときに行っていましたが、今回は一旦ご破算にしたのちにbcache付きで導入しています。

wakimiunten.hatenablog.com

 割りと煩雑な手続きだったので、メモがわりにここに書いています。

現在、/boot 以外の全てのディレクトリがキャッシュされています。なお、スワップ領域はbcacheを通さずにSSDの別パーティションに置いています。

効果はてきめんで、ブート速度やアプリの起動速度はHDDとは段違いに速くなりました。

 

bchaceとは

今回導入したbcacheは、SSDをHDDのキャッシュとして使用する仕組みです。

これは大容量で安いものの遅いHDDを、小容量で高いものの速いSSDでキャッシュするアイデアであり、同様のものがWindows用にIntel SRTとして公開されています。

www.intel.co.jp

入手したThinkpad x220には300GBのHDDが搭載されているほか、MSATAスロットが空きスペースとして実装されていました。そこで、ここに64GBのMSATA SSDを装着し、キャッシュとして使用することにしました。

KingSpec 64GB mSATA3 MINI PCI-E MLC Solid State Drive 64gb mSATA SSD

KingSpec 64GB mSATA3 MINI PCI-E MLC Solid State Drive 64gb mSATA SSD

 

 bcacheはUbuntu 16.04の標準レポジトリに採用されているため導入は簡単です。しかし、設定はわりと面倒で難儀しました。Intel SRTのような「全部お任せ」ではないため、自分でパーティションを切り、何をキャッシュさせるのか、何をキャッシュさせないのか、きちんと頭にたたき込んで設定する必要があります。

私はデスクトップPC上のVMwareで練習してからインストールを行いました。

ボリュームとパーティションの計画

bcacheを効かせるには事前に周到な計画が必要です。VMwareで試行錯誤した結果、以下のような構成に決めました。この構成は、Ubuntuのインストール・メディアで起動した直後、インストーラを走らせる前にgpartedで構成しておきます。

/dev/sdaはHDDです。

これは本体のHDDスロットに格納されている300GBの2.5inchドライブで、SATA接続ではあるものの、速度は凡庸です。以前はこれでブートしていたため、起動時間の間は大変手持ちぶさたでした。  

パーティション 容量 フォーマット 用途
/dev/sda1 300GB クリア /

/dev/sdcはSSDです。

何故これが/dev/sdbではなく/dev/sdcかというと、今回はUSB SDカードアダプタからブートしたからです。手元のUSBメモリはいずれもUSB 2.0ポートからブート出来ず*1、手持ちのThinkpadに USB 3.0ポートが無かったのでこうなりました。いずれにせよ、現在では/etc/fstabはuuidでディスクを管理しているため、インストール後に/dev/sdcが/dev/sdbになっても問題はありません。

さて、/dev/sdcの肝心の中身はというと3つのパーティションに分かれています。 

パーティション 容量 フォーマット 用途
/dev/sdc1 1GB ext4 /boot
/dev/sdc2 48GB クリア /のキャッシュ
/dev/sdc3 15GB linux swap スワップ

 /dev/sdc1 は /boot を格納するパーティションです。これはbcacheの管理外に置いています。何故こうしているかというと、grubが /boot の中のLinuxカーネルを探す段階では、grubはbcacheが効いたドライブを扱えないためです。1GBは特に考えずに参考ページを元に決めました。実際には100MBくらいしか使っていませんが、アップデート時にカーネルの整理を怠ると古いバージョンが保管されて増えていきますので、あまりパーティションを絞らない方がいいでしょう。

 用途を見るとわかるように、/dev/sda1 は /boot以外の / を記録するデバイスになります*2。一方、/dev/sda1 のデータをキャッシュするのが /dev/sdc2 です*3

 注意すべき点は /dev/sda1 と /dev/sdc2 のフォーマットです。これはいずれも「クリア」にしておいてください。ext4にするとシステムが認識してしまうため、あとでbcacheツールで扱うときにエラーが起きる可能性があります。私の場合、エラーが起きると最初からインストールを全部やり直しになりました。

/dev/sdc1 と /dev/sdc3 のフォーマットは、最初にgpartedで指定してもかまいませんが、 /dev/sdc1 はインストール中に再度設定を強いられますので二度手間です。

インストール・メディア

私はいつもUbuntuのインストールディスクのISOイメージを、unetbootinを使ってUSBメモリに焼き込んで利用しています。好きな方法を使用してください。

作業手順

作業はInstalling Ubuntu 15.10 with bcache support.bcache.txt - kandamotohiroを参考にしながら行いました。

全体の流れとしては

  1. Ubuntuインストール・メディアで起動する
  2. gpartedでSSD/HDDのパーティションを切る
  3. bcache-toolをリポジトリから取得し、SSD/HDDでbcacheのペアを作る
  4. bcacheボリュームにUbuntuをインストールする(再ブートしない)
  5. chrootしてインストール先での作業に移る
  6. bcache-toolをリポジトリから取得する。
  7. chrootを終了してインストール先での作業を終え、再ブートする
  8. ネットワーク設定を戻す

 となります。bcacheの取得が二度にわたることをいぶかしんでいらっしゃる方も居るかも知れませんが、これはインストール・メディア上でbcacheを使うのに1回、インストール先にbcacheを入れておくのに1回行うためです。

Ubuntuインストールメディアで起動する

この手順に特に難しい点は無いはずです。Unetbootinの情報はネット上で広く入手可能です。

インストール先のPCは後でbcacheを入手するためにネットワークに接続されている必要があります。

なお、インストール・メディアからの立ち上げは「インストールせずに使ってみる」を選びます。起動語にいきなりインストールを始めるメニューの場合、bcacheを設定できません。

gpartedでSSD/HDDのパーティションを切る

起動したら、先に示したとおりSSD/HDDのパーティションを切ります。繰り返しになりますが、キャッシュおよびバックに使うパーティションはフォーマットを「クリア」にしておきます。

bcache-toolをリポジトリから取得し、SSD/HDDでbcacheのペアを作る

パーティションを切ったらbcache-toolsを取得して、bcacheのペアを作りましょう。当然ですが、ネットワークに繋がっていなければなりません。また、/dev/sda1と/dev/sdc2をext4などにしておくと、ここでエラーがおきますので注意してください。

sudo apt-get update
sudo apt-get install bcache-tools
sudo make-bcache -B /dev/sda1 -C /dev/sdc2
ls /dev/bcache0 

 成功すると、/dev/bcache0という新たなブロック・デバイスが作られます。このデバイスは「/dev/sdc2でキャッシュされた/dev/sda1」です。

bcacheボリュームにUbuntuをインストールする(再ブートしない)

/dev/bcache0ができたら、Ubuntuインストーラを立ち上げてインストールします。インストール先に少し注意してください。先ほど作った /dev/bcache0 が、/ のインストール先になります。

パーティション フォーマット マウント位置
/dev/sdc1 ext4 /boot
/dev/bcache0 ext4 /
/dev/sdc3 linux swap スワップ

フォーマットはここで指定します。

grubブートローダーは/dev/sdaがいいでしょう。PCがブート可能であるなら/dev/sdcでも別にかまいません。

なお、この方法ではボリューム暗号化を使えませんので、プライバシー保護を行う場合にはホームディレクトリを暗号化してください。

なお、インストール終了後、くれぐれも再起動をかけないように気をつけてください。間違って再起動してしまった場合、再起動はインストール・メディアから行ってください。そして再度bcacheパッケージをapt-getで取得します。

chrootしてインストール先での作業に移る

さて、一番の山場です。

ここまでの作業で、インストーラー・システム上でターゲット・ディスクをbcache化し、そこにUbuntuをインストールしました。しかし問題が残っています。インストールしたUbuntuにはbcacheパッケージがインストールされていないのです。

そこで、これを解決するために次のようなトリックを使います。まずインストーラー・システム上で、ターゲット・システムを仮に動かします。そしてターゲット・システムがbcacheパッケージをリポジトリから取得すればいいのです。まるで仮想環境のようですが、unixには昔からこの手の仕事をこなしてきたchrootというプログラムがあります。

手順は以下の通りです。

sudo mount /dev/bcache0 /mnt
sudo mount /dev/sdc1 /mnt/boot
sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys

 インストール先(ターゲット)の/を格納している/dev/bcchace0をインストーラ・システムの/mntにマウントし、その下に/bootをマウントしています。/dev /proc /sys はここでは親システムのもので代用しています。/varは作っていませんので後でエラーが出ますが、無視できるようです。

また、後でインターネットにアクセスしますので、ターゲットの/etc/resolv.confを現行システムのそれに置き換えます*4

sudo cp /etc/resolv.conf /mnt/etc/resolv.conf 

 これで準備ができましたので、作業環境をターゲットに移します。

sudo chroot /mnt
 bcache-toolをリポジトリから取得する。

 インストールしたUbuntu(ターゲット)に移ってきました。つづいて、ここでbcacheをリポジトリから取得します。

sudo apt-get update
sudo apt-get install bcache-tools 
chrootを終了してインストール先での作業を終え、再ブートする

chrootを終了するにはexitを実行します。引き続き、先ほどマウントしたボリュームを全てアンマウントします。

exit
sudo umount /mnt/sys
sudo umount /mnt/proc
sudo umount /mnt/dev
sudo umount /mnt/boot
sudo umount /mnt
sudo reboot

 これで再ブートです。再ブートするとbcacheを使ったインストール先のシステムが動作を開始します。これで終わりと言いたいところですがひとつだけ残っています。

ネットワーク設定を戻す

先ほどインストーラ・システムに合わせて変更したネットワーク設定を戻しておきます。

sudo ln -sf ../run/resolvconf/resolv.conf /etc/resolv.conf 

 なんだかおかしな事をしているように見えますが、 "../run/resolvconf/resolv.conf" は、 /etc/resolve.conf のデフォルト値です。

これで設定は戻りました。ネットワーク設定の変更は再起動無しに適用する方法がありますが、せっかくbcacheを使い始めたので再起動しましょう。再起動する度に、キャッシュの精度があがります。

bcacheの状態を見る

bcache.txt - kandamotohiroの「背後のデバイス」「背後のデバイスの統計」は、キャッシュ状態や動作モードを調べるのに便利なsysfsインターフェースを紹介しています。

キャッシュヒット率に興味のある人はモニターしてみると良いでしょう。

Thinkpadのバッテリー設定

さて、何度もこのブログに書いているように、Thinkpadにはバッテリーの寿命を縮めずに済むよう、最大充電量を制御する機能があります。これはPCの機能ですので、OSに関わらず、あるいはOSを起動していないときにも動作します。

Linux用にこの機能を使うユーティリティが公開されています。GitHub - teleshoes/tpacpi-bat: ThinkPad ACPI Battery Utilというユーティリティです。その使い方が、ThinkPadのバッテリーの充電・放電閾値をLinuxから設定してバッテリーの寿命を伸ばす方法 -- ぺけみさおに詳しく説明されていますので、そちらを参考にインストールと設定をしました。

まとめ

bcacheのおかげでHDDの広々とした容量とSSDの速さを享受できます。大変快適に使えるようになりました。

*1:USB 3.0ポートからはブートする

*2:バックと呼ぶ

*3:キャッシュと呼ぶ

*4:あとで元に戻す