Ubuntu Weekly Recipe

第582回いろいろなディストリビューションでsnapとLXDを利用する

snapはCanonicalとUbuntuコミュニティが開発・推進している「ユニバーサルパッケージ」です。いわゆるLinuxディストリビューションを問わずに利用できるパッケージフォーマットであり、強力な権限管理機能を備えています。今回はこのsnapを、Ubuntu以外のディストリビューションにインストールしつつ、コンテナ管理システムであるLXDのsnap版パッケージをインストールしてみましょう。

snapはいろいろなディストリビューションで利用可能

snapはCanonicalとUbuntuコミュニティが推進する「ユニバーサルパッケージ」です。依存するソフトウェアをすべてパッケージに含めることで、依存関係を気にせずあらゆるディストリビューションでインストール可能なバイナリパッケージとして利用できます。

まずはsnapを説明する上で出てくる用語を整理しておきましょう。ごたくはいいからインストール方法を知りたい人はディストリビューションごとのインストール方法までジャンプしてください。

  • 「snap」はパッケージフォーマットであり、またコマンド名です。
  • snapパッケージをインストールする上でシステムに必要になるのがデーモンサービスである「snapd」です。
  • snapパッケージを構築するツールが「snapcraft」です。
  • snapパッケージを配布するリポジトリサービスを「Snap Store」と呼びます。

開発者はsnapcraftで構築したsnapパッケージをSnap Storeにアップロードします。Snap StoreへのアップロードはUbuntu Oneアカウント(Launchpadアカウント)だけあれば十分です。AndroidのGoogle Playと同様に誰でも任意のソフトウェアをアップロード・配信できます。将来的には有償配信にも対応する予定です。

利用者はsanpdをシステムにインストールした上で、snapコマンドもしくはUbuntuソフトウェアアプリからsnapパッケージをインストールします。既存のパッケージ管理システムに対して、snapは次のような機能が備わっています。

  • 1つ前のバージョンへのロールバック
  • 複数のリリースブランチの配信機能(channel)
  • AppAprmor/seccomp等を利用したホストに対する隔離機能
  • 細かい権限管理(interface)
  • 複数のバージョンの並行利用

一部は他のユニバーサルパッケージでもできたり、ものによっては既存のパッケージ管理システムでもできるものもあります。ただしすべてをひとつのソフトウェアで実現可能なのはおそらくsnapだけでしょう。

ちなみに複数バージョンの並行利用は比較的最近に実験的に実装された機能になります。同じシステム上で同じソフトウェアの異なるバージョンを使い分けたいときに便利です。

最近はいろいろなソフトウェアがsnapで配信されるようになってきたので、本連載でもたびたびsnapパッケージのインストールを紹介しています。代表的になのはLXDですが、第499回のShotCutや第560回のmicrok8sなどがそれに該当しますね。第515回にも紹介されているように、最近のUbuntuではいくつかのGUIアプリについてはsnap版がインストールされるようになりました。また、第476回ではsnapパッケージの作り方が紹介されています。

なお、UbuntuデスクトップやUbuntuサーバーにおいてdeb/APTをすべてsnapで置き換える予定は今のところありません。これはsnapとdeb/APTで目的やターゲットが異なり、それぞれできること・できないことがあり、得意不得意な部分が異なるためです。Debianパッケージを簡単にsnapパッケージにする仕組みは存在するものの、あくまでそれはsnap化に向いているパッケージのみの仕組みであり、Debianパッケージをすべてsnap化しようとすると多大な労力が必要になる割に、得られるものはそこまで多くないでしょう[1]⁠。

更新頻度の高い、単独のCLI/GUIアプリなどはsnap化に向いています。それに対して、いろいろなアプリケーションからライブラリ的に使われるようなソフトウェアはDebianパッケージ化したほうが皆が幸せになれるでしょう。

なぜユニバーサルパッケージなのか

