Developer's Blog

Azure 仮想マシンの OS ディスクを復旧する



ウェブ共同開発部の野田です。AWS や Azure などのクラウド環境を活用した、ウェブサービスの開発・構築をおこなっています。

先日、Azure で払い出した Linux 仮想マシンに、構成管理ツールの Ansible を使ってサーバー構築作業をしました。
その時、Playbook の記述を誤ったまま実行してしまい、sudo コマンド用の設定ファイル /etc/sudoers を誤った内容で上書きしてしまい、とても困ったことになりました。
結果的には復旧することができたのですが、初めての作業でいくつかハマりそうになったため、復旧作業の一部を公開します。



/etc/sudoers

通常、/etc/sudoers ファイルの編集には特権が必要ですが、/etc/sudoers に構文の誤りがあると、syntax error が発生し、sudo の実行ができなくなってしまいます。
そのため、特権が得られず、sudo を使った /etc/sudoers ファイルの編集ができなくなってしまいます。

このような事故を防ぐため、/etc/sudoers ファイルを直接編集することは推奨されておらず、代わりに visudo 等のコマンドを使って編集すべきとされています。
visudo コマンドでは、変更の保存前に構文チェックがおこなわれ、構文誤りがあると保存されないため安全です。

しかし今回は Ansible で直接上書きしてしまい、また root ユーザーのパスワードを設定していなかったため、特権ユーザーとしてログインすることもできず、簡単に復旧する術がありませんでした。

復旧手段

システムを復旧させる手段として、いくつかの方法が考えられました。

  • 別の復旧用仮想マシンに、設定を誤った OS ディスクを接続して修正
  • Azure Recovery Services のバックアップから復旧
    • 日次で仮想マシンのバックアップを取得していたため、バックアップイメージから新しく仮想マシンを作成
  • 再構築
    • 仮想マシンを含む Azure 上の設定は Azure Resource Manager Template に記述し、OS 内の設定は Ansible で記述していたため、再構築が容易な状況
    • データの永続化は SQL Database や Azure ストレージアカウントでおこなっていたため、仮想マシンのボリューム内にサルベージの必要なデータがない

いずれの方法でも良かったのですが、まずは OS ディスクを別のマシンに接続する方法で復旧を試み、それがダメなら他の方法で復旧してみようと考えました。

環境は以下の通りです。

  • デプロイモデル: Azure Resource Manager
  • OS ディスク: 管理ディスク
  • OS: Red Hat Enterprise Linux 7.4

復旧作業

Azure Portal で OS ディスクを復旧 VM に接続して Linux VM のトラブルシューティングを行う の手順を参考に、以下の通り復旧作業を進めました。

仮想マシンの削除

いきなり仮想マシンを削除するのは少し怖いですが、Azure では仮想マシンと OS ディスクは異なるリソースとして管理されており、仮想マシンを削除しても、OS ディスクが削除されません。
データディスクは仮想マシンの実行中でも接続・切断ができますが、OS ディスクは仮想マシンを削除しない限り、切断することができないため、仮想マシンを削除します。

AWS の場合は、仮想マシンを停止していれば OS 用の EBS ボリュームも切断することができるため、このあたりは少し異なるようですね。

復旧用仮想マシンに復旧対象の OS ディスクを接続

復旧用仮想マシンに、復旧対象の OS ディスクをデータディスクとして接続します。

復旧用仮想マシンでマウントして修正

復旧対象の OS ディスクが接続されることを確認します。
ここでは、/dev/sdc として認識されたようです。

$ dmesg | tail -n 8
[34275.660126] scsi 5:0:0:0: Direct-Access     Msft     Virtual Disk     1.0  PQ: 0 ANSI: 4
[34275.681225] sd 5:0:0:0: Attached scsi generic sg2 type 0
[34275.702549] sd 5:0:0:0: [sdc] 67108864 512-byte logical blocks: (34.3 GB/32.0 GiB)
[34275.721120] sd 5:0:0:0: [sdc] Write Protect is off
[34275.723141] sd 5:0:0:0: [sdc] Mode Sense: 0f 00 10 00
[34275.725153] sd 5:0:0:0: [sdc] Write cache: enabled, read cache: enabled, supports DPO and FUA
[34275.852532]  sdc: sdc1 sdc2
[34275.869381] sd 5:0:0:0: [sdc] Attached SCSI disk
$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
fd0      2:0    1    4K  0 disk
sda      8:0    0   32G  0 disk
├─sda1   8:1    0  500M  0 part /boot
└─sda2   8:2    0 31.5G  0 part /
sdb      8:16   0   40G  0 disk
└─sdb1   8:17   0   40G  0 part /mnt/resource
sdc      8:32   0   32G  0 disk
├─sdc1   8:33   0  500M  0 part
└─sdc2   8:34   0 31.5G  0 part

