sorta kinda...

主にAWS関連ですが、これに限らずいろいろ勉強したことや思ったことを書いていきます。

EBS ボリューム初期化を最小の手間で実行するスクリプトを作った

全然関係ないけど最近懸垂にハマってます、那須です。

AMI やスナップショットから EBS ボリュームを作成した場合、ストレージブロックはまだ S3 にあります。 なので何もせずに使うと「あれ?なんか遅いな…」と思うことになりますよね。 それを解消するために EBS ボリュームの初期化を行うわけです。 EBS ボリューム初期化って何よ?って方は↓このドキュメントを読んでください。

docs.aws.amazon.com

で、このドキュメントの手順を見てみると、

  1. wmic でデバイス ID を確認する
  2. 出てきたデバイス ID に対して dd や fio を実行する

という流れですが、wmic で出てきたデバイス ID をコピペして dd や fio の引数として指定するのはなんか面倒ですね。 それが数デバイスだったらまだいいんですが、10個近くなるとだいぶテンション下がります。

私の周りの方に聞く限り、EC2 インスタンスのバックアップは AMI 作成で対応されている方がほとんどだったので、EBS ボリューム初期化も全デバイスに行うことになるはずです。 それなら、手順って 1 つにできるんじゃない?

 

スクリプト実行するだけにしよう

全デバイス ID を取ってきてそれを引数に使ってコマンド実行するスクリプトを作りました。 wmic の代わりに (Get-WmiObject Win32_DiskDrive).deviceid でデバイス ID を取ってます。 dd 実行スクリプトはこんな感じ。

$dd_path = "'C:\dd.exe'"

[System.Collections.ArrayList]$processes = @()
foreach ($deviceid in (Get-WmiObject Win32_DiskDrive).deviceid) {
    $command1 = "$dd_path if=$deviceid of=/dev/null bs=1M --progress --size"
    $command2 = "Write-Host $command1"
    $dd_process = Start-Process -FilePath powershell.exe -ArgumentList "& $command2; & $command1" -PassThru
    $processes.Add($dd_process)
}
foreach ($dd_process in $processes) {
    Wait-Process -InputObject $dd_process
    Get-Process -InputObject $dd_process
}
Write-Host "Initializing Amazon EBS Volumes finished!"

fio 実行スクリプトはこんな感じ。

$fio_path = "'C:\Program Files\fio\fio.exe'"

[System.Collections.ArrayList]$processes = @()
foreach ($deviceid in (Get-WmiObject Win32_DiskDrive).deviceid) {
    $command1 = "$fio_path --filename=$deviceid --rw=read --bs=128k --iodepth=32 --direct=1 --name=volume-initialize"
    $command2 = "Write-Host $command1"
    $dd_process = Start-Process -FilePath powershell.exe -ArgumentList "& $command2; & $command1" -PassThru
    $processes.Add($dd_process)
}
foreach ($dd_process in $processes) {
    Wait-Process -InputObject $dd_process
    Get-Process -InputObject $dd_process
}
Write-Host "Initializing Amazon EBS Volumes finished!"

よく見るとわかりますが、コマンド部分が違うだけなので function でいい感じにしようと思えばできますが、そんなに頻繁に使わないのでこれでいいかなーと…

このスクリプトを対象インスタンスに置いといて、リストアした時に上記のスクリプトを実行するだけで EBS ボリューム初期化ができます。 EC2 インスタンス作成時であれば、ユーザデータにこのスクリプトを実行するように書けばさらに手間を減らせますね。

実際に実行すると、各デバイスごとに PowerShell ウィンドウが開いてコマンド実行するようになってます。

f:id:nasrinjp1:20190605083957p:plain
dd 実行の様子

f:id:nasrinjp1:20190605083930p:plain
fio 実行の様子

スクリプト実行したウィンドウでは、↓こんな感じの出力になります。 特に意識してログ等は出してないですが、必要に応じてログを出したりすることもできますよ。

PS C:\Users\Administrator> C:\exec_dd.ps1
0
1
2

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
              0        0          0       5.66   1448
              0        0          0       5.97   1816
              0        0          0       5.89   1068
Initializing Amazon EBS Volumes finished!
PS C:\Users\Administrator> C:\exec_fio.ps1
0
1
2

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
              0        0          0       5.67   3612
              0        0          0       5.92   3628
              0        0          0       6.00    380
Initializing Amazon EBS Volumes finished!

 

感想

あんまりしない作業なので毎回ドキュメントを見て思い出してやってましたが、これでドキュメントを見ずにすみます。 でも本当にあまりやらない作業なのでここまでする必要があったのかどうかは疑問が残りますが、PowerShell のお勉強をしたと思って積極的に使っていこうと思いました。