Linuxディストリビューションを使用している人の大半は、個々のディストリビューションのパッケージ管理システムにお世話になっていることでしょう。特に依存関係まで含めて必要に応じてインストールやビルドを行ってくれるその仕組みは、ソフトウェアの再配布やソースコードの取得の自由が保証されているFLOSSで構築されているがゆえの利点であるとも言えます。

ただし一般的に異なるパッケージ管理システム同士に互換性はありません。そもそもパッケージ名の命名ルール自体が異なります。さらにバイナリ配布がメインとなっているパッケージ管理システムのほとんどは特定のパッケージに対しては特定のバージョンのみインストールできる仕組みです。結果として、次のような問題が起こりえます。

  • 特定のディストリビューション・パッケージ管理システム向けにしか提供されないソフトウェアがある
  • 同じソフトウェアでもディストリビューションごとて提供されるバージョンが異なる
  • あるソフトウェアを構築する際に必要なライブラリなどのバージョンがとても古い

いずれも利用者が自分自身で解決できる問題ではあるものの、手間はそれなりにかかります。さらに大変なのはLinux向けのソフトウェアを開発する側です。もし最新バージョンのバイナリパッケージをリリースするのであれば、各ディストリビューションのリリースごとのパッケージ・バージョンの違いを意識しながら構築しなくてはならないからです[2]⁠。

UbuntuであればPPAが活用できます。それなりに体力があるところは、RHEL/CentOS系とDebian/Ubuntu系のそれぞれの独自リポジトリを構築して提供しているかもしれません。ディストリビューションのパッケージに依存せずに利用できるソフトウェアであれば、特定の言語のエコシステムを利用する手もあるでしょう。

どの方法もどうしても開発側に「ディストリビューションごとのパッケージング」の知識が必要になってしまいます。結果的にソフトウェアごとに「提供するディストリビューションが異なる」状況が発生する状態です。ユニバーサルパッケージはそのような状況を打破するために作られました。たとえばsnapパッケージを作りたいのであれば、snapcraft.ymlという名前のファイルに必要な情報を埋めるだけです。ビルド自身はDockerやLXDのコンテナの中で実行可能です。

といっても考え方自体はそこまでものでもありません。たとえばユニバーサルパッケージ的な機能を備えたAppImage(旧称klik)は2004年のリリースです。

今だとsnapと双璧をなすFlatpak(旧称xdg-app)もユニバーサルパッケージを実現する存在です。FlatpakはどちらかというとGUIアプリケーションをメインターゲットとしていますが、こちらも開発は活発なのでいずれCLIでのUXも改善することでしょう。第513回でも紹介しているように、Flatpakで提供されているソフトウェアは増えています。

ディストリビューションごとのインストール方法

能書きはこれくらいにして、実際に各ディストリビューションでsnapを使える方法を説明しましょう。最低限必要なのがsnapdです。このデーモンだけはsnapパッケージとして配布できないので、各ディストリビューションのパッケージとして配布されています。

ちなみにsnapの権限管理機能を利用するためにはAppArmorといくつかのカーネルコンフィグが必要です。これらについてはディストリビューションによって対応がまちまちなので、snapdはAppArmorがなくても動作するようになっています。AppArmorがない場合、snapパッケージはホストシステムへのリソースにアクセス可能なdevmodeとして動作します。

今回インストールする対象は次のディストリビューションです。

Ubuntuを始めとしていくつかの派生ディストリビューションには最初からsnapdがインストールされています。それ以外のインストール方法はsnapcraftの公式ドキュメントにまとまっていますので、そちらも参照してください。

Debian 10へのインストール

DebianはDebian 9からリポジトリにsnapdが存在しています。よってaptコマンドからsnapdをインストール可能です。

$ sudo apt update
$ apt policy snapd
snapd:
  インストールされているバージョン: (なし)
  候補:               2.37.4-1+b1
  バージョンテーブル:
     2.37.4-1+b1 500
        500 http://deb.debian.org/debian buster/main amd64 Packages

$ sudo apt install snapd
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:
  liblzo2-2 squashfs-tools
