ぶていのログでぶログ

思い出したが吉日

Canonical MAASでDebian 12 (bookworm)のカスタムイメージを作ってインストールする

Canonical MAAS(以降MAAS)ではUbuntu、RHELとその互換ディストリ、VMware ESXi、Windowsのインストールに対応している。

maas.io

各公式イメージを使ってインストールする以外にも、カスタムイメージを作りそれを使ってインストールすることもできる。カスタムイメージの作成方法は以下のドキュメントに記載されている。

maas.io

ドキュメントではPackerテンプレートを使った手順が紹介されている。このテンプレートにはUbuntu、RHELとその互換ディストリ、VMware ESXiのカスタムイメージが登録されている。

github.com

これらのディストリ・OS以外でカスタムイメージを作ればMAASでもインストールできるのでは?っと思いついたので、Debian 12をインストールできるようにしてみた。

この記事における前提条件

MAAS環境であれば動作すると思うが、念のため私が試した環境と特筆すべき前提条件や注意事項を書いておく

  • MAAS 3.3.4
  • デプロイ先のマシンはProxmoxVE上のVM
    • ベアメタルやProxmoxVE以外のVMでも問題ないはずだが未検証
  • デプロイ先のマシンはUEFI bootに設定
    • Legacy bootでもデプロイできるが少し手順を変更する必要がある(後述)
  • この手順ではカスタムイメージはroot-tgz方式作成した
    • ディスクイメージをddする方式もあるようだがうまく動かなかった
  • 設定を戻さないとDebian 12以外のカスタムイメージがデプロイできなくなる(後述)

ディスクイメージの準備

まずはインストールするためのディスクイメージを作成する。 ディスクイメージの形式はrootファイルシステムをすべてtarアーカイブで固めたtar形式と、Rawなディスクイメージを使用するdd形式がある。 さらに、それらをgzやbz、xzなどで圧縮する必要がある。 今回はtar形式で作成しそれをgzで圧縮することにする。dd形式も試してみたのだが、tar形式ほどうまく行かず色々調査するのもめんどくなったので次回のチャレンジとする。。

tar形式の作成は比較的簡単で、Debian 12のクラウドイメージをダウンロードしてきてそのクラウドイメージの中身をtar+gzでアーカイブするだけである。 Debian 12のクラウドイメージはqcow2とrawイメージで配布されている。 どちらを使っても差はないが今回はqcow2を使用した。

# https://cloud.debian.org/images/cloud/bookworm/ からqcow2をDLする
# 以下は記事時点の最新イメージ
wget https://cloud.debian.org/images/cloud/bookworm/20230802-1460/debian-12-generic-amd64-20230802-1460.tar.xz

# qcow2イメージを./rootにマウントする
# WSLではnbdデバイスが使えないのでfuseを経由している
qemu-nbd --socket=$(pwd)/nbd.sock --format=qcow2 debian-12-generic-amd64-20230802-1460.qcow2 &
mkdir -p fuse root
sudo nbdfuse fuse --command nbdkit -s nbd socket=$(pwd)/nbd.sock &
sudo kpartx -a fuse/nbd
sudo mount /dev/mapper/loop0p1 root
sudo mount /dev/mapper/loopp15 root/boot/efi

# tarアーカイブの作成
sudo tar -Sczpf debian-12-generic-amd64-20230802-1460.tar.gz --acls --selinux --xattrs -C root .

ディスクイメージのアップロード

次にディスクイメージのアップロードだが、WebUIにはカスタムイメージをアップロードするための画面はないので、maasコマンドを使用する必要がある。 ディスクイメージのアップロードはboot-resources createサブコマンドを使用する。このサブコマンドの詳しい使い方は-hオプションを指定して確認してほしい。

MAAS_PROFILE=api
boot-resources create name=debian-bookworm architecture=amd64/generic title="Debian 12 (bookworm)" filetype=tgz content@=debian-12-generic-amd64-20230802-1460.tar.gz

地味にハマりどころはcontentパラメータは@=にしないといけないところである。 これはヘルプテキストにも書いておらず、エラーメッセージにも記載されていないのだが、公式ドキュメントのどこかに書いてあった(記載場所失念)。

ちなみに、maasサーバが遅くmaasコマンドの実行が遅い環境向けにDockerイメージを用意したのでご活用ください。

github.com

MAASの準備

実はこの記事を書くまでMAASのデプロイの流れを正しく理解しておらず、OSのデプロイはPXEブートでデプロイ対象のOSイメージを起動して自動インストールしているものだと考えていた。 しかし正しくは以下のような順序になっている。

  1. デプロイ用のUbuntuをPXEブートで起動
  2. cloud-initが起動しOSデプロイ用のcurtinコマンドを実行
    • curtinのextractステージでデプロイするOSのディスクイメージをストレージにコピーされる
  3. デプロイが完了したら再起動 4, デプロイさせたOSのcloud-initが起動してMAASから情報をDLする
  4. 4を検知してMAASのステータスがDeployedに変更

