Ubuntu Weekly Recipe

第714回Firefoxを含むsnapパッケージとの付き合い

Ubuntu 22.04 LTSではFirefoxがsnapパッケージに完全に移行しました。実際に使ってみると、これまでといろいろ違う部分で戸惑っている人もいることでしょう。今回は改めてFirefoxを含むsnapパッケージの使い方について説明します。

snap版Firefoxは罠が多い

第710回のSnap版Firefoxを使用しないでやり過ごすでも解説したように、UbuntuのFirefoxパッケージは21.10からsnap版に移行し、22.04からDebianパッケージ版(debファイル版)が削除されました。

22.04のリリースまでにsnapに起因する多くの不具合が修正されたものの、まだたくさん残っている状態です。もしsnap版Firefoxで「うまく動かない」⁠何かおかしい」と感じ、なおかつそれが致命的であれば、とりあえず第710回にあるように他の手段を使うことをおすすめします。また、20.04を使い続けたり、Ubuntu以外のディストリビューションを使うという手もあるでしょう。ただしUbuntuの公式派生ディストリビューションは、22.04でsnap版Firefoxに移行しているため注意が必要です。

snapパッケージの作り方を解説した第654回snapパッケージング入門でも紹介しているように、snapは「ユニバーサルパッケージ」という扱いです。これはFlatpakなどと同じように、システムのファイルシステムからは独立したルートファイルシステムを持ち、AppArmorやseccompを使ってコンテナのような隔離環境の中でアプリケーションを動かします。

結果的に隔離されすぎて「これまで普通にできたことができなくなる」という問題を抱えているのです。代表的なものだけでも次のような制限があります。

  • ホームディレクトリの外および/mediaの外にはアクセスできない
  • ホームディレクトリの位置が決め打ち
  • ネットワーク共有ファイルを読み書きできない
  • システムに影響を与える拡張機能を動かせない
  • 起動に時間がかかる

たとえばFirefoxの場合なら、ファイルをホームディクトリ以外の任意の場所にダウンロードする際にエラーになります。他にもwgetコマンドなどで/tmp以下にダウンロードしたHTMLファイルを、Firefoxで開こうとしてもエラーになるでしょう。これに関しては、今のところよく使用するディレクトリをホームディクトリにbindマウントするぐらいしか手はありません。ちなみに/mediaの下であればアクセス可能です。

さらにホームディレクトリを/home以外の場所にしている場合はFirefox自体が起動しません。これはFirefoxと言うよりはsnap側の問題です。

また、Firefoxがシステムリソースから隔離された結果、Firefox上からKeePassXやGNOME Shellの拡張機能の管理などが動きません。これらに関しては将来的に解消される見込みですが、まだ対応時期までは不明です。ただしsnap化された利点として、修正されたら比較的すぐにUbuntu 22.04 LTSにも反映される見込みではあります。

Firefoxの起動時、特に初回の起動時は時間がかかります。これに関してはFirefox 100で多少緩和されていますが、フォントが多い場合など環境によって遅くなる原因が異なるため、あまり効かないかもしれません。Firefoxそのもののパフォーマンスが落ちているという話もあるものの、これもビルド時にLTO(Link Time Optimization)PGO(Profile Guided Optimization)が有効化されたFirefox 100でほとんど違いがなくなっています

ここまではsnapパッケージそのものの制限に近い問題です。しかしながら、snapの制限に起因していくつかの不具合も見つかっています。⁠名前を付けて保存」はホームディレクトリ以外には効かないのですが、エラーを表示せず単純に無視してしまいます。また、ホームディレクトリであっても、なぜか~/デスクトップ/にも保存できません