以下のパッケージが新たにインストールされます:
  liblzo2-2 snapd squashfs-tools
アップグレード: 0 個、新規インストール: 3 個、削除: 0 個、保留: 0 個。
14.5 MB のアーカイブを取得する必要があります。
この操作後に追加で 61.5 MB のディスク容量が消費されます。
(後略)

ただ、どうしてもsnapdのバージョンは古くなってしまいがちです。

$ snap --version
snap    2.37.4-1+b1
snapd   2.37.4-1+b1
series  16
debian  10
kernel  4.19.0-5-amd64

snapパッケージは/snap/bin/以下に実行バイナリへのシンボリックリンクを配置します。/etc/profile.d/apps-bin-path.shでPATHの設定をしていますので、一度ログインし直してください。

実際にsnapパッケージをインストールし、実行してみましょう。

$ sudo snap install hello-world
2019-08-17T21:16:44+09:00 INFO Waiting for restart...
hello-world 6.4 from Canonical✓ installed

$ snap list
Name         Version  Rev   Tracking  Publisher   Notes
core         16-2.40  7396  stable    canonical✓  core
hello-world  6.4      29    stable    canonical✓  -

$ hello-world
Hello World!

coreパッケージはsnapアプリケーションを動かすためのベースシステムです。

CentOS 7へのインストール

CentOSやRHELは7.6以降であればEPELリポジトリにあるsnapdパッケージを利用可能です[3]⁠。よってあらかじめEPELリポジトリを有効化しておいてください。

$ sudo yum install epel-release
$ yum info snapd
中略
利用可能なパッケージ
名前                : snapd
アーキテクチャー    : x86_64
バージョン          : 2.39.2
リリース            : 1.el7
容量                : 14 M
リポジトリー        : epel/x86_64
要約                : A transactional software package manager
URL                 : https://github.com/snapcore/snapd
ライセンス          : GPLv3
説明                : Snappy is a modern, cross-distribution, transactional package manager
                    : designed for working with self-contained, immutable packages.

$ sudo yum install snapd
(中略)
インストール:
  snapd.x86_64 0:2.39.2-1.el7

依存性関連をインストールしました:
  audit-libs-python.x86_64 0:2.8.4-4.el7   bash-completion.noarch 1:2.1-6.el7                 checkpolicy.x86_64 0:2.5-8.el7
  fuse.x86_64 0:2.9.2-11.el7               fuse-libs.x86_64 0:2.9.2-11.el7                    libcgroup.x86_64 0:0.41-20.el7
  libsemanage-python.x86_64 0:2.5-14.el7   libzstd.x86_64 0:1.4.2-1.el7                       policycoreutils-python.x86_64 0:2.5-29.el7_6.1
  python-IPy.noarch 0:0.75-6.el7           setools-libs.x86_64 0:3.3.8-4.el7                  snap-confine.x86_64 0:2.39.2-1.el7
  snapd-selinux.noarch 0:2.39.2-1.el7      squashfs-tools.x86_64 0:4.3-0.21.gitaae0aff4.el7   squashfuse.x86_64 0:0.1.102-1.el7
  squashfuse-libs.x86_64 0:0.1.102-1.el7

完了しました!

snapパッケージをインストールするためにはsnapdが起動していなくてはなりません。snapd.socketをアクティベーションしておくと、必要に応じてsnapdを起動してくてくれます。

$ sudo systemctl enable --now snapd.socket

$ snap --version
snap    2.39.2-1.el7
snapd   2.39.2-1.el7
series  16
centos  7
kernel  3.10.0-957.27.2.el7.x86_64

また、/snapディレクトリは作られませんので自分で作成します。

$ sudo ln -s /var/lib/snapd/snap /snap

Debianと異なり、CentOSの場合は/etc/profile.d/snapd.sh/snap/binのPATH設定などを行います。よってやはりログインし直してください。

