使用 Terraform、Chef 或 Powershell 以编程方式设置 EBS 卷 Windows 驱动器号



我正在使用terraform和chef来创建多个aws ebs卷并将它们附加到EC2实例。

问题是我希望能够为每个 ebs 卷提供一个特定的 Windows 驱动器号。问题是当EC2实例实例化窗口时,只是给它顺序驱动器号(D,E,F等)

某些驱动器的大小相同,因此我不一定能根据驱动器大小重命名。有谁知道用地形或厨师做到这一点的方法。我的谷歌foo没有找到任何东西。

当然,这必须为其他人提出吗?

我确实看到了使用 EC2Config Windows GUI 来设置它们的参考,但重点是自动化该过程,因为最终我希望 chef 安装 SQL Server,并且某些数据预计会在某些驱动器号上传输。

这似乎有效 - 尽管我确实想知道是否有更简单的方法。

function Convert-SCSITargetIdToDeviceName
{
param([int]$SCSITargetId)
If ($SCSITargetId -eq 0) {
return "/dev/sda1"
}
$deviceName = "xvd"
If ($SCSITargetId -gt 25) {
$deviceName += [char](0x60 + [int]($SCSITargetId / 26))
}
$deviceName += [char](0x61 + $SCSITargetId % 26)
return $deviceName
}
Get-WmiObject -Class Win32_DiskDrive | ForEach-Object {
$DiskDrive = $_
$Volumes = Get-WmiObject -Query "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='$($DiskDrive.DeviceID)'} WHERE AssocClass=Win32_DiskDriveToDiskPartition" | ForEach-Object {
$DiskPartition = $_
Get-WmiObject -Query "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='$($DiskPartition.DeviceID)'} WHERE AssocClass=Win32_LogicalDiskToPartition"
}
If ($DiskDrive.PNPDeviceID -like "*PROD_PVDISK*") {
$BlockDeviceName = Convert-SCSITargetIdToDeviceName($DiskDrive.SCSITargetId)
If ($BlockDeviceName -eq "xvdf") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="D:"; Label="SQL Data"} };
If ($BlockDeviceName -eq "xvdg") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="L:"; Label="SQL Logs"} };
If ($BlockDeviceName -eq "xvdh") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="R:"; Label="Report Data"} };
If ($BlockDeviceName -eq "xvdi") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="T:"; Label="Temp DB"} };
If ($BlockDeviceName -eq "xvdj") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="M:"; Label="MSDTC"} };
If ($BlockDeviceName -eq "xvdk") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="B:"; Label="Backups"} };
} ElseIf ($DiskDrive.PNPDeviceID -like "*PROD_AMAZON_EC2_NVME*") {
$BlockDeviceName = Get-EC2InstanceMetadata "meta-data/block-device-mapping/ephemeral$($DiskDrive.SCSIPort - 2)"
If ($BlockDeviceName -eq "xvdf") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="D:"; Label="SQL Data"} };
If ($BlockDeviceName -eq "xvdg") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="L:"; Label="SQL Logs"} };
If ($BlockDeviceName -eq "xvdh") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="R:"; Label="Report Data"} };
If ($BlockDeviceName -eq "xvdi") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="T:"; Label="Temp DB"} };
If ($BlockDeviceName -eq "xvdj") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="M:"; Label="MSDTC"} };
If ($BlockDeviceName -eq "xvdk") { $drive = gwmi win32_volume -Filter "DriveLetter = '$($Volumes.DeviceID)'"; Set-WmiInstance -input $drive -Arguments @{DriveLetter="B:"; Label="Backups"} };
} Else {
write-host "Couldn't find disks";
}
}

> 我需要一台具有 4 个相同大小的驱动器的 Windows Server 2016,但我不在乎哪个块设备变成了哪个驱动器号。以下是我(使用Packer)获取此内容的步骤:

首先,在模板的构建器区域中,根据需要添加任意数量的块设备(在我的情况下 -launch_block_device_mapping下的 4 个条目)。然后,在预配器列表中运行以下命令:

  1. 使用任何Windows 2016 Amazon实例上可用的脚本初始化磁盘;这将使每个磁盘联机,向其添加分区,将分区扩展到最大可能的大小,格式化分区并为其分配Windows驱动器号。

    {
    "type": "powershell",        
    "inline": [
    "C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1"        
    ]
    }
    

    笔记:

    如果添加"-Schedule">参数,则此时不会初始化磁盘,因为此选项只会将脚本添加到计划在下次启动实例时运行一次的任务(之后会停用)。

    驱动器号按字母顺序分配,从 D 开始(因为 C 是为根驱动器保留的)。

    卷附加到实例的顺序与块储存设备名称无关,并且不会有一对一的对应关系(xvdb 不会变成D:\驱动器,xvdc不会变成E:\,等等)

  2. 将所需的标签分配给已初始化磁盘的每个驱动器号。

    {
    "type": "powershell",
    "inline": [
    "write-output "Label partitions after initializing disks"",
    "label C: "OS"",
    "label D: "Programs"",
    "label E: "Data"",
    "label F: "Backup"",
    ...
    ]
    }
    

    注意:另一个可能的选择是在运行磁盘初始化脚本之前直接在DriveLetterMapping.json文件(可在任何 Windows 2016 Amazon AMI 上使用)中添加标签(我无法完成此操作)。

  3. 添加可能需要的任何其他配置程序(例如,激活 Windows 组件、安装应用程序或检查 Windows 更新)后,作为配置程序列表中的最后一个条目,请确保添加了实例初始化和 SysPrep 脚本

    {
    "type": "powershell",
    "inline": [
    "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule",
    "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown"
    ]
    }
    

    注意:最后一步特定于 EC2Launch,从 Windows 2016 开始适用。对于旧版本(如Windows 2012),语法有所不同,它基于EC2Config。

从此配置获取 AMI 后,从该配置启动的任何实例的驱动器号都应符合要求。

如果驱动器号及其标签未按预期映射,您还可以尝试使用实例的用户数据强制重新标记驱动器。在启动它之前,可以轻松地将 powershell 脚本作为明文传递;下面只是一个可能的例子:

<powershell>
write-output "Force re-map of drive letters based on labels, after disk initialization"
# remove drive letters, but keep labels
Get-Volume -Drive D | Get-Partition | Remove-PartitionAccessPath -accesspath "D`:"
Get-Volume -Drive E | Get-Partition | Remove-PartitionAccessPath -accesspath "E`:"
Get-Volume -Drive F | Get-Partition | Remove-PartitionAccessPath -accesspath "F`:"
# add drive letters based on labels
get-volume | where filesystemlabel -match "Programs" | Get-Partition | Set-Partition -NewDriveLetter D
get-volume | where filesystemlabel -match "Data" | Get-Partition | Set-Partition -NewDriveLetter E
get-volume | where filesystemlabel -match "Backup" | Get-Partition | Set-Partition -NewDriveLetter F
</powershell>

如果您考虑此链接中的表格: https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-volumes.html

您可以看到,在 EBS 上,第一行是:

Bus Number 0, Target ID 0, LUN 0 /dev/sda1
Bus Number 0, Target ID 1, LUN 0 xvdb

EC2 始终将磁盘 0 (/dev/sda1) 设置为 C:

所以你知道当你运行"New-Partition -DiskNumber1-UseMaximumSize -IsActive -AssignDriveLetter"时,你会得到D:给它。

因此,如果您在构建器中使用以下卷(在本例中只有两个卷,但您可以执行许多卷)使用 Packer 预置 AMI 映像:

"launch_block_device_mappings": [{
"device_name": "/dev/sda1",
"volume_size": 30,
"volume_type": "gp2",
"delete_on_termination": true
},
{
"device_name": "xvdb",
"volume_size": 30,
"volume_type": "gp2",
"delete_on_termination": true    
}]

..你可以计划,知道 xvd[b] 实际上是将要映射的内容后面的两个字母。

然后使用 Terraform 启动此多卷 AMI 的 EC2 实例,并将其放在aws_instance资源的user_data部分中:

user_data = <<EOF
<powershell>
Initialize-Disk -Number 1 -PartitionStyle "MBR"
New-Partition -DiskNumber 1 -UseMaximumSize -IsActive -AssignDriveLetter
Format-Volume -DriveLetter d -Confirm:$FALSE
Set-Partition -DriveLetter D -NewDriveLetter S
</powershell>
EOF

Set-Partition -DriveLetter D -NewDriveLetter S行是用于将已知顺序驱动器重命名为习惯的任何字母的行。 就我而言,他们希望 D: 作为 S: - 只需重复这一行即可将 E: 重命名为 X: 或任何您需要的名称。

希望这有帮助。

更新:还有另一种方法(Server 2016 up),当我发现 Sysprep 将所有映射烘焙到 AMI 映像中时,我发现了这种方法。

您必须在 C:\ProgramData\Amazon\EC2-Windows\Launch\Config 中提供一个 DriveLetterMappingConfig.json 文件才能进行映射。文件的格式为:

{
"driveLetterMapping": [
{
"volumeName": "sample volume",
"driveLetter": "H"
}
]
}

。只是,默认情况下,我的驱动器没有卷名;他们是空白的。所以回到 1980 年代的老式"LABEL"命令。已将 D: 驱动器标记为卷 2。所以文件看起来像:

{
"driveLetterMapping": [
{
"volumeName": "volume2",
"driveLetter": "S"
}
]
}

运行 C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1 测试了这个工作(D: 变成了 S:)

