EC2上のWindowsサーバーでディスクとEBSボリュームのマッピングについて

EC2で構築したWindowsサーバにおいて。
下記画像のように同じ容量で複数のEBSが割り当たっている場合。
（画像はDドライブからHドライブがすべて8GB）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/24b2e37d-1c6f-fc03-b8bc-ccde1fadfc9b.png)

下記のようなマネジメントコンソール上の表示と見比べてみると、どのEBSボリュームがOS上ではどのディスクに割り当たっているのかぱっと見ではわかりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/e07b9c01-4f99-31c6-99b3-cdcbe8b57ca7.png)

本記事ではこのような場合、OS上のディスクとEBSボリュームをマッピングする方法について説明します。

なお、後述しますがNitro世代のNVMeドライブとNitro以前では状況が異なるのでその点についても少しだけ触れます。

## 今回利用する環境

- Windows Server 2022(ami-0987eed561fe06332 Windows_Server-2022-English-Full-Base-2024.07.10)
- t3.micro
- ebsnvme-id.exe 
- PowerSHell 5.1.20348.2582

## ebsnvme-id.exeを利用してNVMeドライブのマッピングをおこなう。（t3.microでNVMe）

[EBS デバイスの特定](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/nvme-ebs-volumes.html#identify-nvme-ebs-device)

最近ではAWSが提供するWindowsイメージから構築していれば、すでに下記パスに配置済みかと思います。

`C:\PROGRAMDATA\AMAZON\Tools`

こちらを利用すると簡単にディスクとEBSボリュームのマッピングを行えます。
（Windows Server 2008以降 かつ　NVMeのみ対応）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/c8f1f17d-f880-6a82-acf2-16c9b7b1184c.png)

画像では`C:\ProgramData\Amazon\tools\ebsnvme-id.exe`を実行するとOS上のDisk Numberとそれに対応するとVolume IDとDevice Nameが表示されます。

Disk Numberからドライブレターを確認するにはディスクの管理から確認するか
（画像ではDisk Number 4がFドライブである事を確認している）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/cd417222-fecf-23e1-d9fb-8ed120621131.png)

### PowerShellコマンドでドライブレターまで取得してみる

下記のようなワンライナーで一括して出力する事ができます。

```powershell
Get-Partition | Where-Object DriveLetter | Select-Object DiskNumber , DriveLetter, @{name='Volume ID';expression={ C:\ProgramData\Amazon\tools\ebsnvme-id.exe $_.DiskNumber | Select-String "Volume ID"}},@{name='Device Name';expression={ C:\ProgramData\Amazon\tools\ebsnvme-id.exe $_.DiskNumber | Select-String "Device Name"}} 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/359c961a-9faf-578b-62c7-f8259474531c.png)

だいぶ手抜きをしていて、`ebsnvme-id.exe`の処理結果をそのまま出力しているので`Volume ID`と`Device Name`項目に入っている文字列が`Volume ID: vol-003f21ceb8373f470`や`Device Name: xvdd`といった具合にPrefixに余計な文字列がついています。

## PowerShellスクリプト（mappings.ps1）を利用してドライブのマッピングを行う。（t3.microでNVMe）


[Windows インスタンスでのディスクとボリュームのマッピング](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/ec2-windows-volumes.html)

ebsnvme-id.exeを利用する方法以外に、上記ドキュメントにPowerShellスクリプト(mappings.ps1)の記載あるので、こちらを利用してディスクとEBSボリュームのマッピングを行えます。
（Windows Server 2012以降に対応）

なお後述しますが、スクリプト内部ではAWS Tools for Windows PowerShellを利用しているため、EC2の情報が取得できるようなIAMロールをEC2にアタッチするか、個別にAWS Tools for Windows PowerShellに認証情報をセットする必要があります。

### EC2にアタッチするIAMロールの調整

今回はEC2にアタッチするロールとしてqiita-ec2-roleを作成してec2にアタッチしました。

qiita-ec2-roleの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/776b5572-3321-f992-fa94-c0696478161a.png)

EC2へアタッチ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/e5fa30fc-3e9d-7e66-b08a-dbadd32bd7be.png)

### mappings.ps1の作成

```powershell:mappings.ps1
# List the disks for NVMe volumes

function Get-EC2InstanceMetadata {
    param([string]$Path)
    (Invoke-WebRequest -Uri "http://169.254.169.254/latest/$Path").Content 
}

function GetEBSVolumeId {
    param($Path)
    $SerialNumber = (Get-Disk -Path $Path).SerialNumber
    if($SerialNumber -clike 'vol*'){
        $EbsVolumeId = $SerialNumber.Substring(0,20).Replace("vol","vol-")
    }
    else {
       $EbsVolumeId = $SerialNumber.Substring(0,20).Replace("AWS","AWS-")
    }
    return $EbsVolumeId
}

function GetDeviceName{
    param($EbsVolumeId)
    if($EbsVolumeId -clike 'vol*'){
    
        $Device  = ((Get-EC2Volume -VolumeId $EbsVolumeId ).Attachment).Device
        $VolumeName = ""
    }
     else {
        $Device = "Ephemeral"
        $VolumeName = "Temporary Storage"
    }
    Return $Device,$VolumeName
}

