5

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

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

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

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

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

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

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

5 回答 5

2

我需要一个具有 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>
于 2019-12-06T22:06:19.450 回答
2

如果您考虑此链接中的表格: 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 -DiskNumber 1 -UseMaximumSize -IsActive -AssignDriveLetter”时,你会得到 D: 给它。

因此,如果您使用 Builders 中的以下卷使用 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: as S: - 只需重复此行即可将 E: 重命名为 X: 或您需要的任何内容。

希望这可以帮助。

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

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

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

...只是,默认情况下,我的驱动器没有volumeName;他们是空白的。所以回到 1980 年的旧“标签”命令。将 D: 驱动器标记为 volume2。所以文件看起来像:

{
  "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:\ProgramData\Amazon\EC2-Windows\Launch\Config to ensure instance starts with correct drive mappings
Write-Host "S3 Download: DriveLetterMappingConfig.json"
Read-S3Object -BucketName ********* -Key DriveLetterMappingConfig.json -File 'c:\temp\DriveLetterMappingConfig.json'
Write-Host "Copying DriveLetterMappingConfig.json to C:\ProgramData\Amazon\EC2-Windows\Launch\Config..."
Copy-Item "c:\temp\DriveLetterMappingConfig.json" -Destination "C:\ProgramData\Amazon\EC2-Windows\Launch\Config\DriveLetterMappingConfig.json" -Force
Write-Host "Set Initialze Disks to run on every boot..."
C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1 -Schedule

是的,没有理由给 c 贴上标签:但我很开心……

带有“-Schedule”参数的最后一行意味着每次启动都会发生这种情况。

于 2019-09-24T16:40:34.787 回答
1

在 AWS windows 服务器 2016 及更高版本上,您可以在创建 EC2 期间使用 userdata 中的以下行来初始化辅助卷

C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1

更多信息在这里:

亚马逊支持

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

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

所以我最终将以下脚本传递给 userdata 并将其发送到保存在 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.
于 2020-07-06T19:18:47.673 回答
1

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

  1. 用“DriveLetter”标记每个卷并重视您想要分配的内容。没有“:”
  2. 在 IAM 中为 EC2 实例授予“ec2:DescribeTags”和“ec2:DescribeVolumes”权限
  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
    }
于 2020-04-30T19:04:11.520 回答
0

首先,我们强制执行安装约定,简单地说明非 root 卷使用 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>  
    

于 2021-04-29T17:21:48.760 回答