ディスクイメージをネットワークブートする

OSのデバッグごときでUSBメモリを挿したり抜いたりしたくない!という人のために。

 

これを使いましょう。

サンワサプライ USB3.0切替器(2回路) SW-US32

https://www.amazon.co.jp/dp/B00A2KXSRK/ref=cm_sw_r_tw_dp_x_wgAtyb1GSAJ1C

(wordpressってplugin入れないとamazonのリンク展開できないのね)

 

もちろん冗談なのですが、それを抜きにして、これは大変便利です。ポチッとボタンを押すだけで、USBメモリの接続先をビルド環境とテスト環境で切り替えられるので。デバッグがめっちゃ捗ってストレスフリーです。
まあでも人間、このボタンを押すのでさえだるくなるんですよ。ボタンを押し忘れて、HDDから起動しちゃう事もありますし。

 

というわけで、(たぶん)最強のブート環境である、ネットワークブートを作ります。

今回解説する方法は、ディスクイメージをネットワークからブートさせてしまうので、自分で書いてるToy OSのデバッグに限らず、linuxがインストールされたHDDのダンプファイルだろうと、OSのインストールディスクだろうと、何でもネットワーク越しに起動できます。(これは自作OS Advent Calendar 2016の記事ですが、OSのデバッグやる人でなくてももしかしたら役立つ・・・かもしれない)

ちなみにlinuxをネットワーク経由で起動するのなら、もう少しだけシンプルにできます。まあその話は今回はしませんが。

 

※注意

最初に軽く書きましたが、今回想定しているのは、しがない個人がより手軽にOSのデバッグをするためにネットワークブートする、という状況です。何十台とあるマシンに一気にプロビジョニング当てる場合は、素直にPXEサーバーを立てて、DHCPからPXEサーバーを教えてあげれば良いと思います。まあたぶんそういう事をしたい人はこのブログ見てないよね。

作業環境はUbuntu 14.04を想定しています。他の環境の場合は適宜読み替えてもらえれば。

あと、UEFIについては試していません。テスト環境はLegacy BIOSから立ち上げるものとしてください。

 

大雑把な解説

iPXEmemdiskを使います。

iPXEは拡張版PXE、という感じのファームウェアで、PXEの機能相当の提供に加え、HTTPや無線LANなどもサポートしています。(詳しくは後述)

memdiskは、ディスクイメージを起動してくれるブータブルバイナリで、iPXEから直接ディスクイメージを起動する事ができないため使用しています。

システム構成はこんな感じです。

netboot

(クリックして拡大)

今回のポイントは、iPXEを使うお陰で面倒な環境構築(物理)をする必要がない、という所です。

PXEを使う場合は、PXEサーバーを立ててDHCPサーバーからPXEサーバーを教えてあげなければならない(参考)ので、自前のDHCPサーバーを用意してあげる必要があり、あまりお手軽ではありません。iPXE であれば、ビルドマシン上でHTTPサーバーを走らせ、イメージを配布するだけで手軽に起動できるようになるため、便利です。ただ、その代わりiPXEイメージの方にビルド環境のIPアドレスを書き込むため、ビルド環境のIPが変わるたびにiPXEイメージの焼き直しが必要になります。まあIPが変わるのなんてPCを再起動したときくらいなので、デバッグを始める前にメディアに焼けば良いわけですし、それすら面倒なら適当なファイルサーバーを用意してあげて、そこにディスクイメージをアップロードする形にすれば、iPXEイメージを焼き直す必要はなくなります。あとはビルド環境を固定IPにしてしまう、なんてのもアリですね。

もう一つiPXEの良い点は、イメージの配信をHTTPサーバーでできる所です。PXEだとTFTPだけど、HTTPサーバーの方が楽。もちろん、プロトコルとしてはTFTPの方が軽量なので、TFTPサーバーを使う方法についてもあとで軽く触れておきます。

 

iPXEを使ってみる