UbuntuなどMAASがサポートされているディストリ・OSなら特にこれで問題ないのだが、サポートされていないディストリの場合は2でキックされるcurtinコマンドの動作をいい具合に調整し、デプロイされるOSの設定を正しく行う必要がある。 このcurtinコマンドの設定は /var/snap/maas/current/preseeds/curtin_userdata_custom で行う。 curtinで設定できる内容は公式ドキュメントを参照してほしい。 このファイルを以下のように設定するとDebian 12が正常にデプロイできるようになるはず。

#cloud-config

# Debianのカーネルパッケージ名に合わせる
kernel:
  fallback-package: linux-image-amd64
  package: linux-image-amd64

# Ubuntu用のリポジトリに変更されるのを防ぐ
apt:
  preserve_sources_list: true

# 後続のコマンドで必要なのでjqをインストール
early_commands:
  01_apt-update: ["apt-get", "update"]
  02_install-jq: ["apt-get", "install", "-y", "jq"]

# grub-installがコケるので必要なパッケージをインストール
curthooks_commands:
  01_install_packages:
    - curtin
    - in-target
    - '--'
    - 'bash'
    - '-c'
    - |
      apt-get update && \
      DEBIAN_FRONTEND=noninteractive apt-get install -y efibootmgr grub-efi-amd64

# PXEブートの無効化とデプロイOSのcloud-initの設定を行う
late_commands:
  01_disable_pxe_boot: [wget, '--no-proxy', '{{node_disable_pxe_url}}', '--post-data', '{{node_disable_pxe_data}}', '-O', '/dev/null']
  51_setup_cloudconfig:
    - bash
    - "-c"
    - |
      for kind in maas-cloud-config maas-datasource maas-reporting
      do
        target_path=${TARGET_MOUNT_POINT}/$(jq -r ".cloudconfig.\"$kind\".path" $CONFIG)
        mkdir -p $(dirname $target_path)
        jq -r ".cloudconfig.\"$kind\".content" $CONFIG > $target_path
      done

デプロイする

ここまで準備できたらDebian 12がデプロイできるはず。 デプロイする手順に特別なことはなく、デプロイするときのOS選択でCustom OSを選択しReleaseでDebian 12 (bookworm)を選択すればよい。

問題がおこらなければDeployedになるはず。

Tips: UEFI bootを使わずにLegacy bootを使う場合

上記手順ではUEFI bootを使ったセットアップ手順を紹介した。 ここではLegacy bootを使う場合の手順を記載する。といっても大きく手順が変わるわけではない。 まず、ディスクイメージを用意するときにgrub-pc-binパッケージをインストールする。 パッケージのインストールならcurtinでやればいいのでは?ッと思うかもしれないが、DEBIAN_FRONTEND=noninteractive apt-get install -y grub-pc-bin してもDEBIAN_FRONTEND=dialogが求められエラーになってしまいうまくインストールできなかったため、ここだけ手動でインストールすることで回避することにした*1。 grub-pc-binのインストールは、クラウドイメージをマウント後に以下のコマンドを実行する。

# ネットワーク接続に必要なマウントポイント
sudo mount -o bind /dev root/dev
sudo mount -o bind /run /root/run
sudo mount -o bind /proc /root/proc

sudo chroot root/ apt-get update
sudo chroot root/ apt-get install -y gurb-pc-bin

最後に /var/snap/maas/current/preseeds/curtin_userdata_custom からefibootmgrとgrub-efi-amd64のインストール 部分を削る。前述した内容であればcurthooks_commandsの部分を削除すればよい。

Tips: curtinが実行するコマンドに設定される環境変数

curtinが実行するコマンドには以下の環境変数が設定される。

  • WORKING_DIR : curtinコマンドが実行されたディレクトリ。curtinコマンドの設定ファイルなどが格納されている
  • TARGET_MOUNT_POINT : デプロイ先のストレージがマウントされたパス。curtin in-targetコマンドを使えば意識する必要ないが、そのコマンドを使う場合は参照することがある
  • `OUTPUT_NETWORK_CONFIG: デプロイ用のOSに設定されたnetplanのコンフィグファイルのパス。コンフィグファイルの内容が格納されているわけではないので注意
  • OUTPUT_FSTAB: デプロイするOS向けに出力されたfstabファイルのパス。fstabの内容が格納されているわけではないので注意
  • CONFIG: curtinに設定されたすべてのコンフィグが出力されたファイルのパス

Tips: curtinで指定するコマンドはアルファベット順に実行される

curtiの各ステージで実行するコマンドは *_commands で指定できる。 そこで指定するコマンドに名前をつけられるのだが、実行順序はこの名前のアルファベット順になる。

late_commands:
  c_command: ["~~~"]
  a_command: ["~~~"]
  0_command: ["~~~"]

上記のような設定であれば0_command -> a_command -> c_commandの順で実行される。
地味に罠なのだが、MAASによってデフォルトでbuiltinというコマンド名が登録されており、このコマンドより先に実行したい場合は、数字始まり or aで始まるコマンド名を指定する必要がある。

Tips: curtinのデバッグ

以下のgistが参考になる。なお、私は今回の手順を確立したあとに発見したのでもっと早く見つけたかった…つらい。

参考

*1:もしかしたら、grub-efi-amd64を削除してからgrub-pc-binをインストールすれば回避できたかもしれない