銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

AzureのLinux仮想マシンで、起動すると3%くらいの確率で発生する事象を調査するために無限再起動スクリプトを使った話

この記事はAzure Advent Calendarと一人Advent Calendar1日目のエントリです。

qiita.com

adventar.org

1日目ということで軽いものからはじめます。とある事象を調査していたのですが、その事象というのがAzure上のLinux仮想マシンを再起動(仮想マシンの再起動だけではなく、システムの再起動 systemctl rebootでも発生)すると数%程度の確率で発生するというものでした。今日はこの事象そのもよりも、この事象を調べた方法について紹介します。

ようはひたすら再起動して、再現するかどうかなどを調べればいいのですが、数%なので手動ではつらいお仕事です。Azureからの再起動を自動化してもよかったのですが、システムの再起動で再現するのでLinuxシステム側で完結するようにしました。なお、RHEL7で動作確認しています。

以下のようなスクリプトを/root/poll_reboot.shに保存します。ファイル名はなんでもよいです。また、# ここから必要に応じてログ出力というところから# ログ出力ここまでというところまでの間に調査に必要なコマンドの実行とログの出力をしておきます。今回なんでこんなコマンドを実行しているかは最後に説明します。

#!/bin/bash

if [ -f "/var/log/num" ];then
    global_num=`cat /var/log/num`
else
    global_num=0
fi

function handler()
{
    sleep 80
    num=`expr ${global_num} + 1`
    echo -e "${num}:\t"`date -R` >> /var/log/reboot.info
    echo -e "${num}:\t"`date -R` >> /var/log/waagent.log
    # ここから必要に応じてログ出力
    echo -e "${num}:\t"`date -R` >> /var/log/disk.info
    ls -la /dev/disk/azure/scsi1/* >> /var/log/disk.info
    # ログ出力ここまで
    echo ${num} > /var/log/num
}
function is_not_run()
{
    if [ -f "/root/stop" ];then
        exit 253
    fi
    if [ ${global_num} == "100" ];then
        exit 252
    fi
}

function main()
{
    is_not_run
    handler
    reboot
}

main

次に以下の行を/etc/rc.d/rc.localに追加します。

bash /root/set_reboot.sh

最後に次のコマンドを実行します。

# chmod +x /etc/rc.d/rc.local
# systemctl enable rc-local

あとはシステムの再起動をすると、100回まで再起動を繰り返します。とめたい場合はtouch /root/stopなどとして/root/stopにファイルを作れば止まります。また再起動した回数は/var/log/numに保存されているので、100回に到達した後もう一度やりなおしたい場合は/var/log/numを削除しておきます。

さて、こんな検証をした背景ですが、実行しているコマンドをみてみましょう。

# ls -la /dev/disk/azure/scsi1/* 
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun0 -> ../../../sdc
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun1 -> ../../../sdf
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun2 -> ../../../sde
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun3 -> ../../../sdi
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun4 -> ../../../sdh
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun5 -> ../../../sdj
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun6 -> ../../../sdd
lrwxrwxrwx. 1 root root 12 Nov 24 22:38 /dev/disk/azure/scsi1/lun7 -> ../../../sdg

この仮想マシンにはこのように8つディスクが接続されています。

f:id:tanaka733:20181124234828p:plain

これらのディスクがマウントされるパスなのですが、必ずしもLUN0,1,2...のものから順に/dev/sdc , sdd, sde...と順になるわけではありません。現に上の実行例ではLUN1がsdfになっています。また実行するたびにこの対応関係が維持される保証ありません。LUN0にマウントしているディスクが今はsdcですが、次に再起動したらsddになっている可能性もあります。ただ多くのケースで維持されることがほとんであるため、どちらかというとAzure上のLinux(すくなくともRHEL)仮想マシンではじめてこの現象に遭遇する、というケースがありました。というわけで、じゃあどのくらいの頻度で発生するのだろうと試したのがこのスクリプトで、仮想マシンサイズなどにも依存するとは思いますが、少なくとも以前検証したときは100回の試行で4回ほど実行順が他の96回とは異なるケースがあったので、無視できない割合であることがわかりました。

ただ、今回このブログのために改めて検証したら100回の試行すべてで同じ順番だったため、もしかすると何かしら改善があったのかもしれません。ただ、あくまで保証はされないのでご注意ください。

また、じゃあLUNの数値から該当ディスクのマウントパスを見つける方法ですが、上のコマンドのように dev/disk/azure/scsi1/lun*となります。これはAzure Linux Agentが設定するudevルールにより生成されるシンボリックリンクで以下のドキュメントに記載があります。

docs.microsoft.com

ドキュメントにもあるtreeコマンドを実行するとまとめて確認できます。

# tree /dev/disk/azure
/dev/disk/azure
├── resource -> ../../sdb
├── resource-part1 -> ../../sdb1
├── root -> ../../sda
├── root-part1 -> ../../sda1
├── root-part2 -> ../../sda2
└── scsi1
    ├── lun0 -> ../../../sdc
    ├── lun1 -> ../../../sdf
    ├── lun2 -> ../../../sde
    ├── lun3 -> ../../../sdi
    ├── lun4 -> ../../../sdh
    ├── lun5 -> ../../../sdj
    ├── lun6 -> ../../../sdd
    └── lun7 -> ../../../sdg

1 directory, 13 files

また、/etc/fstabなどファイルシステムを識別したい場合はファイルシステムUUIDを利用する方法もあり、先程のドキュメントの次の節で説明されています。RHELなど各プラットフォームでの永続的な名前づけに関するリンクも掲載されています。

このudevルール含め、WALinuxAgentは随時重要な更新がされています。