Ubuntu Weekly Recipe

第568回overlayrootでUbuntuを一時的に読み込み専用にする

Ubuntuのoverlayrootパッケージを使うと、Ubuntuシステムを一時的または恒久的に「読み込み専用」として起動できます。今回はこのoverlayrootパッケージの使用方法を紹介しましょう。

overlayrootとは

LinuxのOverlayFSは、複数のディレクトリツリーをレイヤーのように重ねることで、一つのディレクトリツリーに見せかける仕組みです。

一般的な使い方としては、より下位の層を読み込み専用としてマウントしたディレクトリツリーとして用意し、上位の層を読み書き可能なディレクトリツリーとして用意し、そのふたつを重ねる方法です。これにより作成されたディレクトリツリーに対する変更は、すべて上位の層にのみ反映され、下位の層は変更されません。

身近な例だと、Dockerがストレージ・ドライバーのひとつとしてOverlayFSを採用しています。インスタンス作成時、ベースコンテナは下位の層として利用され、インスタンス用のレイヤーが上位の層として使われます。これによりインスタンスに対する変更はすべて上位の層に反映され、ベースコンテナは他のインスタンスでも流用できるのです[1]⁠。

overlayrootはこのOverlayFSを既存のUbuntu環境でも利用するためのツールです。具体的にはすでにインストール済みの環境を下位の層として利用し、上位の層をRAMや別のストレージデバイスとして指定することで、既存の環境を変更することなくUbuntuを起動できます。

overlayrootのインストール

overlayrootを利用するためにはoverlayrootパッケージをインストールしなくてはなりません。

実はサーバー版の場合は最初からoverlayrootパッケージがインストールされています。デスクトップ版のみ明示的にインストールが必要です。

$ sudo apt install overlayroot

インストールされるのは主に次の4つです。

  • 設定ファイルであるoverlayroot.conf
  • initramfs用の各種スクリプト
  • 下層レイヤーメンテナンス用のoverlayroot-chrootコマンド
  • overlayroot有効化時のためのMOTDファイル

サーバー版には最初からインストールされていることからもわかるように、overlayrootパッケージをインストールしただけでは、overlayrootは有効化されません。有効化するには次のいずれかの対応が必要です。

  • カーネルパラメーターに「overlayroot=XXX」を指定する
  • /etc/overlayroot.local.confに「overlayroot="XXX"」を指定する
  • /etc/overlayroot.confに「overlayroot="XXX"」を指定する

設定内容は上位のほうが優先されます。つまりカーネルパラメーターとoverlayroot.confの両方に設定を行っている場合は、カーネルパラメーターのほうが優先されます。

overlayrootの有効化

さっそくoverlayrootを有効化してみましょう。前述のとおり方法はいくつかありますが、今回は/etc/overlayroot.local.confを編集することにします。後ほどもとに戻す方法も説明しますので、安心して次のコマンドを実行してください。

$ echo 'overlayroot="tmpfs"' | sudo tee -a /etc/overlayroot.local.conf

上記設定を行うと次回起動時から、/etc/fstab上のルートファイルシステムを下位の層として、さらにRAMを上位の層としてマウントします。つまり上位の層への変更はすべて、揮発性のRAM上に書き込まれるため再起動時に削除されます。

具体的にはinitramfsの中の初期化スクリプトがoverlayfsとしてマウントし、/etc/fstabを書き換え、最終的に「/usr/lib/klibc/bin/run-init」を実行します[2]⁠。

たとえば次のようなfstabがあったとします。

UUID=1868998f-7acf-4dd4-8aee-fc44bee0033a /               ext4    errors=remount-ro 0       1

上記のようにoverlayroot.local.confを編集した場合、次のように変更されるのです。

#UUID=1868998f-7acf-4dd4-8aee-fc44bee0033a /media/root-ro/ ext4 ro,errors=remount-ro,noauto 0 1
/media/root-ro/ / overlay lowerdir=/media/root-ro/,upperdir=/media/root-rw/overlay/,workdir=/media/root-rw/overlay-workdir/_ 0 1
#overlayroot:swap=0#/swapfile none swap sw 0 0

UUIDで指定されたデバイス(本来のルートファイルシステム)は、/media/root-roにマウントされ、読み込み専用の下位のレイヤー(lowerdir)として設定されます。読み書き可能な上位のレイヤー(upperdir)は、今回tmpfsを指定しているためtmpfsとしてマウントされています。

実際に起動したあとの、/proc/mountsの中を見てみましょう。

$ egrep "overlayroot|/media/root-ro|/media/root-rw" /proc/mounts 2>/dev/null | sort -r
tmpfs-root /media/root-rw tmpfs rw,relatime 0 0
overlayroot / overlay rw,relatime,lowerdir=/media/root-ro,upperdir=/media/root-rw/overlay,workdir=/media/root-rw/overlay-workdir/_ 0 0
/dev/sda1 /media/root-ro ext4 ro,relatime 0 0

/dev/sda1が/media/root-roに、tmpfsが/media/root-rwにマウントされていることがわかりますね[3]⁠。

