の続編。件の記事で挫折した内容が達成できたので書く。
mkosi
によるイメージのビルド時に AUR パッケージのビルドとインストールもあわせてやる方法が実現できた。
これによって先の内容は無用となった。哀しい。
TL; DR
をみてもらうのが手っ取り早い。
解説
上の通りなのだがそれではブログに書く意味がないので言葉で説明する。
ビルド中のコンテナから外に出れない
mkosi.default
の [Packages]
内で WithNetwork=yes
を与えるか mkosi
自体に --with-network
を与える。
こうすることで mkosi.build
スクリプトが実行される段階(mkosi
の man 内容でいう development image)でコンテナから外に出れる。
man に書いてあったのを見落としていた。man はちゃんと読むべきだった。
ちなみに WithNetwork=yes
をすると mkosi
を実行しているホストのネットワークがそのまま使用され、そうでない場合は systemd-nspawn
コマンドに --private-network
が付与されるようだった。
ホストとコンテナとでネットワークまわりの namespace が共有されてしまうのはちょっと気持ち悪いが、まあいいか……。
ビルド対象が依存するパッケージをいれる
上の WithNetwork=yes
でインターネットに出れるようになる為、 pacman -U
する際の依存関係解決も pacman
側で任せられるようになる。
よって mkosi.default
の [Packages]
内に依存パッケージをズラズラ書いておく必要がなくなる。単に pacman -U --noconfirm
とかすればよい。
ただデフォルトでは /etc/pacman.d/mirrorlist
の内容が全部コメントアウトされているので、 mkosi.postinst
あたりで適当なミラーをアンコメントするなり適当なファイルで書き換えるなりする処理がが必要。
私は後者を選んだ。
PKGBUILD をコンテナ内に持ち込む
あらかじめ AUR 上のパッケージを手元に git clone
しておく。以下では git clone
してできたディレクトリを aurpkg/
とする。
mkosi.default
の [Package]
内で以下のようにしてやればよい:
BuildSources=aurpkg
を指定SourceFileTransfer=mount
を指定
こうすると mkosi
するディレクトリの中にある aurpkg/
というディレクトリがビルド用コンテナ内から $SRCDIR
(/root/src
) で参照できる。
makepkg
コマンドを叩く
makepkg
コマンドは root では実行できない。しかし mkosi.build
は root として実行される。どうするか。nobody ユーザとして makepkg
を実行してやればよさそう。
具体的には sudo -u nobody -- bash -c "makepkg -sr"
などとやればよい。
ただしこれを実行すると AUR パッケージが必要とするパッケージをインストールする段階にうつり、nobody ユーザが sudo
で root になる為のパスワードをきかれてしまい悲しいことになる。
なので事前に PKGBUILD の depends
や makedepends
に書かれてるものを pacman -S --noconfirm
しておくのがよい。
以上を踏まえて私は以下のようにした:
source $SRCDIR/PKGBUILD [[ -n "$depends" ]] && pacman -Sy --noconfirm "${depends[@]}" [[ -n "$makedepends" ]] && pacman -Sy --noconfirm "${makedepends[@]}"
また makepkg
は自身が使うディレクトリを一旦 mkdir -p
してみる実装になっているようで 1、 $SRCDIR
(/root/src/
) や $BUILDDIR
(/root/build/
) を nobody ユーザで mkdir -p
できるようになっていないとエラーを吐いてコケてしまう。これには /root/
で nobody ユーザが実行権限をもっている必要がある。
加えて $BUILDDIR
や $SRCDIR
および後述する $DESTDIR
(/root/dest/
) それ自体も nobody ユーザから読み書きができるようになっていないと必要なファイルを参照したり作成できなくなってしまうので、これまたコケてしまう。
よって setfacl
で以下のようにしてやる:
for DIR in $BUILDDIR $SRCDIR $DESTDIR; do setfacl -m u:nobody:rwx $DIR setfacl -d --set u:nobody:rwx,o::- $DIR done setfacl -m u:nobody:rwx /root setfacl -d --set u:nobody:rwx,o::- /root
makepkg
の結果をどうインストールするか
mkosi.build
が実行される development image の段階で生成物を pacman -U
しても最終的に得られるイメージには反映されない。development image はあくまで中間イメージであり、最終成果物を得る為の過程にすぎない為だ。
また mkosi.build
を実行することで作成された内容は $DESTDIR
(通常はコンテナ内 /root/dest/
)に移しておかないと mkosi.build
終了時に中間イメージごと消滅してしまう。
mkosi.postinst
は中間イメージ作成時と最終イメージ作成時の双方で実行されるので、 pacman -U
を mkosi.postinst
で実行してあげればよい。
また mkosi.build
で makepkg -sr
した結果作成されたパッケージを $DESTDIR
下に移すには makepkg
する際に PKGDEST
という環境変数を $DESTDIR
にしてやればよい。こうすることで作成されたパッケージは $DESTDIR
以下に出力される。
$DESTDIR
に移された成果物は最終イメージ内 /
直下に配置されるので、 mkosi.postinst
では /
下にあるパッケージを pacman -U
してやればよい。
# mkosi.build # mkosi.build は $SRCDIR (/root/src/) で実行されるので makepkg する前にディレクトリを移動する必要はない # PKGEXT を変えているのは生成物を xz で圧縮させないようにさせるため sudo -u nobody -- bash -c "PKGDEST=$DESTDIR PKGEXT='.pkg.tar' makepkg -sr"
# mkosi.postinst for CANDIDATE in /*.pkg.tar; do if [ -e "$CANDIDATE" ]; then pacman -U --noconfirm "$CANDIDATE" rm -f "$CANDIDATE" fi done
まとめ
とりあえずやりたいことはできるようになったのでよかった。なんかもっとシンプルにできそうな気もするが、今はこれが限界。