EvinceでPDFファイルを開いたとき、PDF上のURLをクリックしてもFirefoxが起動しません。フォントのファイルや設定を読み込めないことがあるようです。さまざまな事情から、一旦Waylandのサポートを切ってあります(XWaylandを経由して動きます⁠⁠。そのため、⁠任意倍率のスケーリング」使用時にフォントがにじんで表示されてしまうという問題も発生しています。

他にもいろいろsnap版Firefoxの問題が報告されていますが、総じて「広く使ってもらう」には時期尚早な状態で、なおかつ不具合報告と修正に対して人的リソースが全然足りていない状況です。期せずしてsnap版のFirefoxがsnapパッケージに対するネガティブキャンペーンになっています。

特にFirefoxをヘビーに使っている人は、当面はUbuntu 20.04 LTSを使い続けるか第710回を参照することを強くおすすめします。

snapパッケージの権限管理

さて、ユニバーサルパッケージは、仕組み上設けられている制約に対して、いくつかの権限管理によってリソースにアクセスできる口を設けています。具体的にはスマートフォンアプリの「権限」をイメージすると良いでしょう。リソースのうち現在デスクトップ向けとして最も活発に開発されているのが、Flatpakでも利用するXDG desktop portalです。これはデスクトップアプリケーションがアクセスするリソースを一通り揃えています。

XDG desktop portalはアプリケーション側がPortal APIを使えるように作り込んでいる必要があります。またGTKやQtを使っているならより便利なラッパーAPIもあるようです。ものによっては環境変数によってPortal APIの利用が有効化されるものもあります。

snapパッケージは、デスクトップアプリだけでなくサーバーデーモンやCLIツールにも利用できるため、OS上のデスクトップリソースだけでなく、パッケージ自身が提供するリソースなど、いくつかの追加リソースも利用できるようになっています。それがsnap interfacesです。リソースを提供する側が「slot」を用意し、それにリソースを利用する側が「plug」「connection」するという体裁を取っています。slotとplugの組み合わせを「interface」と呼んでいます。

snap interfacesはXDG desktop portalと異なり、アプリケーション側の対応は不要です。snap側が適切にどのリソースを見せるようにするかを判断します。アプリケーション側からはホストのリソースがそのまま見えるようになっています。snapシステム側が最初から用意しているinterfaceもありますし、アプリケーションが他のアプリケーション向けに新規のinterfaceを用意することも可能です。

ちなみにXDG desktop portalを利用しているアプリケーションはsnap interfacesのうちdesktop interfacesに接続している必要があります。

デスクトップアプリケーションの場合は、システム設定の「アプリケーション」から権限管理を変更できます。Ubuntu 22.04 LTSであれば最初にインストールされているアプリケーションのうちFirefoxとUbuntuソフトウェアのみがsnapパッケージなので、まずはFirefoxを開いてみると良いでしょう。

図1 Firefoxの権限設定。ほぼすべての権限が有効化されている
図1

ほぼすべての権限が有効化されており、個別にオン・オフが切り替えられます。またコマンドだとより細かいinterfaceの変更も可能です。次の方法で実際の接続状態が表示されます。

$ snap connections firefox

先ほど言及した「desktop interfaces」はシステム設定には表示されませんが、コマンドからなら接続の切り替えが可能になっています。

snapパッケージのアップデート管理

snapパッケージは自動的にアップデートが行われます。しかしながら勝手にアップデートされると困る場合も多いでしょう。aptのように「完全にアップデートをやめる」方法はないものの、一定時間アップデートを遅らせる、といった方法なら対応可能です。

snapパッケージはsnap refreshコマンドによって手動で更新できます。手動で実行しない場合も、およそ1日に4回の頻度でチェック&更新を行います。次回の更新スケジュールは次のコマンドで確認可能です。

$ snap refresh --time
timer: 00:00~24:00/4
last: yesterday at 20:53 JST
next: today at 03:42 JST

更新スケジュールはsnap setコマンドで変更可能です。たとえば毎日朝4時にのみ更新したい場合は次のように設定します。

$ sudo snap set system refresh.timer=04:00

タイムゾーンはシステムの設定に基づきます。タイムゾーンを日本に設定しているマシンで午前4時を指定したら、日本の午前4時と判断されます。

他にも「月末の金曜日(fri5⁠⁠」のような設定も可能です。細かい書式はsnapのドキュメントにあるTimer string formatを参照してください。ちなみに次のように実行すると、初期設定値に戻せます。

$ sudo snap unset system refresh.timer

一時的に更新を止めたいだけならrefresh.holdを設定します。これはRFC 3339フォーマットで指定しないといけないため、dateコマンドで設定したほうがいいでしょう。たとえば、⁠2日間更新を止める」なら次のように実行します。

$ sudo snap set system \
  refresh.hold="$(date --date='2 days' +%Y-%m-%dT%H:%M:%S%:z)"

ただし止められるのは最大90日までです。

直近の更新状況はsnap changesで確認できます。ただし本当に直近の更新だけです。またsnap tasks IDで、個々の変更の詳細を確認できます。

$ snap changes
ID   Status  Spawn                   Ready                   Summary
9    Done    yesterday at 10:58 JST  yesterday at 10:59 JST  Auto-refresh snap "gtk-common-themes"
10   Done    today at 01:54 JST      today at 01:54 JST      Change configuration of "core" snap
11   Done    today at 02:10 JST      today at 02:10 JST      Change configuration of "core" snap
12   Done    today at 02:11 JST      today at 02:11 JST      Change configuration of "core" snap

次のコマンドを実行すると、アプリケーションが動いている間は更新を実行しません。

$ sudo snap set core experimental.refresh-app-awareness=true

この設定はsnapd 2.56以降のどこかで、最初から設定されるようになる見込みです。以前はこの設定がないと、Firefoxなどは更新時にクラッシュしてしまっていたのですが、現在はその問題は別の方法で解消済みです。

ただしその結果として、snap版のFirefoxが「更新されたこと」を検知できません。実際に更新を反映させるためには、Firefoxの再起動が必要です。Firefox更新時の再起動を手動で行いたいなら、アドレスバーにabout:restartrequiredと入力し、表示される「Firefoxを再起動」ボタンを押すと良いでしょう。

snapパッケージの関連ディレクトリ

snapパッケージはシステムのルートファイルシステムと隔離されている都合上、一般的なDebianパッケージと異なるディレクトリ構成になっています。

  • /var/lib/snapd/snaps/:snapパッケージの保存場所
  • /snap/パッケージ名/:snapパッケージのマウントポイント
  • /var/snap/パッケージ名/:snapパッケージのシステム用データ領域
  • ~/snap/パッケージ名/:snapパッケージのユーザー固有のデータ領域

まずsnapパッケージの実態は「Squashfsのファイル」です。これはsnap installsnap refreshによって、/var/lib/snapd/snaps/以下にダウンロードされます。

snapパッケージを管理するsnapdは、これを/snap/パッケージ名/以下にバージョンごとのディレクトリを作って読み込み専用でマウントさせます。mountコマンドを引数なしで実行すると多数のsnapファイルがマウントされていることがわかるかと思います。

ちなみにUbuntuデスクトップの場合、最大2個のバージョンが保持されます。たとえばFirefoxなら次のようになっています。

$ ls -l /snap/firefox/
合計 0
drwxr-xr-x 7 root root 201  4月 12 17:37 1232
drwxr-xr-x 7 root root 201  5月  3 00:31 1300
lrwxrwxrwx 1 root root   4  5月  6 01:54 current -> 1300

古いバージョンにはsnap revert パッケージ名で戻せます。ちなみにrevertした場合、より新しいバージョンは一旦無効化され、snap refreshでは自動更新されません。もし新しいバージョンに戻したい場合はsnap refresh パッケージ名とパッケージ名を明示してrefreshしてください。また保持するバージョンの数はsudo snap set system refresh.retaine=数で増やせます。

/snap/パッケージ名は読み込み専用でマウントされるため、別途書き込み可能な領域が必要です。それが/var/snap/パッケージ名/です。

$ ls -l /var/snap/firefox/
合計 12
drwxr-xr-x 2 root root 4096  4月 19 19:08 1232
drwxr-xr-x 2 root root 4096  4月 19 19:08 1300
drwxr-xr-x 3 root root 4096  4月 29 16:34 common
lrwxrwxrwx 1 root root    4  5月  6 01:54 current -> 1300

こちらもバージョンごとにディレクトリが作られています。commonはバージョンに依存しないデータ領域です。つまりsnapパッケージが更新されたときも維持されるべきデータが保存されます。このあたりはsnapパッケージによって何をどのように使うかが異なります。

Firefoxのプロファイルのようなユーザー固有のデータは~/snap/パッケージ名/に保存されます。こちらもバージョン固有のディレクトリだけでなく、commonも存在します。

$ ls -l ~/snap/firefox/
合計 12
drwxr-xr-x 4 shibata shibata 4096  4月 29 17:08 1232
drwxr-xr-x 4 shibata shibata 4096  5月  6 16:11 1300
drwxr-xr-x 4 shibata shibata 4096  4月 29 17:08 common
lrwxrwxrwx 1 shibata shibata    4  5月  6 16:11 current -> 1300

ちなみに~/snapに関しては、将来的にダウンロードデータなど他のアプリケーションからも参照する可能性がある~/Snapと、プロファイルのような直接参照する可能性が少ない~/.snapに分離される話も出ていますが、今のところいつ適用されるかは未定です。

/var/snap/パッケージ名/~/snap/パッケージ名/snap save パッケージ名「スナップショット」として、バックアップ可能です。またsnap removeで明示的にパッケージをアンインストールするときも自動的にバックアップが取られ31日間は保存されます。バックアップデータのリストはsnap savedで確認できます。

バックアップはsnap export-snapshot ID ファイル名でzipファイルとして外だしできますし、zipファイルはsnap import-snapshot ファイル名でシステムに取り込めます。またsnap restpre IDで現在のシステムにリストアできます。

snapのチャンネル管理とロールバック

snapには「チャンネル」という概念があります。特定のパッケージでも、複数のチャンネルで複数のバージョンを並行してリリースできるのです。チャンネルはUbuntuソフトウェアの右上のプルダウンメニューやsnap info パッケージ名で確認できます。

図2 Firefoxのチャンネル
図2
shibata@nuc:~$ snap info firefox
(略)
tracking:     latest/stable/ubuntu-22.04
refresh-date: yesterday at 01:54 JST
channels:
  latest/stable:    100.0-2     2022-05-05 (1300) 168MB -
  latest/candidate: 100.0-2     2022-05-02 (1300) 168MB -
  latest/beta:      101.0b2-1   2022-05-04 (1313) 169MB -
  latest/edge:      102.0a1     2022-05-06 (1318) 180MB -
  esr/stable:       91.9.0esr-1 2022-05-05 (1284) 161MB -
  esr/candidate:    91.9.0esr-1 2022-04-27 (1284) 161MB -
  esr/beta:         ↑
  esr/edge:         ↑
installed:          100.0-2                (1300) 168MB -

「latest」「stable」⁠candidate」⁠beta」⁠edge」は基本的にどのsnapパッケージにも存在します。チャンネル未指定でインストールした場合は「latest/stable」が使われます。

これらのチャンネルは、snapパッケージの開発者に使い方を一任されています。たとえばcandidateはまったく使われていなかったり、stableよりbetaのほうが古いってこともざらにあるので注意が必要です。

「latest」以外のチャンネルは、アプリケーションごとに固有のチャンネルです。特別な許可がなければ作れないことになっています。Firefoxの場合は長期サポート版になるESRを別チャンネルとして提供しているようです。LXDなんかはサポート中のリリースバージョンごとにチャンネルを用意しています。

snapパッケージをインストールするときは、次の方法でチャンネルを指定できます。

$ sudo snap install FOO --channel=latest/edge

--stable--betaといった短縮形もあります。インストール済みのsnapパッケージを別のチャンネルに切り替えたいならrefreshコマンドを利用します。

$ sudo snap refresh FOO --channel=latest/beta

チャンネル間は比較的自由に切り替えられますが、アプリケーション側がチャンネル切り替えに対応しているかは未知数です。たとえばFirefoxの場合、ダウングレードになるチャンネル切り替えは、プロファイルのバージョンチェックにひっかかる場合があるので注意しましょう。これはsnap revertを実行するときも注意が必要です。

ちなみに実験的機能ではあるものの、同じ名前のsnapパッケージを別名で同時にインストールする方法も存在します。この方法を使えば、最新安定版を使いながら、ベータ版も試す、といった使い方も可能になります。

snap版で何か動かないときは

snap版でなにかの機能が「うまく動かない」ときは、権限管理側で弾いている可能性が一番高いです。よって、システム設定の「アプリケーション」から、必要な機能が無効化されていないか確認しておきましょう。

また、既存の機能では対応しきれない権限が必要な場合もあります。その可能性を探りたい場合は、次のようにAppArmorが不許可メッセージを出していないか確認します。まずは端末を開いて次のコマンドを実行してください。

$ journalctl -f | grep DENIED

この状態で「うまく動かなかった操作」を再度実施してみます。apparmor="DENIED"と表示されるようなら、関連する何か権限が足りない可能性が高いです。

Firefoxの場合まずはubuntu-bug firefoxを実行して不具合報告をしておきましょう。ただし修正までには時間がかかると思われますので、日常生活に必須の機能であれば、snap版以外のパッケージを使うことになるでしょう。

おすすめ記事

記事・ニュース一覧