function GetDriveLetter{
    param($Path)
    $DiskNumber =  (Get-Disk -Path $Path).Number
    if($DiskNumber -eq 0){
        $VirtualDevice = "root"
        $DriveLetter = "C"
        $PartitionNumber = (Get-Partition -DriveLetter C).PartitionNumber
    }
    else
    {
        $VirtualDevice = "N/A"
        $DriveLetter = (Get-Partition -DiskNumber $DiskNumber).DriveLetter
        if(!$DriveLetter)
        {
            $DriveLetter = ((Get-Partition -DiskId $Path).AccessPaths).Split(",")[0]
        } 
        $PartitionNumber = (Get-Partition -DiskId $Path).PartitionNumber   
    }
    
    return $DriveLetter,$VirtualDevice,$PartitionNumber

}

$Report = @()
foreach($Path in (Get-Disk).Path)
{
    $Disk_ID = ( Get-Partition -DiskId $Path).DiskId
    $Disk = ( Get-Disk -Path $Path).Number
    $EbsVolumeId  = GetEBSVolumeId($Path)
    $Size =(Get-Disk -Path $Path).Size
    $DriveLetter,$VirtualDevice, $Partition = (GetDriveLetter($Path))
    $Device,$VolumeName = GetDeviceName($EbsVolumeId)
    $Disk = New-Object PSObject -Property @{
      Disk          = $Disk
      Partitions    = $Partition
      DriveLetter   = $DriveLetter
      EbsVolumeId   = $EbsVolumeId 
      Device        = $Device 
      VirtualDevice = $VirtualDevice 
      VolumeName= $VolumeName
    }
	$Report += $Disk
} 

$Report | Sort-Object Disk | Format-Table -AutoSize -Property Disk, Partitions, DriveLetter, EbsVolumeId, Device, VirtualDevice, VolumeName
```

ドキュメントに記載しているスクリプトをmapping.ps1に保存してスクリプトを実行していきます。（そのまま貼り付けても動きますが）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/e9086246-180e-6989-bd59-57f30a801a60.png)

### 実行ポリシーの調整とmappings.ps1の実行

実行ポリシーをRemoteSignedに変更して、保存したmappings.ps1を実行します

実行するとしばらく時間がかかりますが、下記のように結果が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/774db394-0d66-2d71-ed07-9b43e28d13c1.png)

なお実行に時間がかかるのは、ちゃんと見てませんが内部的に`AWS Tools for Windows PowerShell`を利用しており、この巨大なモジュールを読み込む部分で時間がかかってそうな気がします。

### 認証情報がないとエラーになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/4b3d03e9-1c7f-cad6-02e7-b4081dbb7ac3.png)

`AWS Tools for Windows PowerShell`の認証情報がない状態で実行すると上記画像のようにエラーとなり、VirtualDeviceが`N/A`で表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/c03a90dc-47ef-7bb3-a7ed-0896d29b732a.png)

なお2024年7月現在、ドキュメントには上記画像のように記載されており。
認証情報がないと取得できないのは`EbsVolumeID`と書かれていますが。

EbsVolumeIDが取得できて、Deviceが取得できてない気がします。

## NVMe以前のインスタンスタイプで実行すると

紹介したAWSのドキュメントにも記載がありますが、今回紹介している手順はNVMeドライバを対象としています。

このためNVMeドライバを使わない、Nitro以前のインスタンスタイプ（t2.micro）で同様にebsnvme-id.exeとPowerShellスクリプトを実行するとどうなるか確認してみます。

#### Nitro以前のt2.microでebsnvme-id.exeを実行してみる

Nitro以前なt2などのインスタンスタイプで実行すると下記のようになります。

```powershell
# メタデータ（IMDSv2)にアクセスしてインスタンスタイプ表示
$headers = @{ "X-aws-ec2-metadata-token-ttl-seconds" = 21600 }
$token = Invoke-RestMethod http://169.254.169.254/latest/api/token -Method Put -Headers $headers
$tokenHeader = @{ "X-aws-ec2-metadata-token" = $token }
irm http://169.254.169.254/latest/meta-data/instance-type -Headers $tokenHeader

# ebsnvme-id.exe実行
C:\ProgramData\Amazon\tools\ebsnvme-id.exe
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/96ef5614-8f4a-4c45-7156-d9dec04a5422.png)

画像のように`No EBS NVMe disks found.`となり情報が取得できません。

Nitro以前のt2インスタンスだとNVMeではないので情報が取得できないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/ce979e16-602e-fd47-375c-00e534de65b4.png)

#### Nitro以前のt2.microでmappings.ps1を実行してみる

ドキュメントにはNVMeを想定していると記載がありますが。
Nitro以前のインスタンスタイプでも正常に動作していそうです。（t2.microでしかためしてませんが下記画像のように動作しました）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/48c0f62e-a36c-5c37-94d1-80a7cc6c08a0.png)

## 総評

目視で確認できるように、EBSごとにボリュームサイズを微妙に変えたりする手法もありますが。

今回はドキュメントにある方法を確認してみました。

Nitro世代とそれ以前では少し違いが出てくるって所は気にしたい所かと思います。