KVMのゲストマシン上でSSHのポート閉じてしまいシリアル接続もできないのでディスクイメージをホストにマウントしてどうにかする
どうも、まるさ@maruuusa83です.
KVMで複数の仮想マシンを立てて色々な実験環境を運用しているのですが,そのうちの一つでオペミスでSSHのポートを閉じてしまい,シリアル接続用の設定もしていなかったせいでコンソールに接続することが全くできなくなってしまいました.
試行錯誤しつつ解決したのでメモ.
状況と方針
ゲストOSの側は全てのポートが閉じてしまっているので,ネットワークからはなす術がありません.
また,シリアル通信でコンソールにログインを試みるも,事前の設定がなされていないためにこれも失敗.
というわけで,一旦ゲストOSを落としてイメージファイルをホストOSにマウントしてゴニョゴニョいじります.
最後にオマケで非常用にシリアルコンソールが使えるように設定する方法を書いておきます.
イメージファイルについて調べる
KVMで動作するゲストOSのディスクは,基本的にはqemu-imgで作られるraw形式かqcow2形式になっているはずです.
とりあえず,次のコマンドでディスクイメージの形式を調べます.
# qemu-img info disk.img image: disk.img file format: qcow2 virtual size: 300G (322122547200 bytes) disk size: 57G cluster_size: 65536 Format specific information: compat: 1.1 lazy refcounts: true
raw形式であれば kpartx -av disc.img
して mount /dev/mapper/loop0p1 /mnt
的なことをすれば簡単にマウントできますが,qcow2形式の場合には圧縮が施されているのでそいつを何とかしてあげる必要があります.
ぐう・・・
qemu-nbdを使えるようにする
qcow2形式のディスクイメージのマウントには, qemu-nbd
を使うとよいです.
これでraw形式の時のようにループバックマウントして中身を覗けるようになります.
これを利用するためまずは nbd
モジュールを読み込みます.
# modprobe nbd modprobe: FATAL: Module nbd not found.
やめてくれmodprobe その術はオレに効く
Linuxカーネルをビルドしてnbdを手に入れる
CentOS7ではnbdのビルドと組込みは行われないようなので,カーネルを落としてきて頑張って自分でビルドします.
とりあえずソースコードをゲットしましょう.
uname -r
とかで自分のカーネルのバージョンを調べて同じバージョンのソースコードをゲットしてください.
# uname -r # wget http://vault.centos.org/7.2.1511/updates/Source/SPackages/kernel-3.10.0-327.28.3.el7.src.rpm # rpm -ivh kernel-3.10.0-327.28.3.el7.src.rpm
次にビルドの準備をします.
頑張って依存性を解決しながら rpmbuild
を進めてください.
# mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} # echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros # cd ~/rpmbuild/SPECS # rpmbuild -bp --target=$(uname -m) kernel.spec # cd ~/rpmbuild/BUILD/kernel-3.10.0-327.28.3.el7/linux-3.10.0-327.28.3.el7.centos.x86_64/
make menuconfig
で Device Driver > Block devices
とたどって, Network block device support
に M
をセットしてください.
menuconfigができたら,makeしましょう.
# make prepare && make modules_prepare && make ... CC [M] drivers/block/nbd.o error: ‘REQ_TYPE_SPECIAL’ undeclared (first use in this function) sreq.cmd_type = REQ_TYPE_SPECIAL; ^
やめてくれ・・・
nbdはRedhatのサポート外なので,このバージョンではどうもうまくコンパイルできないらしい・・・
REQ_TYPE_SPECIAL
は REQ_TYPE_DRV_PRIV
に変更されているので, nbd.c
内の該当箇所を修正してもう一度ビルドします.
fsync_bdev(bdev); mutex_lock(&nbd->tx_lock); blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_DRV_PRIV; // これを修正した nbd_cmd(&sreq) = NBD_CMD_DISC;
改めてビルドを進める・・・
# make prepare && make modules_prepare && make # make M=drivers/block -j8
通った!のでmodを読み込んでいく.
# modinfo drivers/block/nbd.ko filename: /root/rpmbuild/BUILD/kernel-3.10.0-862.el7/linux-3.10.0-862.el7.centos.x86_64/drivers/block/nbd.ko license: GPL description: Network Block Device retpoline: Y rhelversion: 7.5 srcversion: A36E8E32685072269226933 depends: vermagic: 3.10.0 SMP mod_unload modversions parm: nbds_max:number of network block devices to initialize (default: 16) (int) parm: max_part:number of partitions per device (default: 0) (int) parm: debugflags:flags for controlling debug output (int) # cp drivers/block/nbd.ko /lib/modules/3.10.0-327.28.3.el7.x86_64/extra/ # depmod -a && modprobe nbd
modprobe
で invalid argument
的な事を言われてしまう場合はソースのバージョンとOSのカーネルのバージョンがちゃんとマッチしているか確認してください.
正しくnbdが読み込まれたか確認するために /dev
を覗いてみます.
# ls /dev |grep nbd nbd0 nbd1 nbd10 nbd11 nbd12 ...
よしよし
qcow2イメージをループバックマウントする
nbdが使えるようになったので, qemu-nbd
を使ってマッピング接続します.
# qemu-nbd -c /dev/nbd0 disk.img
とりあえず fdisk
して正しくパーティションが読めてるか確認してみます.
# fdisk -lu /dev/nbd0 WARNING: fdisk GPT support is currently new, and therefore in an experimental phase. Use at your own discretion. Disk /dev/nbd0: 322.1 GB, 322122547200 bytes, 629145600 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: gpt Disk identifier: 49524BB2-F36A-41E3-BB7D-9C5ED6ABA100 # Start End Size Type Name 1 2048 4095 1M BIOS boot 2 4096 629143551 300G Linux filesyste
きちんと認識できているようなので,ループバックマウントします.
パーティション分けがなされているので, kpartx
でバチッと分けてあげてからマウントします.
# kpartx -av /dev/nbd0 add map nbd0p1 (253:3): 0 2048 linear /dev/nbd0 2048 add map nbd0p2 (253:4): 0 629139456 linear /dev/nbd0 4096 # これが本体っぽい # mkdir /mnt/nbd0p2 # mount -o loop /dev/mapper/nbd0p2 /mnt/nbd0p2
ls
してみる
# ls /mnt/nbd0p2 bin dev home ... boot etc initrd.img ...
やったーファイルシステムが読めるようになったぞー!!!
chroot して設定を書き換えていく
方針としては,chroot
で強引にゲストOSのシェルを起動して nfw
で22番をこじ開ける感じです.
今回ホスト側がCentOS7でゲスト側がUbunt18だったので,さすがに無理かなーと思いつつ試しましたが,結論から言うとこれでうまくいきました.
chroot
コマンドでルートをすげ替えます.OSが違ったり /dev
の中身が無かったりするので色々と具合が悪いこともありますが,とにかく試します.
# chroot /mnt/nbd0p2 # ufw allow 22 Rule added Rule added (v6)
えっめっちゃあっさり通った・・・!
アンマウントして再起動
マウントの時と逆の手順を踏んでアンマウントしていきます.
# umount /mnt/nbd0p2 # kpartx -dv disk.img # qemu-nbd -d /dev/nbd0
あとは仮想環境を立ち上げてみてsshを繋ぐなりしてみて設定が正しく行われているか確認してください.
【おまけ】非常用にシリアルコンソールから接続できるように設定する
今回シリアルでつながってればこんなに大変なことにはならなかったに違いないので,シリアルコンソール接続ができるように設定します.
grubに起動オプションを設定
イメージファイルの中のgrubの設定を書き換えていきます.
/mnt/nbd0p2/etc/default/grub
に起動オプション console=tty0 console=ttyS0,115200n8r
を追加します.
# cd /mnt/nbd0p2/etc/default/ # vim grub ... GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200n8r" # ここに書く
mkconfigして接続テストしてみる
そして grub-mkconfig -o /boot/grub2/grub.cfg
します.
再起動して,接続テストをしてみてください.
今回はこのへんで.
つかれた ノ
まるさ