$ sudo snap install hello-world
2019-08-17T23:51:40+09:00 INFO Waiting for restart...
Warning: /var/lib/snapd/snap/bin was not found in your $PATH. If you've not restarted your session
         since you installed snapd, try doing that. Please see https://forum.snapcraft.io/t/9469
         for more details.

hello-world 6.4 from Canonical✓ installed
$ hello-world
Hello World!

パッケージインストール時にsnapdが起動しているため、Debianとは少し異なるメッセージですね。警告は/var/lib/snapd/snap/binがsudo時のPATHとして設定されていないことによる警告です。

openSUSE Leap 15.1へのインストール

openSUSE Leap/Tumbleweedは、snappyリポジトリからsnapdのインストールが可能です。よってまずはsnappyリポジトリを有効化します。

$ sudo zypper addrepo --refresh https://download.opensuse.org/repositories/system:/snappy/openSUSE_Leap_15.1 snappy
リポジトリ 'snappy' を正常に追加しました

URI         : https://download.opensuse.org/repositories/system:/snappy/openSUSE_Leap_15.1
有効        : はい (y)
GPGチェック : はい (y)
自動更新    : はい (y)
優先順位    : 99 (既定の優先順位)

$ sudo zypper --gpg-auto-import-keys refresh
以下の鍵を自動的にインポートします:

  リポジトリ:        snappy
  鍵の名前:          system:snappy OBS Project <system:snappy@build.opensuse.org>
  鍵の指紋:          4F2FA05B 2C6589C3 FD12055E F7C6E425 ED340235
  鍵の作成日時:      2018年09月05日 19時57分20秒
  鍵の期限切れ日時:  2020年11月13日 19時57分20秒
  RPM の名前:        gpg-pubkey-ed340235-5b8fb690

(中略)
すべてのリポジトリを更新しました。

$ sudo zypper dup --from snappy
リポジトリのデータを読み込んでいます...
インストール済みのパッケージを読み込んでいます...
ディストリビューションのアップグレードを準備しています...

何もすることがありません。

上記はopenSUSE Leap 15.1にインストールした例です。他のリリースを使う場合は適宜URLを変更してください。

snapdパッケージをインストールしましょう。

$ sudo zypper install snapd
(中略)
以下 2 個の新しいパッケージをインストールします:
  snapd squashfs
(後略)

openSUSEの場合は、snapdそのものを有効化する方法が紹介されています。

$ sudo systemctl enable snapd
$ sudo systemctl start snapd

Tumbleweedの場合は、snapd.apparmorも有効化する必要があるようです。

$ sudo systemctl enable snapd.apparmor
$ sudo systemctl start snapd.apparmor

CentOSと同様にPATH設定するためにログインし直してください。

$ snap --version
snap           2.39.1-lp151.3.1
snapd          2.39.1-lp151.3.1
series         16
opensuse-leap  15.1
kernel         4.12.14-lp151.28.13-default

実際にsnapパッケージをインストールし、実行してみましょう。

$ sudo snap install hello-world
hello-world 6.4 from Canonical✓ installed

$ snap list
Name         Version  Rev   Tracking  Publisher   Notes
core         16-2.40  7396  stable    canonical✓  core
hello-world  6.4      29    stable    canonical✓  -

$ hello-world
Hello World!

Arch Linuxへのインストール

Arch Linuxへのインストールは、snapcraft.ioよりはArch Wikiのほうがかなり詳しく紹介されています。

以前はリポジトリにsnapdパッケージがあったのですが、今はAUR経由のインストールになっているので、gitやbase-develグループが必要になります。

$ sudo packman -S git base-devel

次に必要なパッケージデータをダウンロードしてビルド・インストールしましょう。

$ git clone https://aur.archlinux.org/snapd.git
$ cd snapd
$ makepkg -si

CentOSと同様に、snapd.socketを有効化し、/snapを作成しましょう。

$ sudo systemctl enable --now snapd.socket
$ sudo ln -s /var/lib/snapd/snap /snap

$ snap --version
snap    2.40-1
snapd   2.40-1
series  16
arch    -
kernel  5.2.8-arch1-1-ARCH

