GitHub ActionsでTauriアプリのSnapパッケージを自動ビルドする

Tauriでアプリを作っているんだけど,snapパッケージをビルドしてSnap Storeにアップロードしたいと思った.

しかしドキュメントにはsnapに関する記述がない.

tauri.app

また,Tauriは公式でGitHub Actionsを提供していて,こいつを使ってビルドできるのだが,こいつもsnapをサポートしている様子がない.

github.com

tauri-snap-packager

というわけで別のパッケージを使ってsnapをビルドするわけだが,

github.com

こいつを使ってみた.

ただし,これにはいくつか問題点がある.

  1. multipassが必要になる
  2. ビルドするとsnapcraft.ymlが生成されるが,grade: 'devel' 指定のため,このままだと snapcraft upload できない
  3. summarydescription もデフォルトのままなのでカスタマイズできない
  4. core18に依存しており,かなり古い

1の大きな問題点は,GitHub Actionsだ.GitHub Actionsでmultipassを動かすのはかなり難しい.

github.com

このため,使うのであれば,lxdの方を推奨されており,これはActionsが用意されている.

github.com

しかしここまでクリアしても, gradeの問題は残る. ローカルでやるのであれば,一度 tauri-snap-packager でビルドしたあと,snapcraft.ymlを修正し snapcraft コマンドを再度実行することで再ビルドされる.

しかし,GitHub Actionsでビルドされるとなると,これを毎回シェルスクリプトでやるのは虚しい.

というわけで作った

github.com

独自のtauri-snap-packagerを作った.

差分としては,

  1. core20にアップデート
  2. grade: 'stable'
  3. summarydescriptionはtauri.conf.jsonから取ってくる

状態にしたので,ビルドしたらそのままアップロードできる.

全体としてはこんな感じ

