Vagrant + CentOS7+ kdump でVMのメモリサイズが小さいとkdumpの起動に失敗する

別にVagrantに限った話ではないけど。
Vagrantでprovisionする時にkdumpを起動しているのだが、VMのメモリサイズが1GBになっているようなVMだとそれが失敗していた。
原因と対策について整理しておく。

発生した問題

例えば、以下のようなVagrantfileでVMを起動するとする。

[ruby]
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
config.vm.box = "centos/7"

config.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
end

config.vm.provision "shell", inline: <<-SHELL
yum install -y kexec-tools
systemctl start kdump.service
SHELL
end
[/ruby]

手元に作る環境なので、productionとは異なりメモリサイズを小さくしておく、ということは十分に有り得る。
この時、vagrant upすると以下のようになりprovisioningに失敗する。

[text]
==> default: Running provisioner: shell…
default: Running: inline script
==> default: Loaded plugins: fastestmirror
==> default: Loading mirror speeds from cached hostfile
==> default: * base: ftp.iij.ad.jp
==> default: * extras: ftp.iij.ad.jp
==> default: * updates: ftp.iij.ad.jp
==> default: Package kexec-tools-2.0.7-38.el7_2.1.x86_64 already installed and latest version
==> default: Nothing to do
==> default: Job for kdump.service failed because the control process exited with error code. See "systemctl status kdump.service" and "journalctl -xe" for details.
The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.
[/text]

原因

このログからではよくわからないので、VMにログインして状況を確認する。

[text]
takaishiryou-no-iMac $ vagrant ssh
[vagrant@localhost ~]$ sudo systemctl status kdump.service
● kdump.service – Crash recovery kernel arming
Loaded: loaded (/usr/lib/systemd/system/kdump.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since 水 2016-08-03 14:01:48 UTC; 2min 55s ago
Process: 1597 ExecStart=/usr/bin/kdumpctl start (code=exited, status=1/FAILURE)
Main PID: 1597 (code=exited, status=1/FAILURE)

8月 03 14:01:48 localhost.localdomain systemd[1]: Starting Crash recovery kernel arming…
8月 03 14:01:48 localhost.localdomain kdumpctl[1597]: No memory reserved for crash kernel.
8月 03 14:01:48 localhost.localdomain kdumpctl[1597]: Starting kdump: [FAILED]
8月 03 14:01:48 localhost.localdomain systemd[1]: kdump.service: main process exited, code=exited, status=1/FAILURE
8月 03 14:01:48 localhost.localdomain systemd[1]: Failed to start Crash recovery kernel arming.
8月 03 14:01:48 localhost.localdomain systemd[1]: Unit kdump.service entered failed state.
8月 03 14:01:48 localhost.localdomain systemd[1]: kdump.service failed.
[/text]

起動に失敗したkdump.serviceのstatusを確認すると、「No memory reserved for crash kernel」と表示されている。
これは、メモリをkdump用に割り当てたいが、VMのメモリサイズが不足していて割り当てられないというエラーのようである。

このページの手順2.1によると、割り当てるメモリの量は/etc/default/grubを見れば分かる。実際に見てみるとcrashkernel=autoとなっている。autoの場合は予約するメモリサイズが自動的に設定される。どういう値になるかはこのページに書かれており、また、自動設定に必要な最小メモリサイズの情報がこのページに書かれている。後者を見ると、x86_64の場合は2GB必要であるということが分かる。つまり、上記Vagrantfileでは1GBしかメモリを用意していなかったためkdump用にメモリを確保しておらず、kdumpの起動に失敗したのである。

解決方法

解決方法として、以下が挙げられる。

  1. VMのメモリサイズを2GB以上にする
  2. crashkernelの値を変更し、固定値にする

てっとり早いのはメモリサイズ変更だが、kdumpのためだけに2倍のメモリを使うというのはなんだかしゃくである。なので、crashkernelの値を変更して、固定値にする方法を採用する。

手動で変更する場合はここの手順通りに作業を進め、crashkernelの値を128Mにして再起動すればよい。しかし、Vagrantの場合再起動した後にkdumpを起動する必要があるため、ややこしい。

そこで、aidanns/vagrant-reloadを使う。これはprovisioningの途中でVMを再起動して、その後のprovisioningをやってくれるというvagrantのプラグイン。Vagrantfileを以下のように修正してやる、。

[ruby]
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.require_plugin "vagrant-reload"

Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
end

config.vm.provision "shell", inline: <<-SHELL
sed -i "s/crashkernel=auto/crashkernel=128M/g" /etc/default/grub
grub2-mkconfig -o /boot/grub2/grub.cfg
SHELL
config.vm.provision :reload

config.vm.provision "shell", inline: <<-SHELL
yum install -y kexec-tools
systemctl start kdump.service
SHELL
end

[/ruby]

vagrant upするとちゃんとVMが再起動し、sshで再度接続して次のprovisioningに進んでいることがわかる。

[text]
==> default: Running provisioner: shell…
default: Running: inline script
==> default: Generating grub configuration file …
==> default: Found linux image: /boot/vmlinuz-3.10.0-327.22.2.el7.x86_64
==> default: Found initrd image: /boot/initramfs-3.10.0-327.22.2.el7.x86_64.img
==> default: Found linux image: /boot/vmlinuz-0-rescue-cb81bd8ac73c409cb970c217f287cf9f
==> default: Found initrd image: /boot/initramfs-0-rescue-cb81bd8ac73c409cb970c217f287cf9f.img
==> default: done
==> default: Running provisioner: reload…
==> default: Attempting graceful shutdown of VM…
==> default: Checking if box ‘centos/7’ is up to date…
==> default: Clearing any previously set forwarded ports…
==> default: Clearing any previously set network interfaces…
==> default: Preparing network interfaces based on configuration…
default: Adapter 1: nat
==> default: Forwarding ports…
default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Running ‘pre-boot’ VM customizations…
==> default: Booting VM…
==> default: Waiting for machine to boot. This may take a few minutes…
default: SSH address: 127.0.0.1:2200
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Remote connection disconnect. Retrying…
==> default: Machine booted and ready!
[default] GuestAdditions 5.0.26 running — OK.
==> default: Checking for guest additions in VM…
==> default: Rsyncing folder: /Users/r_takaishi/src/github.com/takaishi/dev-vm/centos7/ => /home/vagrant/sync
==> default: Machine already provisioned. Run vagrant provision or use the --provision
==> default: flag to force provisioning. Provisioners marked to run always will still run.
==> default: Running provisioner: shell…
default: Running: inline script
==> default: Loaded plugins: fastestmirror
==> default: Loading mirror speeds from cached hostfile
==> default: * base: ftp.riken.jp
==> default: * extras: ftp.riken.jp
==> default: * updates: ftp.riken.jp
==> default: Package kexec-tools-2.0.7-38.el7_2.1.x86_64 already installed and latest version
==> default: Nothing to do
[/text]

provisioningする度にVMを再起動するので時間が伸びるのがデメリット。