/snap/binへのPATH設定のために再ログインしてください。そのあとの実行方法は他のディストリビューションと同じです。

$ sudo snap install hello-world
2019-08-17T23:51:40+09:00 INFO Waiting for restart...
Warning: /var/lib/snapd/snap/bin was not found in your $PATH. If you've not restarted your session
         since you installed snapd, try doing that. Please see https://forum.snapcraft.io/t/9469
         for more details.

hello-world 6.4 from Canonical✓ installed
$ hello-world
Hello World!

snapの実行パスについて

snapはシステムからの隔離を目的の一つにあげています。よって標準の設定では、アプリの中からシステムのファイルシステムにはアクセスできないようになっています。このため実行バイナリは一般的な実行PATHにはインストールしていません。snapパッケージでインストールされた実行コマンドは/snap/bin⁠からリンクしている/snap/パッケージ名/バージョン/bin⁠)にありますので、/snap/binをPATHに追加する必要があります。

どのディストリビューション向けのsnapdパッケージも、/etc/profile以下のファイルとして上記PATH設定を行うファイルがインストールされます。よって一般ユーザーであれば、この設定で問題ありません。

気をつけなくてはいけないのは、sudoでコマンドを実行する際です。sudoのとき実行PATHはスクリーニングされますので、/snap/binを明示的に指定しなくてはなりません。Ubuntuの場合は/etc/sudoersに次のような/snap/binを追加する設定がありますので、必要に応じて他のディストリビューションでも同じ設定を行っておくと良いでしょう。

Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

AppArmorが動かない環境でのsnapの制限

前述のようにsnapはAppArmorやseccompを利用して隔離環境を実現しています。つまりAppArmorが動いていない環境ではsnapの隔離機能は動作しません。システムで動作している隔離機能のリストは次のように確認できます。

$ snap debug sandbox-features
apparmor:             kernel:caps kernel:dbus kernel:domain kernel:file kernel:mount
    kernel:namespaces kernel:network kernel:network_v8 kernel:policy kernel:ptrace
    kernel:query kernel:rlimit kernel:signal parser:unsafe policy:default support-level:full
confinement-options:  classic devmode strict
dbus:                 mediated-bus-access
kmod:                 mediated-modprobe
mount:                freezer-cgroup-v1 layouts mount-namespace per-snap-persistency
    per-snap-profiles per-snap-updates per-snap-user-profiles stale-base-invalidation
seccomp:              bpf-actlog bpf-argument-filtering kernel:allow kernel:errno
    kernel:kill_process kernel:kill_thread kernel:log kernel:trace kernel:trap kernel:user_notif
udev:                 device-cgroup-v1 tagging

特に注意すべきは「confinement-options」です。これの「strict」が有効になっていないと、完全な隔離は実行されません。今回インストールした環境だと、残念ながらAppArmorが動いている環境も含めて、いずれもstrictは有効化されませんでした。

ちなみにstrictな環境だとhello-worldパッケージと一緒にインストールされる、hello-world.evilコマンドがエラーになります。

$ hello-world.evil
Hello Evil World!
This example demonstrates the app confinement
You should see a permission denied error next
/snap/hello-world/29/bin/evil: 9: /snap/hello-world/29/bin/evil: cannot create /var/tmp/myevil.txt: Permission denied

上記のようなエラーメッセージが表示されない場合、何がしかの隔離機能が無効化されていると言えます。

snap版LXDをいろいろなディストリビューションにインストールする

最後にsnapdをインストールした環境にシステムコンテナマネージャーであるLXDをインストールしましょう。LXDは第521回でも紹介しているように、Linux上でシステムコンテナを動かすためのツールです。ホストから隔離された軽量の環境を、かんたんに構築できます。

LXDは現在snapパッケージへの移行しています。よって最新のLXDやLTS版のLXDをインストールしたいならsnap版が便利です。

