WSLでUbuntuのユニバーサルパッケージシステム「snap」を使う
はじめに
前回はUbuntuのパッケージ管理について解説しました。UbuntuのリポジトリにはDebian GNU/Linux譲りの豊富なパッケージが存在します。多くのソフトウェアをパッケージから手軽にインストールできるのはUbuntuの魅力の1つですが、近年ではこうしたOSが提供するパッケージの「使いづらさ」も目立ってきました。
今回は、Ubuntuの従来のパッケージシステムが持っている問題と、その解決方法の1つである「ユニバーサルパッケージシステム」について解説します。
Ubuntuのパッケージとソフトウェアのバージョン
Ubuntuは半年ごとに新しいバージョンがリリースされます。そして、パッケージはOSを構成する一部として各リリースごとにビルドし直され、専用のリポジトリで提供されています。Ubuntuは通常のリリースでは9か月、2年に一度リリースされる長期サポート版では5年のサポートが提供されています。この「OSのサポート」とは、そのリリース向けのパッケージ群に対して、セキュリティ修正やバグ修正のアップデートが提供されるかということを意味します(後述の「Ubuntuのリポジトリとサポート」も参照)。
ここで気をつけなければならないのは「一度リリースされたパッケージは、ソフトウェアのバージョンそのものは上げない」という点です。具体的な例として、1つ前の長期サポート版である「Ubuntu 22.04 LTS」のPHPのパッケージを見てみましょう。
Ubuntu 22.04 LTSは2022年4月にリリースされました。そのリリース時に提供されていたPHPのバージョンは「8.1」で、リリースから2年半以上が経過した2024年12月現在、Ubuntu 22.04 LTSのリポジトリにあるPHPのバージョンは8.1のままです。
PHP 8.1は2021年11月にリリースされたバージョンです。そして2023年11月にアクティブサポートが終了しています。また、セキュリティサポートは2025年12月に終了する予定です。Ubuntu 22.04 LTSは5年(2027年まで)、有償サポートを契約すれば10年(2032年まで)のサポートが提供されます。つまりPHPの開発元のサポートが先に打ち切られてしまうことになり、どう考えても計算が合いません。
2024年12月現在、PHPは最新の安定版として8.4がリリースされています。8.4は2028年までサポートされるので「PHPそのもののバージョンを都度上げていけば良い」と考えるかもしれませんが、Ubuntuでは「リリース内でソフトウェアのバージョンそのものを上げる」ということを原則として行いません。繰り返しになりますが、Ubuntuにより提供されているパッケージはすべて「OSを構成する一部」であるため、開発期間内に十分なテストが行なわれた後で提供されているのです。
しかし、リリース後に新しいバージョンを投入してしまうと意図しない不具合を発生させてしまうことも考えられます。また、迂闊に共有ライブラリのバージョンを上げてしまうと、他のアプリに異常を来したり、OS全体の整合性を壊してしまう可能性もあります。こうした理由により、Ubuntuの安定性を維持するためにも、リリース後にソフトウェアの新バージョンを投入することは原則としてできなくなっているのです*1。
*1: いくつか例外はあります。そこでUbuntuでは、ソフトウェアのバージョンそのものは上げず、セキュリティ修正のみをパッチとしてパッケージに取り込む(バックポートする)方式を採用しています。Ubuntu 22.04 LTSリリース当時のPHPパッケージの正確なバージョンは「8.1.2-1ubuntu2」でした。そして2024年12月現在のPHPパッケージの正確なバージョンは「8.1.2-1ubuntu2.19」です。「8.1.2」という部分がPHPのバージョンを表しているのですが、ここは変わらず、ハイフンより後ろのバージョンが上がっていることが分かるでしょう。これがセキュリティ修正を取り込み、Ubuntu独自の変更バージョンを上げているということを意味しているのです*2。
*2: 「あるソフトウェアのバージョンX.Xに重大な脆弱性が発見された。修正するにはX.Yにバージョンアップせよ」と言われることがありますが、Ubuntuの場合は「X.X」に修正パッチを当てて「X.X-2」のようなパッケージとして提供します。これを見た人が「バージョンX.Xを使っている! 脆弱性対策がなされていない!」と勘違いするのはUbuntuあるあるです。修正パッチをバックポートしているケースでは、パッケージのバージョン番号を見ただけでは脆弱性の対策状況は判断できないという点を覚えておくとよいでしょう。そして、ここが重要なのですが、仮に開発元のサポートが終了しても、Ubuntuでは独自にパッケージのメンテナンスを行います。PHP 8.1のサポートは2025年に終了してしまいますが、Ubuntu 22.04 LTSのPHP 8.1は、2026年になってもセキュリティサポートが「Ubuntuによって」提供されるのです*3。
*3: 同様にバージョン番号だけを見て「このソフトのバージョンX.Xはもうサポートが終了している! まだ使っているとはけしからん!」と勘違いする人もよくいます。開発元のサポートとディストリビューションのサポートはまた別であることも覚えておきましょう。ちなみに、こうした事情はUbuntuに限らず、Stableリリース(バージョンX.Xのような安定板を定期的にリリースするタイプのリリースモデル)を採用しているディストリビューションであれば、だいたい同じになっています。
「長期サポート版のUbuntuでは5年のサポートが提供される」と述べましたが、実はすべてのパッケージにセキュリティアップデートが提供されるわけではありません。Ubuntuが提供しているパッケージは、大きく「main」「universe」「restricted」「multiverse」の4つのコンポーネントに分類されています。
コンポーネント | 内容物 | ライセンス | メンテナンス担当 | セキュリティアップデート |
---|---|---|---|---|
main | カーネルをはじめとする主要パッケージ | オープンソースソフトウェア | Canonical社 | あり |
universe | 主にDebian GNU/Linuxからインポートしたパッケージ | オープンソースソフトウェア | コミュニティ | ベストエフォート |
restricted | グラフィックカードのドライバなど | 非オープンソースソフトウェア | Canonical社 | あり |
multiverse | 利用条件や再配布条件に制限があるパッケージ | 非オープンソースソフトウェア | コミュニティ | ベストエフォート |
セキュリティアップデートの提供が約束されているのは、Canonical社がメンテナンスを担当している「main」と「restricted」に限定されています。「universe」と「multiverse」のパッケージはUbuntuコミュニティによるベストエフォートでの対応となっています。そのため、Ubuntuを長期に安定運用させるためにはuniverseとmultiverseのパッケージを採用するか、慎重に検討する必要があります。
なお、有償サポートの「Ubuntu Pro」を契約すると、universeとmultiverseのパッケージにも10年間のセキュリティアップデートが提供されるようになります。Ubuntu Proは個人であれば5台まで無償で利用できるため、小規模なサーバー運用では利用を検討してみるのもお勧めです。
Ubuntuのパッケージが抱える問題
Ubuntuが提供している公式パッケージを使えば、開発元のサポート等を気にすることなく、Ubuntuのサポートが切れるまで特定のソフトウェアの特定のバージョンを使い続けることができます。この「ディストリビューターが長期間メンテナンスを継続してくれる」というのは、非常に大きなメリットであるのは間違いありませんが、これが昨今のアプリ開発事情と噛み合わなくなってきています。
「特定のバージョンがメンテナンスされ続ける」というのは、言い換えれば「アプリのバージョンがOSのライフサイクルに縛られる」ということも意味します。OSは安定したものを長期間使い続けたくても、アプリのバージョンはどんどん上げていきたいと考えるのが自然でしょう。ミドルウェアはともかく、ユーザーが直接触れるアプリであればなおさらです。しかし前述の通り、OS全体の整合性や安定性の問題からリリース後にアプリのバージョンを上げることはできないのです。
近年のアプリケーションの進化の早さには目を見張るものがあります。そのため「APTを使えば多くのアプリが簡単にインストールできる」というメリットを「望んだバージョンをインストールできない」というデメリットが上回るケースも多くなってきているのです。
ユニバーサルパッケージとは
従来のLinuxのパッケージは、UbuntuのDebにしろ、Red Hat Enterprise LinuxのRPMにしろ、そのディストリビューションの作りと密接に関連しています。そのため、異なるディストリビューションはもちろん、異なるリリースのパッケージは基本的に「混ぜるな危険」です*4。
*4: 無理やりインストールすれば動いてしまうこともあります。そこで「Linuxカーネルが動いてさえいれば、どんなディストリビューションのどのリリースでも動く、統一的なパッケージを作ろう」という試みが始まりました。これが「ユニバーサルパッケージ」です。ユニバーサルパッケージの実装には「snap」「Flatpak」「AppImage」があり、Ubuntuではsnapが採用されています。なお、snapは従来のAPT/Debを置き換えるものではありません。アプリの頻繁なアップデートに追従するなど、APT/Debが苦手とする部分を補う目的で併用することが前提となっています。
そもそもの話ですが、リリース後にパッケージのバージョンを上げられない原因は、ひとえにパッケージに依存関係があるからに他なりません。仮に、あるソフトウェアが動作するために必要な要素をすべて単一のパッケージ内に詰め込むことができれば、パッケージの依存関係をなくすことができないでしょうか。そして、依存関係を持たず自己完結しているパッケージであれば、自由に入れ替えられることにならないでしょうか。
ユニバーサルパッケージでは環境依存をなくすため、ソフトウェアの動作に必要な環境一式をパッケージ内に詰め込んでいます。そのため、パッケージ間の依存関係を持たず、単一のパッケージをインストールするだけで、環境を問わず同じソフトウェアを動かすことができます。ユニバーサルパッケージを使えば、OSの一部であった従来のパッケージをOSから切り離すことが可能となります。結果としてOSのライフサイクルに縛られない、自由なバージョンアップが実現できるのです。
snapを使いこなす
それでは、実際にsnapの使い方を見ていきましょう。
WSLへのsnapのインストール
実は、デスクトップ/サーバー版のUbuntuではsnapが標準でインストールされています。例えば、デスクトップ版のUbuntu 24.04 LTSにプリインストールされているFirefoxやThunderbirdは従来のDebではなく、snapでインストールされています。WSL版のUbuntu 24.04 LTSにも同様にsnapがプリインストールされており、すぐに使いはじめることができます。
もし、何らかの理由でsnapがインストールされていない場合は、以下のコマンドでsnapdパッケージをインストールしてください。
$ sudo apt install -U -y snapd
snapパッケージの検索
snapは、snapコマンドとサブコマンドで操作します。使い勝手はaptコマンドとよく似ているため、難しい部分はないでしょう。よく使うであろうサブコマンドを表にまとめました。
サブコマンド | 用途 |
---|---|
install | 指定したパッケージをインストールする |
remove | 指定したパッケージをアンインストールする |
list | インストール済みのパッケージの一覧を表示する |
find | キーワードをもとにパッケージを検索する |
info | 指定したパッケージの詳細な情報を表示する |
refresh | パッケージをアップデートする |
switch | 指定したパッケージのリリースチャネルを切り替える |
disable | 指定したインストール済みのパッケージを無効にする |
enable | 指定した無効になっているパッケージを有効にする |
まずは、どのようなパッケージがあるか検索してみましょう。パッケージの検索は「find」サブコマンドの後に、キーワードを指定して実行します。以下の例では「kubernetes」関連のパッケージを検索しています。
$ snap find kubernetes
条件にマッチしたパッケージのパッケージ名、パッケージのバージョン、パブリッシャー名、ノート、パッケージの概要が表示されます。
UbuntuのAPTのリポジトリにあるパッケージは、すべてUbuntuがビルドして公開している、いわゆる「公式パッケージ」です。対してsnapのストアには様々な開発者によるパッケージが混在しており、パッケージの質も玉石混合となっています。パブリッシャー名の横に緑色のチェックマークがついているパッケージは、そのパブリッシャーが検証していることを示しています。これらのパッケージは「信頼できる」パッケージだと考えて良いでしょう。参考にしてください。
snapパッケージのインストール
それでは、実際にsnapパッケージをインストールしてみましょう。ここでは、例としてKubernetesのコマンドラインツールである「kubectl」をインストールします。パッケージをインストールするには「install」サブコマンドにパッケージ名を指定します。
$ sudo snap install kubectl --classic
インストールにはroot権限が必要なためsudoを利用します。また、kubectlパッケージのインストールには「--classic」オプションが必要です。snapではセキュリティ的な理由で各アプリからホストのリソースへのアクセスが制限されていますが、アプリによってはホストのリソースへアクセスしなければならないものも存在します。こうしたアプリはインストール時にclassicオプションの指定が必要になります。classicオプションが必要かどうかは「find」コマンドの結果の「Notes」の部分に、その記述があるか確認することで判断できます。
Kubernetesは進化が早いシステムの1つで、おおよそ4か月ごとに新バージョンがリリースされます。それに合わせてコマンドラインツールの更新も必要ですが、Ubuntuのリリースポリシー的にAPTのパッケージでは対応が難しいのです。snapを使えば、こうした進化の早いアプリでも簡単に管理できます。
リリースチャネルを切り替える
kubectlは、常に最新版をインストールすれば良いというものではなく、操作するKubernetesクラスターのバージョンと揃える必要がある*5ため、場合によっては過去のバージョンをインストールしたいこともあるでしょう。
*5: 厳密に一致する必要はなく、クラスターのバージョンの±1であれば許容されます。snapには「リリースチャネル」という概念があります。これは、いわばリポジトリを複数の「チャネル」に分けて、異なるバージョンを並行して配布する仕組みです。通常は「edge」「stable」「candidate」「beta」の4つのチャネルが用意されています。これ以外にどのようなチャネルを用意し、どのように利用するかはパブリッシャーに一任されています。特に、チャネルを指定せずにインストールを行った場合は「stable」チャネルからインストールが行われるため、stableチャンルではいわゆる「安定板」のリリースが配布され、edgeチャンルやbetaチャネルでは開発中のバージョンやベータ版が配布されるのが一般的となっています。
そのパッケージにどのようなチャネルが存在するかは「info」サブコマンドで調べることができます。
$ snap info kubectl
上図の「channels」以下がkubectlパッケージに用意されたチャネルです。kubectlでは「edge」「stable」「candidate」「beta」のチャネルすべてで同じバージョンが配布されていること、「latest(最新)」では2024年12月現在の最新バージョンである1.31が配布されていること、リリース前である1.32は「1.32/edge」チャネルで配布されていること、過去のバージョンは「バージョン番号/stable」といったチャネルで配布されていることなどが見て取れます。
それでは、チャネルを切り替えて2つ前のバージョンである「1.29」をインストールしてみましょう。「switch」サブコマンドでkubectlパッケージのチャネルを切り替えます。
$ sudo snap switch kubectl --channel 1.29/stable
チャネルを切り替えたら「refresh」サブコマンドでパッケージを更新します。
$ sudo snap refresh
パッケージのアンインストール
snapパッケージは、removeサブコマンドでアンインストールできます。kubectlパッケージをアンインストールする例は以下の通りです。
$ sudo snap remove kubectl
おわりに
APTのような仕組みを使っていると、デスクトップのアプリケーションはもちろん、サーバーのミドルウェアや言語のランタイム、ライブラリなど、あらゆるソフトウェアがOSに縛られてしまいます。そこでアプリケーション実行環境をカプセル化し、OSのライフサイクルから切り離すことで、自由なバージョンアップを可能にするのがユニバーサルパッケージのメリットです。
特に、例として紹介したkubectlのように進化が早く、特定のバージョンの使用が強制されるようなソフトウェアとの相性は抜群だと言えるでしょう。Ubuntuではsnapを簡単に使い始められますので、ぜひAPTだけでなく、snapの活用も検討してみてください。
なお、snapの解説を呼んで「何かに似ているな」と感じなかったでしょうか。そう「Docker」です。Dockerもまた、自由なバージョン選定と高速なデプロイを実現するため、アプリケーション実行環境をコンテナという形でベースOSから隔離しています。実は、Dockerのようなアプリケーションコンテナとsnapは非常によく似た設計思想を持っているのです。Dockerについても本連載で解説する予定なので、今後の展開にご期待ください。
次回は、WSLを使ってWindows上でLinux向けのGUIアプリケーションをシームレスに動かす方法について解説します。