まずは手軽にiPXEを使って起動してみましょう。

最初にビルド環境から設定します。

ビルド環境で用意すべきものは、適当なHTTPサーバー、OSがインストールされているディスクイメージ、そしてmemdiskです。

memdiskはgzip圧縮されたディスクイメージを起動する事ができるので、ディスクイメージは圧縮しておきましょう。

gzip disk

これでdisk.gzというファイルができます。

 

HTTPサーバーはApacheやnginxを使っても良いのですが、以下のようにpythonで起動してしまうのが一番楽だと思います。

$ python -m SimpleHTTPServer 8080

ぶっちゃけ、HTTPサーバーが起動できればなんでもいいので、お好きなのをどうぞ。

ワンライナーWebサーバを集めてみた by @suda_hiroshi on @Qiita

今回は8080番ポートで立ち上げてますが、それもお好みで大丈夫です。ポート変える場合は、以後の内容を適宜読み替えてください。

立ち上げたHTTPサーバーのルートディレクトリに、作成したディスクイメージとmemdiskを起きます。(memdiskはここからsyslinuxをダウンロードし、展開してあげるとmemdiskというファイルがあるはずなので、それを使ってください)

 

HTTPサーバーで開けたポートが外部から見えるよう、ファイアーウォールを設定します。

# ufw allow 8080

ネットワーク内の他のマシンから、http://<ビルド環境のIPアドレス>:8080/memdiskとhttp://<ビルド環境のIPアドレス>:8080/disk.gzにアクセスできればOKです。

 

次はiPXEの起動メディアを準備します。

まずは手軽にやるために、ここからiPXEイメージをダウンロードしてきます。iPXE起動用のメディアとしてUSBメモリを使う場合はipxe.usbを、CDを使う場合はipxe.isoを使いましょう。

ipxe.usbはディスクイメージなので、ddコマンドで書き込んでください。ISOファイルは煮るなり焼くなりお好きにどうぞ

# dd if=ipxe.usb of=/dev/sdx(対象のデバイス)

テスト環境はとりあえず有線LANを繋いでおきます。無線LANの話はまたあとで。

メディアが焼けたら、そこからブートします。

 

iPXEが起動し始めたら、Ctrl+Bを連打してコンソールに入りましょう。Ctrl+Bを受け付けるタイミングが一瞬あった後、dhcpの初期化を行い、そしてまた一瞬Ctrl+Bを受け付けるタイミングがあるので、そのどちらかでコンソールに飛べればOKです。

p_20161212_065008

(光沢液晶に顔が映らないようにするの、大変)

上のようにiPXEのコンソールが出たら、以下のコマンドを打ち込んで行きます。

iPXE> dhcp

iPXE> kernel http://<ビルド環境のIPアドレス>:8080/memdisk

iPXE> initrd http://<ビルド環境のIPアドレス>:8080/disk.gz

iPXE> boot

ディスクイメージがきちんと構築されていれば、これで起動するはずです。disk.gzのサイズが大きい場合、ダウンロードに少し時間が掛かるかもしれません。

今回テストしたディスクイメージは、grub2からmemtest86+や自作のOSカーネルを起動する、というものでしたが、問題なく起動できました。

 

iPXEイメージのconfigure

起動のたびにキーボードからコマンドを打ち込むのはダルいので、上述のコマンドをスクリプト化して自動的に読み込ませるiPXEイメージを作ります。

今度はiPXEのソースコードをgitからダウンロードします。依存ライブラリがあるので、インストールしておきます。

git clone git://git.ipxe.org/ipxe.git

$ aptitude install build-essential binutils-dev zlib1g-dev libiberty-dev

 

次に以下のようなconfigファイル(load.cfg)を作ります。

#!ipxe

dhcp

kernel http://<ビルドマシンのIPアドレス>:8080/memdisk

initrd http://<ビルドマシンのIPアドレス>:8080/disk.gz

boot

 