所以现在,回到Packer,我还需要使用C:\ProgramData\Amazon\EC2-Windows\Launch\Config中的DriveLetterMappingConfig.json文件配置映像,以确保我在AMI的S:上所做的所有驱动器工作在实例上恢复为S:。(我将文件与我们将要安装在盒子上的所有其他垃圾一起放入 S3 存储桶中。

我将磁盘内容放入 .ps1 并从配置器调用它:

{ "类型": "Powershell", "脚本": "./setup_two_drive_names_c_and_s.ps1">
},

其中上述 .ps1 是:

# Do volume config of the two drives
write-host "Setting up drives..."
Initialize-Disk -Number 1 -PartitionStyle "MBR"
New-Partition -DiskNumber 1 -UseMaximumSize -IsActive -AssignDriveLetter
Format-Volume -DriveLetter d -Confirm:$FALSE
label c: "volume1"
label d: "volume2"
Set-Partition -DriveLetter D -NewDriveLetter S
# Now insert DriveLetterMappingConfig.json file into C:ProgramDataAmazonEC2-WindowsLaunchConfig to ensure instance starts with correct drive mappings
Write-Host "S3 Download: DriveLetterMappingConfig.json"
Read-S3Object -BucketName ********* -Key DriveLetterMappingConfig.json -File 'c:tempDriveLetterMappingConfig.json'
Write-Host "Copying DriveLetterMappingConfig.json to C:ProgramDataAmazonEC2-WindowsLaunchConfig..."
Copy-Item "c:tempDriveLetterMappingConfig.json" -Destination "C:ProgramDataAmazonEC2-WindowsLaunchConfigDriveLetterMappingConfig.json" -Force
Write-Host "Set Initialze Disks to run on every boot..."
C:ProgramDataAmazonEC2-WindowsLaunchScriptsInitializeDisks.ps1 -Schedule

是的,没有理由给 C 贴上标签:但我在滚动...

带有"-Schedule"参数的最后一行表示每次启动都会发生这种情况。

稍微复杂的解决方案。设置为此工作

  1. 用"DriveLetter"标记每个卷,并评估要分配的内容。不带":">
  2. 在 IAM 中为 EC2 实例授予"ec2:描述标签"和"ec2:描述卷"权限
  3. 运行以下脚本,方法是将其传递到用户数据中,或者创建一个 ssm 文档并在启动后运行它
Get-Disk|where-Object IsSystem -eq $False|Foreach-Object {
if ( $_.PartitionStyle -Eq 'RAW') {
Initialize-Disk -Number $_.Number –PartitionStyle MBR
Set-Disk -Number $_.Number -IsOffline $False
$VolumeId=$_.SerialNumber -replace "_[^ ]*$" -replace "vol", "vol-"
$InstanceId = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/instance-id" -UseBasicParsing).Content
$DriveLetter = Get-EC2Volume -Filter @{Name="volume-id";Values=$VolumeId},@{Name="attachment.instance-id";Values=$instanceId}  |ForEach-Object {$_.Tags}|where Key -eq "DriveLetter"|Select-Object -Property Value |foreach-Object {$_.Value}
New-Partition -DiskNumber $_.Number -DriveLetter $DriveLetter –UseMaximumSize
Format-Volume -DriveLetter $DriveLetter
}

<</div> div class="one_answers">在 AWS Windows Server 2016 及更高版本上,您可以使用 userdata 中的以下行在 EC2 创建期间初始化辅助卷

C:ProgramDataAmazonEC2-WindowsLaunchScriptsInitializeDisks.ps1

更多信息在这里 :

亚马逊支持

  • 为什么在启动新的 EC2 Windows Server 2016 实例时看不到我的辅助卷?

  • EC2启动 v2 设置

上面的 AWS 脚本将磁盘初始化为仅 MBR 类型 。(我们不能用MBR类型扩展卷>2TB)

我的用例是初始化 GPT 类型卷。

所以我最终将以下脚本传递给用户数据并将其发送到保存在 C 驱动器中的文件 (我已经提到了Manpreet Nehras的建议来框架用户脚本 https://stackoverflow.com/a/61530894/8227788)

$disks = Get-Disk|where-Object  partitionstyle -eq 'RAW' 
foreach ($diski in $disks) {
Initialize-Disk -Number $diski.Number
Set-Disk -Number $diski.Number -IsOffline $False
$VolumeId=$diski.SerialNumber -replace "_[^ ]*$" -replace "vol", "vol-"
$InstanceId = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/instance-id" -UseBasicParsing).Content
$DriveLetter = (Get-EC2Tag -Filter @{Name="resource-type";Value="volume"},@{Name="resource-id";Value=$VolumeId} | where-object Key -eq "driveletter").value
New-Partition -DiskNumber $diski.Number -DriveLetter $DriveLetter –UseMaximumSize
Format-Volume -DriveLetter $DriveLetter
}
Start-Sleep -s 120
'@
$initializescript | Out-File C:initializescript.ps1
Start-Sleep -s 30  
Then, I called the above script through AWS SSM by creating and associating it with instance . Below is the code

resource "aws_ssm_association" "initialize" {
count = length(var.ec2_name)
name        = var.ssm_document_name
targets {
key    = "InstanceIds"
values = [element(aws_instance.ec2server[*].id, count.index)]
}
}

resource "aws_ssm_document" "InitializeDrives" {
name          = "initializedriveswindows"
document_type = "Command"
content = <<DOC
{
"schemaVersion": "2.2",
"description": "Run command to initialize drives",
"parameters": {
"Message": {
"type": "String",
"description": "Run command to initialize drives",
"default": "Run command to initialize drives"
}
},
"mainSteps": [
{
"action": "aws:runPowerShellScript",
"name": "powershell",
"inputs": {
"runCommand": [
"C:\initializescript.ps1",
"Restart-Computer -Force"
]
}
}
]
}
DOC
} ```
I have included sleep time to avoid race issues.

首先,我们强制执行一个安装约定,该约定仅声明 对于非根卷 对设备使用 xvdDRIVE 约定,其中 DRIVE 与要装载到的驱动器号相同

xvdd - D:
xvde - E:
xvdm = M:

支持驱动器分配..包括"跳过级别"安装

format the volumes .. with the drive letter or some other convention you like
we run diskpart with an input file.. but basically
format fs=ntfs label=D quick

然后我们更新 DriveletterConfig.xml 或 DriveLetterConfig.json(取决于 ec2config 或 ec2launch)

for xml looks like:
<Mapping> <VolumeName>D</VolumeName> <DriveLetter>D:</DriveLetter></Mapping>
<Mapping> <VolumeName>E</VolumeName> <DriveLetter>E:</DriveLetter> </Mapping>
<Mapping> <VolumeName>M</VolumeName> <DriveLetter>M:</DriveLetter> </Mapping>  

相关内容

  • 没有找到相关文章

最新更新