Ubuntuではディストリビューションを問わず利用できる
今回とそのあと数回で、
- 第654回 snapパッケージング入門
(今回) - 第656回 EPUBリーダーをsnapパッケージ化する
- 第658回 自作のsnapパッケージをコンテナ化する
- 第660回 自作のsnapパッケージをSnap Storeに公開する
snapcraftコマンドで作るsnapパッケージ
Ubuntuではディストリビューションをまたいで利用できるユニバーサルパッケージシステムとして
Snapパッケージは、
「ユニバーサルパッケージ」
実は第476回
パッケージ構築環境の準備
snapパッケージをビルドする流れは、
- パッケージビルドのためのsnapcraftコマンド
- ビルド環境を構築するための仮想マシンシステム
- パッケージ情報を記述したYAMLファイル
snapcraftコマンド自体はsnapパッケージ化されているため、
$ sudo snap install snapcraft --classic
もうひとつ必要になるのが仮想マシンシステムです。従来のパッケージを作成したことがあるならおそらくご存知だと思いますが、
作ろうとしているパッケージごとに必要となるツールが異なるため、
snapcraftでは、
MultipassはUbuntuだけでなくmacOSやWindowsでも利用できるため、
Multipassはsnapcraftの初回実行時にインストールするかどうかを問われます。もちろんあらかじめインストールしておいてもかまいませんので、
$ sudo snap install multipass --classic
一点、
$ for table in filter nat mangle; do \ sudo iptables-legacy -t $table -S | grep Multipass | \ xargs -L1 sudo iptables-nft -t $table \ done
もちろんUbuntu 20.
サンプルパッケージの作成
snapcraft init
コマンドを使うと、snapcraft.
を生成してくれます。何かパッケージを作るなら、
$ mkdir snaptest && cd snaptest $ snapcraft init Created snap/snapcraft.yaml. Go to https://docs.snapcraft.io/the-snapcraft-format/8337 for more information about the snapcraft.yaml format. $ ls -R .: snap ./snap: snapcraft.yaml
作られたのはsnap/
」
$ cat snap/snapcraft.yaml name: my-snap-name # you probably want to 'snapcraft register <name>' base: core18 # the base snap is the execution environment for this snap version: '0.1' # just for humans, typically '1.2+git' or '1.3.2' summary: Single-line elevator pitch for your amazing snap # 79 char long summary description: | This is my-snap's description. You have a paragraph or two to tell the most important story about your snap. Keep it under 100 words though, we live in tweetspace and your description wants to look good in the snap store. grade: devel # must be 'stable' to release into candidate/stable channels confinement: devmode # use 'strict' once you have the right plugs and slots parts: my-part: # See 'snapcraft plugins' plugin: nil
逐一コメントが入っているので、
name
:パッケージの名前です。ちなみに構築時に作られる仮想マシンも同じ名前になります。小文字の英数字およびハイフンのみ利用可能で、Snap Storeで配布する際は一意である必要があります。 snap find
でマッチするパッケージ名がないか確認しておくと良いでしょう。base
:後述するベースシステムになるsnapパッケージを指定します。version
:パッケージのバージョンです。最大32文字で、YAML的に文字列として認識させるためにシングルクオートでくくることをおすすめします。ちなみに 「git」 を記述すると 「 git describe
」の結果がバージョンになります。 summary
:snap find
時に表示される78文字以内の概要です。description
:snap info
時に表示されるより詳細な説明です。概要だけでなく、そのパッケージの利用方法などを説明することもよくあります。 grade
:そのパッケージの状態を示します。完全な開発版ならdevel
を、一般的に利用できる状態なら stable
を記述します。confinement
:ホストのリソースへのアクセス権限に関する情報を記述します。strict
がsnapの通常状態でリソースへのアクセスが制限され、ユーザーによる許可が必要になります。 classic
はホストのリソースの利用を前提としたパッケージに使われます。classic
を指定するためにはSnap Store側でレビューを受けた上で特別な許可が必要です。devmode
は開発時に使うモードで、原則としてリソースへのアクセスは制限されません。 devmode
ではSnap Store経由の公開はできません。parts
:実際にパッケージをビルドする手順やコンテンツの場所などを記述します。
base snapはそのsnapパッケージが動くベースシステムを提供するsnapパッケージです。snapパッケージは依存関係を原則としてすべてパッケージに内包するシステムですが、
- core20:Ubuntu 20.
04 LTSのパッケージを元に作られたbase snap - core18:Ubuntu 18.
04 LTSのパッケージを元に作られたbase snap - core:Ubuntu 20.
04 LTSのパッケージを元に作られたbase snap - bare:何も提供しないbase snap
core20は2021年2月に正式リリースされたばかりのbase snapです
bareはたとえばすべてのライブラリを静的にリンクした単一のバイナリのみを提供するようなsnapパッケージに使われます。ただ、
具体的なパッケージングの情報はpartsに記載します。partsは辞書形式になっており、
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
今回の例だと作るのはmy-part
」snapcraft.
の記述が楽になります。
今回はplugin: nil
」
これでsnapcraft.
にいろいろな情報を追記していくことになります。しかしながら、
サンプルパッケージのビルド
snapパッケージのビルドはシンプルで、
$ snapcraft --debug Launching a VM. Launched: snapcraft-my-snap-name (snip) Pulling my-part + snapcraftctl pull Building my-part + snapcraftctl build Staging my-part + snapcraftctl stage Priming my-part + snapcraftctl prime Snapping | Snapped my-snap-name_0.1_amd64.snap
Multipassをインストールしていないと、
- ビルド用の仮想マシンを作成・
起動する - ローカルの環境を仮想マシンにsshfsでマウントする
snap/
の記述に従ってビルドを実施するsnapcraft. yaml - ビルドした成果物をひとつのSquashFSにまとめる
- snapパッケージの完成
- 仮想マシンのシャットダウン
パッケージファイルはパッケージ名_バージョン名_アーキテクチャー.snap
」
「--debug
」snap/
を変更した上で、snapcraft
コマンドを実行したらビルドを継続してくれます。何がおかしいかをトライアンドエラーで調べたい際に便利です。
作成したパッケージのインストール
作成したsnapパッケージは次の方法でインストールできます。
$ sudo snap install my-snap-name_0.1_amd64.snap --dangerous --devmode my-snap-name 0.1 installed $ snap info my-snap-name name: my-snap-name summary: Single-line elevator pitch for your amazing snap publisher: – license: unset description: | This is my-snap's description. You have a paragraph or two to tell the most important story about your snap. Keep it under 100 words though, we live in tweetspace and your description wants to look good in the snap store. refresh-date: today at 23:11 JST installed: 0.1 (x1) 4kB devmode
「confinement
」devmode
なため、--demode
」--devmode
」--dangerous
」
実際にパッケージの中身を見てみましょう。
$ ls -R /snap/my-snap-name/ /snap/my-snap-name/: current x1 /snap/my-snap-name/x1: meta /snap/my-snap-name/x1/meta: snap.yaml
パッケージのメタデータだけがインストールされており他は何もないパッケージですね。ちなみにless my-snap-name_
」
サンプルパッケージを削除するには次のコマンドを実行してください。
$ sudo snap remove --purge my-snap-name my-snap-name removed
適当なファイルを追加でインストールする
「--debug
」snapcraft.
のpartsを次のように編集します。
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
my-part2:
plugin: dump
source: local-files/
dumpプラグインはソースツリーにある任意のファイルをそのままsnapパッケージに取り込むためのプラグインです。source
で指定したファイルを、
このままパッケージを作ってみましょう。今はまだlocal-files
」
$ snapcraft --debug Launching a VM. Failed to pull source: unable to determine source type of 'local-files/'. Check that the URL is correct or consider specifying `source-type` for this part. See `snapcraft help sources` for more information. snapcraft-my-snap-name #
パッケージのビルドが失敗し、local-files
ディレクトリを作り、
$ mkdir local-files $ touch local-files/test.txt
ビルド用仮想マシンのシェルの中で再度snapcraftコマンドを実行します。
snapcraft-my-snap-name # snapcraft (snip) Snapped my-snap-name_0.1_amd64.snap snapcraft-my-snap-name #
今度は無事にパッケージが完成したようです。exitコマンドでログアウトして、
$ less my-snap-name_0.1_amd64.snap | cat path: "my-snap-name_0.1_amd64.snap" name: my-snap-name summary: Single-line elevator pitch for your amazing snap version: 0.1 devmode build-date: today at 23:21 JST license: unset description: | This is my-snap's description. You have a paragraph or two to tell the most important story about your snap. Keep it under 100 words though, we live in tweetspace and your description wants to look good in the snap store. *** Contents: Parallel unsquashfs: Using 8 processors 2 inodes (1 blocks) to write drwxr-xr-x root/root 43 2021-02-11 23:21 drwxr-xr-x root/root 32 2021-02-11 21:40 /meta -rw-r--r-- root/root 407 2021-02-11 23:21 /meta/snap.yaml -rw-rw-r-- root/root 0 2021-02-11 23:20 /test.txt
きちんとlocal-files
以下のtest.
がインストールされるようになりました。
このようにsnapcraftは、
ユニバーサルパッケージとは
最後にsnapパッケージやそれに類いするパッケージフォーマットで言及されることの多い、
「ユニバーサルパッケージ」
歴史的経緯から、
パッケージングにおいて最もネックになるのが
そんな状況を打破するために考えられたのが
- ディストリビューションをまたいで、
同じバイナリパッケージをインストール可能 - 依存関係は原則存在せず、
必要なものはすべてパッケージの中に取り込んだ状態で提供する - サンドボックス化によるセキュリティの向上と、
ディストリビューションとアプリケーションの分離の推進
ソフトウェアは多かれ少なかれ何らかの別のソフトウェアに依存しています。Linux上で動くELFバイナリであれば、
また
結果として任意のバイナリパッケージは、
ユニバーサルパッケージでは、
依存関係に基づくバージョンもパッケージを作る側でコントロールできるため、
しかしながらこれらのメリットを実現するためには、
- パッケージサイズが大きくなる
- ライブラリとの柔軟な組み合わせができない
- パッケージ管理システムそのものの複雑性が増える
- サードパーティのパッケージの利用に対する是非
ディストリビューションのパッケージは、
この品質の高さが従来のパッケージ管理システムの強みであり、
- ソフトウェア開発者:ユニバーサルパッケージフォーマットを用いて、
常に最新のディストリビューションに依存しないパッケージを提供する - ディストリビューター:従来のパッケージフォーマットを用いて柔軟に組み合わせ可能で、
なおかつディストリビューションの中において一貫性の高いパッケージを提供する
ユーザーは用途に応じて2種類のパッケージを使い分けることになります。まず、
Snap以外のユニバーサルパッケージ
さて、
- Nix
-
おそらくユニバーサルパッケージ的な考え方の先駆けとも言うべき存在で、
2000年代前半から存在していたようです。 - AppImage
-
これも比較的早くから存在していた仕組みで、
アプリケーションをISOイメージに閉じ込めることで、 「パッケージ管理」 が不要になっています。 - Flatpak
-
FedoraおよびRHELが強力に推進しているフォーマットで、
今のところGUIアプリケーションをメインターゲットにしているようです。 - Snaps
-
Ubuntu/
Canonicalが推進しているフォーマットです。他と比べると強力な権限管理機能が売りとなっています。 - Docker
-
言わずとしれたコンテナプラットフォームの主役です。最近は任意のアプリケーションの実行環境としての地位も確立しているため、
DockerHubて配布されているコンテナイメージはある種のユニバーサルパッケージと言えるでしょう。
Flatpakについては第513回の
今回紹介したSnapsは、
たとえばLXD、
IoTからサーバー、