$ snap info lxd
(前略)
channels:
  stable:         3.16        2019-08-18 (11672) 57MB -
  candidate:      3.16        2019-08-17 (11672) 57MB -
  beta:           ↑
  edge:           git-4a0aa0a 2019-08-17 (11667) 57MB -
  3.16/stable:    3.16        2019-08-18 (11672) 57MB -
  3.16/candidate: 3.16        2019-08-17 (11672) 57MB -
  3.16/beta:      ↑
  3.16/edge:      ↑
  3.0/stable:     3.0.4       2019-07-23 (11348) 55MB -
  3.0/candidate:  3.0.4       2019-07-23 (11348) 55MB -
  3.0/beta:       ↑
  3.0/edge:       git-81b81b9 2019-07-23 (11362) 55MB -
  2.0/stable:     2.0.11      2018-07-30  (8023) 28MB -
  2.0/candidate:  2.0.11      2018-07-27  (8023) 28MB -
  2.0/beta:       ↑
  2.0/edge:       git-c7c4cc8 2018-10-19  (9257) 26MB -

snapは「channel」という仕組みで、複数のリリースブランチを管理できます。LXDの場合はstable/candidate/beta/edgeをフィーチャーリリースのリリースブランチとして利用し、それとは別に最新の3.x系、LTSリリースである3.0と2.0のリリースブランチを用意しています。

今回はUbuntu 18.04 LTSにインストールされているバージョンと同じLTSリリースである3.0系の最新安定版をインストールしましょう。

$ sudo snap install lxd --channel=3.0/stable
Warning: /snap/bin was not found in your $PATH. If you've not restarted your session since you
         installed snapd, try doing that. Please see https://forum.snapcraft.io/t/9469 for more
         details.
lxd (3.0/stable) 3.0.4 from Canonical✓ installed

詳しくは第521回を参照していただくとして、LXDを利用するにはまず初期設定を行いましょう。基本的に標準の設定を使えば問題ありません。

$ sudo /snap/bin/lxd init
Would you like to use LXD clustering? (yes/no) [default=no]: 
Do you want to configure a new storage pool? (yes/no) [default=yes]: 
Name of the new storage pool [default=default]: 
Name of the storage backend to use (btrfs, ceph, dir, lvm) [default=btrfs]: 
Create a new BTRFS pool? (yes/no) [default=yes]: 
Would you like to use an existing block device? (yes/no) [default=no]: 
Size in GB of the new loop device (1GB minimum) [default=15GB]: 
Would you like to connect to a MAAS server? (yes/no) [default=no]: 
Would you like to create a new local network bridge? (yes/no) [default=yes]: 
What should the new bridge be called? [default=lxdbr0]: 
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 
Would you like LXD to be available over the network? (yes/no) [default=no]: 
Would you like stale cached images to be updated automatically? (yes/no) [default=yes] 
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: 

早速コンテナを構築・起動します。

$ sudo /snap/bin/lxc launch ubuntu:18.04 bionic
To start your first container, try: lxc launch ubuntu:18.04

Creating bionic
Starting bionic

lxc listで起動したコマンドを確認できます。

$ sudo /snap/bin/lxc list
+--------+---------+-----------------------+-----------------------------------------------+------------+-----------+
|  NAME  |  STATE  |         IPV4          |                     IPV6                      |    TYPE    | SNAPSHOTS |
+--------+---------+-----------------------+-----------------------------------------------+------------+-----------+
| bionic | RUNNING | 10.225.172.104 (eth0) | fd42:ac24:7376:aba2:216:3eff:fed3:7ce6 (eth0) | PERSISTENT | 0         |
+--------+---------+-----------------------+-----------------------------------------------+------------+-----------+

たとえばlxc execでコンテナの中のコマンドを実行可能です。

$ sudo /snap/bin/lxc exec bionic cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

LXDの詳しい使い方は第521回から始まるシリーズをご確認ください。

ぜひ他のディストリビューションのユーザーも、snapやLXDを活用いただけたらうれしいです。

おすすめ記事

記事・ニュース一覧