jobs:
  snap:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    env:
      SNAPCRAFT_BUILD_ENVIRONMENT: lxd
      SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Node.js setup
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - uses: pnpm/action-setup@v2
        with:
          version: 8
      - name: Rust setup
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
      - name: Setup LXD
        uses: canonical/setup-lxd@main
        with:
          channel: latest/stable
      - name: Install snapcraft
        run: |
          sudo snap install snapcraft --classic
          sudo snap install lxd
      - name: Install app dependencies and build
        run: pnpm install --frozen-lockfile && pnpm tauri build

      - name: Build snap
        run: |
          pnpm run snap
      - name: Publish
        working-directory: src-tauri/target
        run: |
          snapcraft upload ./*.snap --release beta

これでGitHub Actionsから自動でsnapパッケージをビルドして,betaにアップロードするところまでやってくれる.

『駒田蒸留所へようこそ』が良すぎた

今年はなんといっても『駒田蒸留所へようこそ』が良かった. TVアニメ含めた 2022年 2023年アニメの中で一番の出来といっても過言ではない.

見るのが遅くなってしまったので,今頃これを書いているけど,終盤なのでおそらくもう上映館もかなり減ってしまっていると思う.

www.youtube.com

P.A.WORKSのアニメのお仕事シリーズというのは,背後に壮大なストーリーもなければ世界を救ったりもしない,もちろん異世界に行ったりもしないごく平凡な日常ではある. けれど,2010年代に流行った日常系ゆるふわアニメとは少し違っていて,多少の事件はあるし,そこには成長も挫折もある場合が多い. こういう塩梅が非常にちょうど良くて,リアルなアニメに仕上がっている.

さらに早見沙織はこのアニメの声にぴったりだ.実に落ち着いていて空気感にマッチしている.むしろこれを見たあとでは早見沙織以外この声は思いつかない.

駒田蒸留所も,この路線は健在で,実にいい塩梅で仕上がっている.いや,むしろ短い,もっと長い時間かけて見せてほしいくらいのアニメだった. テーマ自体に「時間がかかるもの」であることが読み取れるので,劇場版120分弱だと,アニメのほうが短く感じてしまう.まぁ作るのには相当時間がかかったのだろうが.

原正行監督作品は『有頂天家族』以来だけど,あれよりはだいぶリアルによった作品になっている.ただ,気になるのは背景美術くらい. ウィスキーやグラスの表現力はさすがP.A.WORKSという実に見事な仕上がりだけど,空や雲といった美術は『有頂天家族』のときのようなアニメ調.雲を見るとはっきりアニメだと認識させられるのだけれど,これにはなにか意味があるんだろうか. ここまでリアルによった表現で,綺麗になっているのに,なぜ空だけ「アニメです」というような主張にするんだろう.そこだけがちょっと気になった.

mantan-web.jp

これはもっと早く見に行けばよかったと後悔.もう一度劇場に行ってもいいくらいの作品だった.

megalodonのMisskeyサポートを終了する

タイトルの通りのことを行った.

github.com

その代わりと言ってはなんだけど,Firefishのサポートを開始している.

fedi.software

WhalebirdからもMisskeyサポートがなくなる

megalodonはWhalebirdFedistarからもクライアントライブラリとして利用している.当然,WhalebirdからもMisskeyは使えなくなる.Fedistarは最初からサポートしていなかったので関係ない.

とりあえず,まだこのへんの終了対応はしていないんだけど,次のバージョンアップで完全に切ろうかと思っている.

理由とか

クリティカルな大きな事件があったわけではないんだけど,少しずつ積み重なってこういう決断に至った.

APIの変更頻度がそれなりに高いのにドキュメントがクソ

Misskeyは今年になってからドキュメントページをリニューアルしている. そして,今のAPIドキュメントはここだ.

misskey-hub.net

俺がこの件で悩んでいた5月くらいは,そもそもエンドポイント一覧のドキュメントすらなかった. 今は一応全部リストアップされているが,それでもすべてのレスポンスが記述されているわけではない.

例えば, /users はユーザの一覧を返すが,UserDetailedのページは存在しない.

users | Misskey Hub

そもそもMisskeyは,/notes 系のAPIのレスポンスであるNote に含まれるUserと, /users 系のレスポンスである UserDetail が別物であり,この辺のハンドリングは非常に苦労する. エンティティという概念が希薄であるとしか思えない.

にもかかわらず,ドキュメントにエンティティの情報がないので,結局全部自分でAPIを叩いて確認しないといけない. megalodonで最初にMisskey対応をしたときも,(リニューアル前のAPIドキュメントだったが)ドキュメントに乗っているレスポンスと,実際に叩いた際に帰ってくるレスポンスが違うことがよくあり,結局ほとんどcurlしながら開発した.

更新頻度の低いソフトウェアなら,「まぁそんなにコントリビュートしてくる人もいないのかね」と同情したくなるが,これでいてAPIの破壊的変更はそれなりにある. つまりコントリビュートしている人にとっては,APIドキュメントはそんなに重要ではなく,サードパーティー製のアプリケーション開発者も大して大事じゃないだろう.

Misskeyサポートを要求する人は別に手伝ってくれない

そういう経緯があって,Whalebirdもmegalodonも,Misskeyの新APIに対応するのが遅れていたりしてIssueが立ったりしていた. が,前述の通りドキュメントが当てにならないので,変更されたAPIについてはソースコードを読むかcurlしてまた実際のレスポンスを確認しながら修正する必要がある.

これに手が回らなくなって

github.com

こういうIssueを立てたのが4月. 5ヶ月経ったが,メンテなの立候補どころか上記の件に対するPRもない.GitHub Sponsorが増えるわけでもない.

みんな新機能への対応は要求するけど,手を貸すのは嫌だということ,自分でコストも負担したくないということ.

絵文字の変更が破壊的すぎた

おそらくv13あたりからだと思うけど,Emoji reaction周りにかなり大きな変更が入った. reactionEmojis にリモートの絵文字情報は入るようになっていたのだが,ローカルで登録されているカスタム絵文字に関する情報が Note エンティティに存在しない. これはおそらく別のAPIを叩いて,サーバのカスタム絵文字一覧を取ってきて,クライアント側で合致させる必要があるのだろうが,これが致命的だった.

megalodonはNode.jsとRustで提供するクライアントライブラリだ.これ自体をアプリケーションとして利用する人はほぼいない. だから,例えばWebSocketでNotificationを受信したとき,内部の絵文字情報を取得しようとすると,それだけでは情報が足らない.かと言って Note をパースするたびに絵文字一覧APIを呼び出すのは非効率だ. いや,サーバのことを考えなければ毎回呼び出してもいいのかもしれんが.

まぁMisskeyの開発チームは,WebUIを主眼に開発しているわけで,APIの使い勝手というのはWebUIを作りやすいようにしているのだろう. だから,きっとWebUIはこれで使いやすいのだろうが,クライアントライブラリとしては,ほぼ対応不可能になってしまった.やろうと思えば,事前に絵文字一覧を取得して,どこかに保存して……ということもできなくはないのだろうが. それをやるほどのモチベーションはすでにないし,誰か別の人がやってくれそうにもない.

Misskey.ioの邪魔はしたくない

Misskeyサポートを求めている人の87%くらいはmisskey.ioを使っているんじゃないだろうか.そのくらいMisskeyの中でioは勢いがあると思うけれど,ioの運営は最近法人化した. これだけのユーザ数を支えるのにかなりのコストを払っているはずで,ioには広告も導入されている.

別にioに特に思い入れがあるわけじゃないんだけど,3rd partyのクライアントは広告と相性が悪い.広告専用のAPIがあるわけでもないし,広告をいれなきゃ使えないわけでもない. となると,当然Whalebirdにはioの広告は表示されないわけだけど,これは一面ではioの運営を邪魔していることになる. Whalebirdがサポートを止めたところで,他のクライアントがサポートしてたら,みんなそっちを使うだけなのかもしれないけど.それでも邪魔はしたくないと思った.まぁ,これは言い訳に近いけど.

Firefishのサポートをする

代わりと言っては何だがFirefish (Calckey) のサポートを開始する.

作ってみた限り,こっちのほうがAPIドキュメントは親切で,一応ちゃんとドキュメント通りのレスポンスが帰ってくるし,不足しているエンティティはたぶんない. ベースが同じなので, UserUserDetail が別物だとか,そいういクソな部分はまだ少し残っているけど,以前のMisskeyクライアント部分をかなり流用して作ることはできた.

まぁRust版の方はベースが存在しなかったので,全部初めから作ったのだが.それが作れるくらいには十分なドキュメントだったように思う.

まとめ

結局OSSというのは,みんな無料だから使っているだけで,そこに自分でコストを払って参加したり,Sponsorになったり,そういうことをする人は稀なんだろう.そして有料化したら,みんな使わないんだろう,どうせ. なので,たとえ要望が来たとして,俺が使わない機能に関して「俺は実装しない」という方針で行こうかと思っている.もちろん欲しい人がPRを送ってくる分には歓迎だけど.

WhalebirdやFedistarを有料化することも考えたけど,有料化するのはそれはそれで,「ユーザが求めている機能を実装しなきゃいけない」圧力を感じてしまうので,止めた.

さよならMisskey

おうちKubernetesにLonghornを入れる

  1. Raspberry Piを買っておうちKubernetesクラスタを作る
  2. おうちKubernetesにSealedSecretsを入れる
  3. Raspberry Piの固定IP割当をルーターから指定する
  4. おうちKubernetesのcontrolplaneを3台に増やす
  5. おうちKubernetesLonghornを入れる <- イマココ

Nodeとなるマシンを一つ増やした.

ChuwiのLarkBox X2023.N100のCPUがほしいなーと思っていたんだけど,N100のMiniPCでDDR5メモリで500GB程度のSSDがあるものを探したら,これに落ち着いた. メモリが12GBと,8GBでも16GBでもないのだけれど,まぁnodeに使うだけだし特に気にせず買った.

これでAmazonのクーポン使って24900円.安い.

www.chuwi.com

で,そろそろ真面目に使えるようなクラスタになってきたので,PVCを作れるようにしたいと思う.というわけでSDSを入れよう. NASという手もあるんだけど,どうせnodeはみんな500GB程度のディスクを持っているし,そこまで大量のデータを入れるつもりもないので,とりあえずSDSを入れてみたいと思う.

SDSの選定

最終的にLonghornを選んでいるわけだけど,正直いまLonghornはそこまで主流ではないと思う.やはり今の主流はRook-Cephじゃないだろうか.

ただ,個人的にはそこまでパフォーマンスを求めていない.台数をあまり増やそうとも思っていないし,Cephの恩恵があるほどの規模になる予定がない. そうなると,むしろLonghornのように復旧が容易な方がメリットが大きいように思う.

ここで述べられている通り,LonghornであればLonghorn自体が壊れていてもデータを救出することができる.

ちなみにデータの救出については公式ドキュメントにも書かれている.

longhorn.io

ノード側の準備

LVMを有効化しておく

longhorn.io

ここに書かれている通り,LonghornではLVMを推奨している.こうすることで,/var/lib/longhorn に割り当てるパーティションの容量を,あとから変更することができるため,拡張性に優れている.

というわけで,Ubuntu Serverインストール時にLVMを有効化しておく.パーティションとして,適当なサイズを用意して /var/lib/longhorn にマウントしておく.

Longhornのインストール

longhorn.io

Helmでインストールするだけ.

service:
  ui:
    type: LoadBalancer

こうしておくと,MetalLBとかでIPを割り当ててくれるので,手元からアクセスできたりする.

バックアップの設定

これだけだとちょっと不安なので,大事なデータはバックアップを設定しておく.

まず,適当なS3 Bucketを用意して,そこにアクセスできるIAM Userを作り,

を,以前いれたSealedSecretsで暗号化してaws-secretsとか適当な名前のSecretsとして適用しておく.

あとはLonghorn UIから行う. Settings -> Generalを開いて,Backupセクションを探す.

Backup Target: s3://my-bucket@ap-northeast-1/
Backup Target Credential Secret: aws-secrets

こういう設定を入れる.

これであとは,同じくLonghorn UIから,個別のVolumeごとにBackupを取得できる. Backup作成のジョブは定期ジョブにすることもできる.

longhorn.io

参考

tech.opst.co.jp

light-of-moe.ddo.jp

www.aimhighergg.com

おうちKubernetesのControlPlaneを3台に増やす

  1. Raspberry Piを買っておうちKubernetesクラスタを作る
  2. おうちKubernetesにSealedSecretsを入れる
  3. Raspberry Piの固定IP割当をルーターから指定する
  4. おうちKubernetesのcontrolplaneを3台に増やす <- イマココ

ついに追加のRaspberry Piを買った.

こいつらを使ってControlPlaneを合計3台に拡張する.

joinコマンドを再発行する

1台目のControlPlaneを作った時点で,kubeadmからjoinコマンドが提示されていた.

$ kubeadm join kube-apiserver.h3poteto.local:10443 --token hogehoge.fugafuga \
  --discovery-token-ca-cert-hash sha256:hogehogefugafuga \
  --control-plane

このtokenは24時間で有効期限が切れてしまうので,今回のようなケースではとうの昔に期限切れになっている.というわけで,新しいtokenを使ったjoinコマンドを再発行してもらう.

1台目に入り,

$ kubeadm token create --print-join-command

とかすると,新しいtokenを使ったjoinコマンドが再発行される. これを2台目以降のControlPlaneで実行する.

しかし,ControlPlaneの場合,これだけだと不足していて,

[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
error execution phase preflight:
One or more conditions for hosting a new control plane instance is not satisfied.

[failure loading certificate for CA: couldn't load the certificate file /etc/kubernetes/pki/ca.crt: open /etc/kubernetes/pki/ca.crt: no such file or directory, failure loading key for service account: couldn't load the private key file /etc/kubernetes/pki/sa.key: open /etc/kubernetes/pki/sa.key: no such file or directory, failure loading certificate for front-proxy CA: couldn't load the certificate file /etc/kubernetes/pki/front-proxy-ca.crt: open /etc/kubernetes/pki/front-proxy-ca.crt: no such file or directory, failure loading certificate for etcd CA: couldn't load the certificate file /etc/kubernetes/pki/etcd/ca.crt: open /etc/kubernetes/pki/etcd/ca.crt: no such file or directory]

Please ensure that:
 The cluster has a stable controlPlaneEndpoint address.
 The certificates that must be shared among control plane instances are provided.


To see the stack trace of this error execute with --v=5 or higher

というようなエラーになる.

Certificateを探す

前述のエラーを見ると, /etc/kubernetes/pki/ca.crt がないと言われている.確かにそんなものはない. これは手動でコピーしてきて,ここに配置してもいいのだけれど,kubeadmで自動的に行っても良い.

まず,1台目のControlPlaneに戻る.

ここで

$ sudo kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
xxxxxxx

をやる.

kubeadmはこのようにinit時のphaseを個別に指定して実行することができる.で,upload-certsをやると,certificateの内容がSecretsに書き込まれる. で, --certificate-key を指定することで,そのSecretから /etc/kubernetes/pki/ca.crt 等の必要な証明書を作ってくれる.

というわけで,2台目で

$ kubeadm join kube-apiserver.h3poteto.local:10443 --token hogehoge.fugafuga \
  --discovery-token-ca-cert-hash sha256:hogehogefugafuga \
  --control-plane \
  --certificate-key xxxxxx

--certificate-keyupload-certsで出てきたcertificate keyを貼り付けると,無事joinできる.

あとは3台目も同じコマンドでいける.

HAProxyを3台用に更新

h3poteto.hatenablog.com

ここで紹介していた,haproxyの設定を更新して,3台にリクエストを分散できるようにしていく.

backend kube-apiserver
        mode tcp
        option tcplog
        option tcp-check
        balance roundrobin
        default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
        server kube-apiserver-1 192.168.0.50:6443 check
        server kube-apiserver-2 192.168.0.51:6443 check
        server kube-apiserver-3 192.168.0.51:6443 check

keepalivedも3台対応しておく.

vrrp_instance haproxy-vip {
  state BACKUP
  priority 100
  interface wlan0                       # Network card
  virtual_router_id 60
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass 1111
  }
  unicast_src_ip 192.168.0.50      # The IP address of this machine
  unicast_peer {                        # The IP address of peer machines
    192.168.0.50
    192.168.0.51
    192.168.0.52
  }

  virtual_ipaddress {
    192.168.0.40/24                  # The VIP address
  }

  track_script {
    chk_haproxy
  }
}

これで,たとえ1台が死んだとしても,VIPでアクセスしていれば2台目以降がレスポンスを返してくれる.

参考

kun432.hatenablog.com

github.com