この状態でルートファイルシステムにいろいろと書いてみましょう。手っ取り早いのはホームディレクトリに何かファイルを作ることです。ソフトウェアも大抵のものは起動できますが、あまりディスクに大量のものを書くような処理は難しいかもしれません。

特にデスクトップ版の場合は、緊急時の対応用ぐらいに思ったほうが良さそうです。

いくつかルートファイルシステムに書き込んだ上で、再起動してみてください。試しにルートファイルシステムに書いた変更が、すべてなかったことになっているはずです。こんな感じで連休中に費やした無駄な時間もなかったことにできたらいいのに。

overlayrootの無効化

overlayrootを無効化するには、/etc/overlayroot.local.confの内容をもとに戻します。具体的にはファイルを削除するか、⁠overlayroot=""」のように空にしてしまいます。

ところでoverlayrootを有効化していると、ルートファイルシステムの変更は再起動後にリセットされます。つまりoverlayrootを有効化した状態だと/etc/overlayroot.local.confを変更できないのです。これは困りました。

当然のことながら、このような状態でも対応できるように作られています。取れる方針は次の2つです。

  • より優先度の高いカーネルパラメーターで無効化する
  • 一時的に低層のファイルシステムに書き込みできるようにする

たとえばGRUB起動時にメニューエントリーを表示し、起動オプションに「overlayroot=disabled」を追加すれば、その起動時はoverlayrootが無効化されます。一時的に無効化して起動したい場合に便利でしょう。

後者の方法はoverlayroot-chrootコマンドを使います。

$ sudo overlayroot-chroot

これだけで低層のルートファイルシステムが書き込み可能な状態で再マウントされます。/etc/overlayroot.local.confを恒久的に変更したいならこの方法を使うと良いでしょう。

書き込み可能な状態を終了するには、⁠exit」コマンドでそのシェルを抜けてください。

GRUBのメニューで時間がかかるようになる

overlayrootを有効化して再起動すると、GRUBメニューが表示され、さらに起動開始するまで30秒ほど待つようになります。これはGRUBの起動完了テスト機能による弊害です。

GRUBにはメニューエントリーに「recordfail」と記載していると、起動時にGRUBの環境変数領域(/boot/grub/grubenv)「recordfail = 1」などを記録します。この環境変数は、grub-initrd-fallback.serviceが起動したら、削除されます。つまりカーネルが起動しinitramfsが期待通り動作し、ルートファイルシステムがマウントされて、systemdが動くようになったら、GRUBの環境変数領域は空になるのです。

GRUBは次回起動時、recordfailなどの環境変数が残っていたら「前回の起動は失敗した(カーネルかinitramfsか他の何かに問題がある⁠⁠」と判断し、30秒ほどメニューを表示し、次のメニューエントリーを代わりに起動します。

さて、今回のようにoverlayrootを有効化した場合、/boot/grubも読み込み専用としてマウントされます。つまり起動が成功したとしてもrecordfailを消せないのです。このため、次の起動時は「前回の起動は失敗した」と判断されてしまうわけです。

もしoverlayrootを常用する場合は、GRUBのメニューエントリーからrecordfailを削除してもいいかもしれません。

より高度な利用方法

overlayroot変数にはtmpfs以外にもさまざまなパラメーターを付与できます。詳細は「/etc/overlayroot.conf」を参照してください。

  • swapパーティションを使用したい場合[4]⁠:overlayroot="tmpfs:swap=1"
  • ルートファイルシステム以外のパーティションは書き込み可能にしたい場合[4]⁠:overlayroot="tmpfs:recurse=0"
  • デバッグ出力を有効化したい場合:overlayroot="tmpfs:debug=1"
  • 上位レイヤーのディレクトリ名(/overlay)を変更したい場合:overlayroot="tmpfs:dir=other"

既存のストレージデバイスを上位レイヤーとして使用したい場合は、tmpfsの代わりに次のように設定します。

overlayroot="device:dev=/dev/sdb"
overlayroot="device:dev=LABEL=flashdrive,timeout=180"
overlayroot="device:dev=/dev/sdb1,mkfs=0,fstype=ext4"

1つ目の例は特定のパーティションを指定しており、2つ目の例はディスクラベルで指定しています。さらに2つ目の例ではマッチするデバイスが存在しない場合は、最大180秒間待ちます。

1つ目、2つ目ともに、デバイスにext4のパーティションを作成します。もし既存のパーティションを流用したいなら、3つ目の例のように「mkfs=0,fstype=ext4」を指定してください。

overlayrootとは別にoverlayroot_cfgdiskという変数も存在します。これはoverlayroot.confが存在するストレージを指定するための変数です。

overlayroot_cfgdisk="LABEL=OROOTCFG"

標準では「disabled」が設定されているため、ローカルのルートファイルシステムが使用されます。たとえば外部ストレージにoverlay.confを保存しておき、そのストレージを接続している状態なら起動できるようにしたい場合に便利でしょう。

他にもパスワードロックやdm-cryptを用いた暗号化ストレージにも対応しています。overlayroot_cfgdiskと合わせると、特定のキーを利用した場合に起動できるような端末も作成できるでしょう。

おすすめ記事

記事・ニュース一覧