/mnt/ 以下にマウント用のディレクトリを作成します。

# mkdir /mnt/rescue

/dev/sdc2 を /mnt/rescue にマウントしようとしたところで警告メッセージが出力され、マウントできませんでした。

# mount -t xfs /dev/sdc2 /mnt/rescue
mount: wrong fs type, bad option, bad superblock on /dev/sdc2,
       missing codepage or helper program, or other error

       In some cases useful info is found in syslog - try
       dmesg | tail or so.

dmesg でログを確認すると、パーティションの UUID が重複しているようです。

$ dmesg | tail -n 1
[34664.742154] XFS (sdc2): Filesystem has duplicate UUID ef39b601-3484-4f7c-81f0-3cb8b79eeda1 - can't mount

確認してみると、復旧用仮想マシンのルートパーティション (/dev/sda2) と、復旧対象 OS ディスクのルートパーティション (/dev/sdc2) が同じ UUID になっていました。
復旧用仮想マシンと復旧対象仮想マシンを、同じイメージから作成したためと思われます。

$ blkid /dev/sda2
/dev/sda2: UUID="ef39b601-3484-4f7c-81f0-3cb8b79eeda1" TYPE="xfs"
$ blkid /dev/sdc2
/dev/sdc2: UUID="ef39b601-3484-4f7c-81f0-3cb8b79eeda1" TYPE="xfs"

マウントオプションに nouuid を指定してマウントすることで、警告を回避することができました。

# mount -t xfs -o nouuid /dev/sdc2 /mnt/rescue
$ dmesg | tail -n 2
[34957.619555] XFS (sdc2): Mounting V5 Filesystem
[34965.941756] XFS (sdc2): Ending clean mount

無事にマウントすることができたため、/mnt/rescue/etc/sudoers を修正します。
また、修正後には念のために visudo コマンドで構文が正しい事を確認しておきます。

# visudo -c -f /mnt/rescue/etc/sudoers
/mnt/rescue/etc/sudoers: 正しく構文解析されました

修正が完了したので、復旧対象 OS ディスクのマウントを解除し、一時的に作成したマウント用ディレクトリを削除しておきます。

# umount /mnt/rescue
# rmdir /mnt/rescue

復旧用仮想マシンから復旧対象 OS ディスクを切断

修正の完了したディスクを仮想マシンから切断します。データディスクの切断は仮想マシンがオンラインの状態でも実行できます。

仮想マシンを再作成

修正の完了したディスクから、仮想マシンを再作成します。
Azure Portal では、ディスクのブレードから VM (仮想マシン) の作成を実行します。

再作成した Virtual Machine を修正

仮想マシンを再作成する際、元の仮想マシンと同じ設定を入力して起動しましたが、ネットワークインタフェースだけは自動生成されたものになっていました。
そのままでも特に問題ありませんでしたが、元の仮想マシンに接続されていたネットワークインタフェースに付け替えてみることにしました。

ネットワークインタフェースを付け替える際は、追加、削除の順でおこなう必要があるようです。
複数のネットワークインタフェースを接続することになるため、一旦仮想マシンを停止して作業をおこないます。
元のネットワークインタフェースを接続し、自動生成されたネットワークインタフェースを切断した上で、不要になったネットワークインタフェースを削除しておきます。

修正が完了した仮想マシンを起動して接続したところ、無事復旧できていることが確認できました。

今後のために

今回の失敗は Ansible で /etc/sudoers ファイルを誤った形式で上書きしてしまったために発生しました。
Ansible でこれを防ぐ方法を探してみると、以下のような方法が見つかりました。

  1. Copy や Template 等のモジュールを使って一旦 /etc/sudoers.tmp のような一時ファイルを作成
  2. Shell モジュールを使って # visudo -c -f /etc/sudoers.tmp のように構文をチェック
  3. Copy モジュールを使って /etc/sudoers.tmp を /etc/sudoers にコピーして上書き

これで万全ではないかもしれませんが、今回のような事故は防げそうです。
今回の経験で、ディスク異常時の復旧方法もわかったので、安心 (?) して環境を破壊していくことができそうです!


フェンリルのオフィシャル Twitter アカウントでは、フェンリルのメンバーが開催する勉強会や、イベント情報などをつぶやいています。よろしければ参加してみてください。


フェンリル採用チームの Twitter アカウントです。AWS や Azure を活用し、クラウドに最適化したシステムを組んでみたい方のご連絡をお待ちしています。


Copyright © 2019 Fenrir Inc. All rights reserved.