カテゴリー: package management

  • Snap パッケージを開発して学んだこと

    fpocket を題材にした CI/CD と Snapcraft 実践録

    ここでは、私がオープンソースの分子ポケット検出ツール fpocketsnap パッケージ として公開しようと試みた経験をまとめます。
    Snapcraft の基本から GitHub Actions を用いた CI/CD、自動更新チェックの仕組み、そしてつまづいたポイントまで、私が実際に体験した内容を中心に書いています。

    snap パッケージ化に興味がある方や、CI を使った自動ビルド・公開を行いたい方の参考になれば幸いです。


    1. はじめに

    Linux ディストリビューション間で依存関係の差があると、バイナリ配布が難しくなることがあります。
    fpocket は C 言語製で比較的コンパイルしやすいのですが、一般ユーザーにとってはインストールの手順が多く、簡単とは言えません。

    そこで、クリック一つでインストールできる snap パッケージとして提供できれば便利だと考え、開発を始めました。

    しかし、snapcraft は奥が深く、パッケージング・CI/CD・Snap Store 運用など、多くの学びがありました。
    この記事では、そうした経験を整理して紹介します。


    2. Snapcraft の基礎

    まず、Snapcraft の基本を簡単におさらいします。

    ● snap の confinement

    snap にはアプリの権限レベルを示す confinement(制限モード) があり、次の 3 種類があります。

    モード 説明
    strict 最も制限が強く、標準的なモード。Snap Store で公開する場合は基本これ。
    devmode 開発用。strict に必要な許可が足りていない場合でも動くが、公開不可。
    classic 権限制限なし。伝統的ツール向け。使用には審査が必要。

    一般的な CLI ツールは strict で動かすのが基本です。また今回の fpocket-snap では、 interfaceshome のみを使用します。

    ● Snapcraft のビルド方式

    snap のビルドには複数の方法があり、それぞれ環境の隔離強度が異なります。

    ビルド方法 特徴
    Multipass core20の場合、Multipassはすべてのプラットフォームでデフォルトのプロバイダー。
    LXD core22以降では、LinuxではLXDがデフォルトプロバイダーであり、macOSおよびWindowsではMultipassがデフォルトとなる。
    –destructive-mode ホスト環境でビルド。再現性は低いが高速。

    この中で、特に注意が必要なのが --destructive-mode です。後述します。


    3. --destructive-mode とは何か

    Snapcraft には、ビルド時に --destructive-mode という特別なオプションがあります。

    snapcraft --destructive-mode

    ● 何ができるのか

    • Multipass や LXD が不要
    • つまり build container 起動不要
    • ホスト環境上で直接ビルドできる
    • CI での簡易ビルドやデバッグに便利
    • VM が起動できない環境で使える

    ● なぜ用意されているのか

    • 「動くかどうかだけ確認したい」
    • 「依存パッケージが揃っている環境で簡単に試したい」
      といった、開発者向けの簡易ビルド用途が目的です。

    ● 公開用パッケージに使ってはいけない理由

    結論として、このモードでビルドした snap を Snap Store に公開するべきではありません

    理由は次の通りです。

    • ビルド環境の汚染が反映される可能性がある(再現性がない)
    • 必要な依存関係が “たまたま” ホストにあるために成功してしまう
    • ビルド環境とsnap baseが一致するとは限らない
    • 安全性の検証が不完全になる
    • Snapcraft 公式が推奨していない

    core22 指定なのに Ubuntu 24.04 でビルドすればエラーになるでしょう。GitHub でホストされる runner (この場合はUbuntu)がずっと同じバージョンとは限りません。

    つまり、開発や検証のためのモードであり、最終版の公開には使用しないのが正しい使い方です。


    4. fpocket-snap の構成説明

    私が構築したリポジトリは次のような構成にしています。

    fpocket-snap/
    ├── .github/
    │   └── workflows/
    │       ├── release.yml
    │       └── upstream-check.yml
    └── snap/
        └── snapcraft.yaml

    GitHub Actions で自動ビルド・公開し、加えて upstream の fpocket に更新がないか定期的にチェックする仕組みを入れています。


    5. snap/snapcraft.yaml の詳細解説

    Snapcraft の定義ファイルは本来リポジトリ直下に置くことが多いのですが、今回は整理のために snap/ ディレクトリに配置しました。

    snap/ に置く理由

    • プロジェクトルートを汚さない
    • GitHub Actions で複数の設定を扱うときに見通しが良い
    • Snapcraft 側も問題なくサポートしている

    ● 主な構成

    fpocket-snapのsnap.yamlを参照してください。

    内容としては次のポイントが重要です。

    • makefile に書かれているパス等の調査を反映
    • parts でソースコードとビルド手順を指定
    • build-packages はコンパイルに必要なパッケージ
    • stage-packages はランタイム依存
    • strict モードで動作するように設計
    • Snap Store のページ の紹介文になる情報も記載する
    項目 説明
    summary ストアの検索結果などに表示(短文)
    description 詳細ページに表示(複数行OK)
    title 見出しとして表示される(省略可)
    作成者名 snapcraft.yaml 内には不要(ストア登録時にアカウント名が自動的に「publisher」として表示)
    README.md 自動では反映されない。description部分が代わりに使われる。
    スクリーンショット 手動でSnapcraftダッシュボードからアップロード可能。
    フィールド 目的 fpocket の場合の内容
    website Snapパッケージに関する公式ページ(=あなたがメンテナンスしているsnapラッパープロジェクト) 🔗 https://github.com/akuroiwa/fpocket-snap
    source-code ソフトウェア本体(上流プロジェクト)のソースコードURL 🔗 https://github.com/Discngine/fpocket など、fpocketの公式リポジトリ

    Snapcraft の定義は簡潔ですが、Tiny な CLI ツールには十分です。


    6. GitHub Actions のワークフロー構成

    6-1. release.yml

    この workflow は タグを切ったときに snap をビルドして Store へ公開するためのものです。

    主な流れは次のとおりです。

    1. コード checkout
    2. snapcore/action-build@v1 で snap をビルド
    3. snapcore/action-publish@v1 で Store に公開

    snapcraft.yaml が snap/ にある場合

    デフォルトではルートにあると認識されるため、次の指定が必要です。

    with:
      path: snap/

    これがないとビルドが失敗します。

    ● パッケージ名登録と認証トークン

    パッケージ名は事前に調べ、snap store に存在しないことを確認しなければなりません。Ubuntu One のアカウントが必要です。

    snapcraft register fpocket
    snapcraft export-login --snaps fpocket --channels stable,edge snapcraft_token.json
    snapcraft logout

    生成したトークンの中身(ファイル内の文字列)を GitHub Actions の secret にペーストし保存しますが、その際に yml ファイルから呼び出す環境変数名でなければなりません。

    私の場合、トークン生成時にチャンネル指定の不備が原因で公開に失敗し、再登録後に workflow を re-run して修正することがありました。使用するチャンネルが複数ある場合は必ず指定しなければなりません。


    6-2. upstream-check.yml

    fpocket 自体の更新を監視するための workflow です。

    • cron で定期実行
    • GitHub Releases を確認
    • 新しいリリースがあれば issue を自動作成
    • Issue 作成時にメール通知されるため、見逃しにくい

    fpocket の upstream に動きがあった際に素早く対応できるので便利です。


    7. GitHub Actions: Snapcraft Actions の解説

    snapcore/action-build@v1

    Snap をビルドする Action です。この アクション は自動で LXD を使います。


    snapcore/action-publish@v1

    ビルドした snap を Snap Store のチャネルに公開します。

    with:
      release: stable

    チャネルとしては stable, candidate, beta, edge が選べます。
    オプション無しでインストールできるのは stable(安定版)のみです。

    snapcore/action-build@v1 の出力は id: build を付けることで ${{ steps.build.outputs.snap }} として利用可能です。これにより、.snap の明示的なパス指定(snap/*.snap)が不要になります。


    8. 実際のトラブルと解決策(経験ベース)

    ここからは、私が実際に遭遇したトラブルです。

    ● snapcraft コマンドの変更

    snapcraft list-revisions

    は現在、

    snapcraft revisions

    にリネームされています。
    古いコマンドを使うと警告が出ます。

    snapcraft revisions fpocket #Rev.としてrevision番号を出力する
    snapcraft release fpocket 1 stable #Rev.を特定した1で指定しstableに昇格する

    ● トークン無効による公開失敗

    snapcraft export-login で作成したトークンが権限不足で動作せず、
    workflow が失敗することがありました。
    再生成と再登録で解決しました。

    ● 構成順序のミス

    設定順序の問題で snapcraft が正しく読み込まれず、ビルドエラーが発生したこともあります。snapcore/action-build@v1 実行後でなければ動作しません。snapcraft: command not foundと怒られてしまいます。
    workflow ファイルの記述順は意外と重要です。


    9. まとめ

    fpocket の snap 化を通じて、多くの知見を得ました。

    • snapcraft は強力だが慣れが必要
    • strict モードで動かすための調整が大切
    • GitHub Actions での自動ビルド・公開は便利
    • --destructive-mode は開発時に便利だが、本番公開には不向き
    • upstream 更新チェックによる自動監視は役立つ

    snap パッケージの配布は、Linux ユーザーにとってインストール手順を大幅に簡略化できるメリットがあります。
    今後は multi-arch 対応や、自動テストなどを取り入れて改善していきたいと思います。