■自分の環境
・ホストサーバ:ubuntu 16.04
・libvertのバージョン:1.3.1
・OpenStack:mitaka
■必須環境
・libvertのバージョン:1.2.9以上
・OpenStack:mitaka以上であること
■対象とする読者
OpenStack環境はすでにできているが、仮想サーバをEFI起動させたいという方に向けて書いています。
自分はなかなかハマってしまったので、備忘として。
やることがわかっていれば、簡単なのでしょうが、仮想化の初心者なので。。。
大きく分けて、3つの作業を行います。
1.KVMで、EFI起動できるようにする。
2.Glanceへのイメージ登録時に、EFI起動の設定を加える。
3.起動ファイルの再作成(バグ?対応。本当はいらない作業)
■参考にしたURL
また、今回の調査にあたり、以下のサイトや記事を参考にさせていただきました。
みなさま、ありがとうございます。
・OpenStackドキュメント - Boot From UEFI image
・uefi_bootsupport_techtip_final.pdf
・OpenStackドキュメント - Images and instances
・QEMU の為の UEFI ファームウェアのビルド手順
・libvirt の UEFI 設定
・第441回 QEMU/KVMでUEFIファームウェアを使う
それでは、始めていきます。
(EFI起動は、OpenStackのMitakaからの対応らしいので、ご注意を)
##1.KVMで、EFI起動できるようにする。##
自分はOpenStackの仮想サーバを、KVMで実行しているのですが、
KVMは、デフォルトではEFI起動はせず、BIOSでの起動となってしまうようです。
Horizonで作成したインスタンスを起動しようとすると、
エラーメッセージが出てきて、なんだか切ない気持ちになります。
そこで、まずはKVMでもEFI起動できるようにしていきます。
その前にlibvertのバージョンを調べます。
・libvirtのバージョン確認
$ virsh version
コンパイル時に使用したライブラリ: libvirt 1.3.1
使用中のライブラリ: libvirt 1.3.1
使用中の API: QEMU 1.3.1
実行中のハイパーバイザー: QEMU 2.5.0
libvirtのバージョンが1.2.9以上であることを確認してください。
バージョンに問題がなければ、KVMでEFI起動できるようにするための「OVMF」をインストールします。
・OVMFをインストール
$ sudo apt install ovmf
・何かできている
以下のコマンドを打って、それぞれ2つのファイルができていることを確認します。
$ ls /usr/share/OVMF/
OVMF_CODE.fd
OVMF_VARS.fd
これで、KVM側の作業は終了です。
##2.Glanceへのイメージ登録時に、EFI起動の設定を加える。##
Glanceへのイメージの登録の際に、EFI起動するための指定が必要です。
Horizonでは、設定項目がなさそうなので、コマンドラインから、Glanceの登録を行います。
・glanceイメージを登録
(筆者はvdiファイルを取り込んだので、file、disk-formatなどは環境に合わせた値に変換してください。)
$ openstack image create "NAME" --file XXXXXXXXXX.vdi --disk-format vdi --container-format bare --property hw_firmware_type=uefi --public
「--property hw_firmware_type=uefi」がポイント!
このpropertyを指定しないと、OpenStack側は、EFI起動せず、BIOSで起動させようとしてしまうので、注意してください!
MySqlでglanceユーザでログインし、「image_properties」テーブルを参照してみてください。
先ほど登録したGlanceイメージのpropertyが、name:hw_firmware_type、 value:uefiで登録されていることを確認します。
$ sudo mysql glance
MariaDB [glance]> select * from image_properties;
+----+--------------------------------------+-------------- ---+-------+---------------------+---------------
| id | image_id | name | value | created_at | updated_at >| deleted_at | deleted |
+----+--------------------------------------+------------- ----+-------+---------------------+---------------
| 1 | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | hw_firmware_type | uefi | 2017-01-01 04:57:31 | 2017-01-01 04:57:31 | NULL | 0 |
+----+--------------------------------------+-------------- ---+-------+---------------------+---------------
これで、準備はOK。
その前に。。。
・driver.pyをちょっと見てみる
先ほど設定した「--property hw_firmware_type=uefi」はどのように使用されるのでしょうか。
そのヒントは、以下のpyファイルに書かれているようです。
$ view /usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py
(前略)
DEFAULT_UEFI_LOADER_PATH = { ←①
"x86_64": "/usr/share/OVMF/OVMF_CODE.fd",
"aarch64": "/usr/share/AAVMF/AAVMF_CODE.fd"
}
(中略)
if hw_firmware_type == fields.FirmwareType.UEFI: ←②
if self._has_uefi_support():
global uefi_logged
if not uefi_logged:
LOG.warn(_LW("uefi support is without some kind of "
"functional testing and therefore "
"considered experimental."))
uefi_logged = True
guest.os_loader = DEFAULT_UEFI_LOADER_PATH[ ←③
caps.host.cpu.arch]
guest.os_loader_type = "pflash"
else:
raise exception.UEFINotSupported()
guest.os_mach_type = self._get_machine_type(image_meta, caps)
(後略)
①の部分にて、「DEFAULT_UEFI_LOADER_PATH」の指定が、
OVMFをインストールされた際にできた「OVMF_CODE.fd」に指定されていることがわかります。
これが、EFI起動するためのローダーとなるのでしょう。
さらに、いつこのPATHを使うかというと、
②の「if hw_firmware_type == fields.FirmwareType.UEFI」ブロックの中。
hw_firmware_typeや、UEFIなどの記載があります。
はい、先ほど指定したpropertyの値ですね。
おそらく、fields.FirmwareType.UEFIは、固定文字でuefiとなっているのでしょう。
このif文に入った際に、③でguest.os_loader = DEFAULT_UEFI_LOADER_PATHとあります。
きっとこれで、EFI起動するためのお膳立てはできているはず!
##3.起動ファイルの再作成##
・まだダメだった
これで普通にインスタンス作成すれば、起動すると思いきや!!
ここで数時間試行錯誤。
で、ふと思い、KVM側の設定を確認してみる。
$ virsh list
Id |名前 |状態
----------------------------------------------------
20 |instance-00000001 |実行中
・設定を確認
以下のコマンドで、VMの起動設定のXMLファイルを、確認/編集することができます。
$ virsh edit <インスタンス名>
(前略)
<os>
<type arch='x86_64' machine='pc-i440fx-xenial'>hvm</type>
<loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
<nvram template='/usr/share/OVMF/OVMF_CODE.fd'>/var/lib/libvirt/qemu/nvram/インスタンス名_VARS.fd</nvram>
<boot dev='hd'/>
<smbios mode='sysinfo'/>
</os>
(後略)
あれれ? 参考にしたサイトと、表示が異なっている!!
「<nvram template='/usr/share/OVMF/OVMF_CODE.fd'>」となっている!?
「<nvram template='/usr/share/OVMF/OVMF_VARS.fd'>」になると思っていたのに!!
こちらのサイトでは、
OVMF_CODE.fdは、ファームウェアの指定で、
OVMF_VARS.fdは、nvramの指定、と説明されていました。
上記の設定は、nvramのテンプレートにOVMF_CODE.fdが設定されている。
うーん。もしかして設定が変なことになってしまっている???
ここは、OpenStack側が、自動で設定する項目のはずなのに。
・仕方ないので、起動ファイルを再作成
すでにOVMF_CODE.dfをテンプレートとして起動ファイルが作成されてしまっているため、
OVMF_VARS.dfをテンプレートとして作成するようにします。
まずは、すでに作成されているファイルがあると、再作成されないため、リネームする。
$ sudo mv /var/lib/libvirt/qemu/nvram/instance-00000001_VARS.fd /var/lib/libvirt/qemu/nvram/instance-00000001_VARS.fd_bk
以下のコマンドで、<os>部分のパラメータを書き換えます。
$ virsh edit <インスタンス名>
(前略)
<os>
<type arch='x86_64' machine='pc-i440fx-xenial'>hvm</type>
<loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
<nvram template='/usr/share/OVMF/OVMF_VARS.fd'></nvram>
<boot dev='hd'/>
<smbios mode='sysinfo'/>
</os>
(後略)
・再作成
$ virsh start <インスタンス名>
・設定を確認
$ virsh edit <インスタンス名>
(前略)
<os>
<type arch='x86_64' machine='pc-i440fx-xenial'>hvm</type>
<loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
<nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/qemu/nvram/インスタンス名_VARS.fd</nvram> ←値が変更されていることを確認
<boot dev='hd'/>
<smbios mode='sysinfo'/>
</os>
(後略)
・いけんじゃねーか
ということで、あとは、コマンドラインでも、Horizonからでも、普通にインスタンスを作成すれば、EFI起動がなされます。
本当は、XMLファイルを作成するスクリプトを編集すればスマートなのでしょうが、そこまでは追っていません。
また、今回はmitakaで試しましたが、最新版では解消されているかも??