Ubuntu Weekly Recipe

第611回 Packerでmultipass用の仮想マシンイメージを作る

この記事を読むのに必要な時間:およそ 6 分

第590回で紹介したマルチプラットフォームな仮想マシン管理ツールである「Multipass」は,原則としてUbuntuサーバーのイメージを起動するように作られています。しかしながら実は任意の仮想マシンイメージの指定も可能です。そこでPackerで仮想マシンイメージを作成し,Multipassで管理する方法を紹介しましょう。

MultipassとPacker

第590回「Windows/macOS/Linuxで使える仮想マシン管理ツール『multipass⁠⁠」で紹介したように,MultipassはWindowsやmacOS,Linuxでも使える仮想マシンを管理するツールです。DockerやLXDのようにコマンドラインから気軽に仮想マシンを起動・終了するような使い方を想定しています。

multipassは特に指定しなければサーバー版のUbuntuをベースイメージとして使います。もし自動的にカスタマイズしたいなら,cloud-initを使うか,インスタンス作成後にプロビジョニングツールを使うことを想定しています。しかしながらあらかじめ構築済みのイメージやUbuntu以外の仮想マシンを立ち上げたいこともあるはずです。

そこで今回は自分で仮想マシンイメージを作る方法とそれをmultipassで利用する方法を紹介します。Ubuntu版multipassの標準のバックエンドはQEMUなので,QEMUで任意のOSのインストーラーを使ってディスクイメージを作成し,それを利用しても良いのですが若干面倒です。よってマシンイメージの作成自動化ツールとして広く使われているPackerを使うことにしましょう。PackerであればWindowsのHyper-V用イメージにも対応しています。

PackerはUbuntuならパッケージ管理ツールからインストール可能です。しかしながら18.04だと1.0.4,現在開発中の20.04ですら1.3.4と古いバージョンしかインストールできません※1⁠。DebianでもFTBFSな状態なので誰かがメンテナンスを引き継がなければ将来的にパッケージそのものがなくなってしまう可能性があります※2⁠。

※1
snap版に至っては1.0.0のまま更新されていません。
※2
言い換えるとコントリビュートのチャンスです。

よって素直にPackerのダウンロードページからバイナリをインストールしましょう。PackerはGo言語で作られたバイナリなので,ホスト側に必要なのはモダンなlibcだけです。おそらくUbuntuであれば,サポートしているどのバージョン・アーキテクチャーでも特に問題はないでしょう。該当ページの「Linux」から,使っているマシンのCPUアーキテクチャーに合わせてアーカイブファイルをダウンロードしてください。今回はAMD64版を使うことにします。

$ wget https://releases.hashicorp.com/packer/1.5.4/packer_1.5.4_linux_amd64.zip
$ unzip packer_1.5.4_linux_amd64.zip
$ sudo cp packer /usr/local/bin/

バイナリひとつ配置すればいいので簡単ですね。また,Packer自身がQEMUを使うように設定するため,QEMUパッケージをインストールしておく必要があります。multipassパッケージ同梱のQEMUを使ってもいいのですが,いろいろ調整が必要なので,パッケージ版をインストールしておきましょう。

$ sudo apt install qemu-system-x86 qemu-utils

これでインストールは完了です※3⁠。

※3
ホストに余計なバイナリをインストールしたくないために,LXDの中にPackerをインストールするという考え方もあります。ただしLXDコンテナの中からKVMを使うのは少し手間がかかります。もしどうしてもコンテナに閉じ込めたいのなら,第609回「LXDからコンテナではなく仮想マシンを起動する」で紹介したようにNested KVMを設定した上で,最新のLXDで実装された仮想マシンかmultipassのインスタンスの中にPackerをインストールすると良いでしょう。

Packer用ファイルとcloud-initデータの作成

PackerはJSONファイルに基づいて,仮想マシンイメージを構築します。builderがISOファイルやルートファイルシステムのアーカイブをダウンロードした上で仮想マシンを起動し,provisionerがインストール後の諸々の設定を行います。builderがOSごとのインストール方法や作成するイメージ形式の違いを吸収し,パッケージのインストールや設定ファイルの作成はprovisionerが担うと思っておけば良いでしょう。正確にはbuilderがOSのインストールを行うわけではありません。しかしながら今回はcloud-initによって,builderによる仮想マシン起動の際にインストールも事実上「自動化」します。

ベースイメージはUbuntu Cloud Imagesのデータを使うことにします。これは各種クラウドサービスで使用するUbuntuのベースイメージを配布しているサイトです。リリースごとに最新のアップデートを適用したイメージが,ほぼデイリーでビルドされるので,ベースイメージとしてはもってこいなのです。

ちなみにこのイメージにはアカウントは設定されていません。ユーザーごとに異なる設定はクラウドサービスごとに合わせたcloud-initで設定する,というスタンスです。

Packerでイメージを構築する際,Packerのprovisionerが仮想マシンインスタンス内部にSSHログインできる必要があります※4⁠。つまりあらかじめアカウントが必要です。そこでQEMU用のbuilderからcloud-initの設定を行うことにします。これには第561回「ローカルインストール時もcloud-initを活用する」で紹介した知識が利用可能です。

※4
正確にはPackerとイメージの間の通信はcommunicatorが担っており,SSH以外のcommunicatorも存在します。しかしながらQEMUに限って言えば,SSHが必須と考えて良いでしょう。

cloud-initをサポートしたイメージは,どこかからcloud-initの設定ファイルを取得しなくてはなりません。一般的なクラウドサービスは,たとえばシリアルコンソール経由などサービスごとに取得方法を用意しており,ユーザーはそれを気にすることなくデータだけを渡せば良いようになっています。それに対してQEMUはもともとcloud-initには対応していないため,cloud-initのプログラム側で考慮する必要があります。それがNoCloudという仕組みです。

NoCloudでは次のいずれかの方法で,cloud-initの設定ファイルを取得可能です。

  • ボリュームラベルが「cidata」「CIDATA」な,vfatもしくはiso9660のストレージ
  • カーネルコマンドラインで指定されたパラメーター
  • SMBIOS上のシリアル番号に記載された文字列

後者のふたつに関しては,cloud-initデータが存在するファイルの位置を指定可能です。つまり任意のURLにcloud-initファイルを配置し,それをダウンロードできるのです。

Packerのbuilderはhttp_directoryというパラメーターを指定することで,インスタンス作成時にそのディレクトリを見せるHTTPサーバーを立ち上げます。よってここにcloud-initファイルを置くことで,仮想マシンイメージ構築時にcloud-initを実行できるようになります。

最後に注意が必要なのは,⁠multipass自身もインスタンス作成時にcloud-initを使用している」点です。つまり作成した仮想マシンイメージとmultipassのcloud-init設定がバッティングしてしまうと,その仮想マシンイメージをmultipassで立ち上げられません。そこでprovisionerで,いくつかの調整を行います※5⁠。

※5
実はcloud-initの中で全部やってしまう方法もなくはないのですが,そうすると最終的に「Packerいらなくないか?」って話になって本記事の前提が破綻するのです。Packerのほうが手順が簡単になりますし,cloud-initがない環境にも使えて汎用性があるということで,どうかここはひとつ納得してください。

まとめるとmultipass用のイメージをPackerで構築するために,次のファイルを準備する必要があります。

  • cloud-init用の設定ファイルmeta-datauser-data
  • Packer用の設定ファイルubuntu.json

それでは順番に作っていきましょう。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。