テスト環境が無線LANの場合は、以下を2行目に記述しましょう(未検証です)

set net0/ssid WIFISSID
set net0/key WIFIKEY

無線LANはデバドラの都合で動かないケースもあり得るので、テスト環境は有線LANを使う事をオススメします。(ビルド環境は無線か有線かは関係なし)

configファイルが書けたら、iPXEをビルドします。

 $ cd ipxe/src

$ make bin-x86_64-pcbios/ipxe.usb EMBED=../../load.cfg

ISOファイルを作る場合はipxe.usbをipxe.isoに変えてください。メディアに焼く部分は先程の通り。

 

最後に

今回、iPXEとHTTPサーバーを使ってネットブート環境を構築しましたが、先程も書いたとおり、イメージ配信サーバーのIPアドレスが変わるたびにiPXEイメージの再構築が必要になります。OSのデバッグをしている上では、デバッグを始めようと思ったときに毎回イメージ作成作業をすれば良い(スクリプトで自動化すれば、コマンド一つでメディアまで焼けるので)のですが、もしそれすらも面倒になった場合は、サーバー(ローカル、グローバル問わず)を使うか、ビルドマシンのIPを固定するかして、IPアドレスが変わらないようにしてあげれば良いと思います。

僕はデバッグを始めようと思ったときに一回USBメモリに焼く作業くらいは許容範囲かなー、って思ってます。今のところは。たぶんUSBメモリを焼くよりも、テスト環境の起動のために電源ボタンないしリセットボタンを押す事の方が苦になると思うので、先にそっちをなんとかしなきゃいけなさそうです。WoLとか使えばいけそうですね。make叩いたら一発で隣にあるマシンが勝手に起動して、OSの起動までできるようになれば、デバッグがもの凄く捗りそうですよね。

 

おまけ(TFTPサーバーを立てる)

HTTPサーバーは環境構築が楽なのですが、重いです。(気になる程ではないのだけども)

というわけで、TFTPサーバーをビルド環境に立ててみましょう。PyPXEが良さげなので、今回はこれを使いました。

 git clone https://github.com/psychomario/PyPXE

PyPXE/netboot/がルートディレクトリとなります。memdiskはすでにあるので、ここにディスクイメージをおいてあげればよろし。

TFTPはUDPの69番ポートを使用するので、ファイヤーウォールを開けておきます。起動は以下のコマンドで。

# python -m pypxe.server

 

iPXEのconfigは以下の通りです。

#!ipxe

set next-server <ビルド環境のIPアドレス>

kernel memdisk

initrd disk.gz

dhcp

autoboot

iPXEメディアを焼いて、起動しましょう。

 

おまけ(grubを使っている場合)

今回はmemdiskを挟んでディスクイメージを丸々起動させましたが、ぶっちゃけ、PXEブートできるカーネルバイナリを作れるなら、直接iPXEから起動しちゃえば良いと思います。また、grub2から起動している場合はgrub2をPXEブートできるので、それを作ってあげるのが良いかと。この方法はたぶんTFTPプロトコルでしかできないと思います。調べた限りでは。

これだとカーネルバイナリのみをダウンロードしてくるので、ディスクイメージまるごとよりかは軽くなります。まあディスクイメージは圧縮してるので、たぶんそんなに変わらないけども。

 

まずビルド環境で以下のコマンドを叩きます。

$ grub-mknetdir -d /usr/lib/grub/i386-pc/ –net-directory=(TFTPサーバーのルートディレクトリ)

ルートディレクトリ以下にboot/grub/i386-pc/core.0というファイルができるので、iPXEの設定ファイルに以下のように記述します。

#!ipxe

dhcp

set filename /boot/grub/i386-pc/core.0

set next-server <ビルド環境のIPアドレス>

dhcp

autoboot

/boot/grub/grub.cfgの先頭に以下を追記して、後は普通のgrubのconfigを書きましょう。

set root=(pxe)

あとはイメージをビルドして起動するだけですね。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中