Примечания

Примечания

Я установил Ubuntu 18.04 в Hyper-V на хосте Windows 10 и раскрыл функциональность на некоторых портах, которые доступны другим программам, работающим на хосте при доступе http://vm-ip-number:port(например, http://192.168.0.1:12345). Работает очень хорошо.

Я хотел бы использовать имя вместо IP-номера виртуальной машины для подключения к ней (по всем обычным причинам, поскольку это будет идти в файлах конфигурации). Для полных серверов Linux или MacOS я бы позволил хосту объявлять себя с помощью zeroconf, но некоторые поиски показали, что это не работает хорошо для Windows 10 через границы виртуальных машин.

Другой подход может заключаться в том, чтобы Hyper-V назначил виртуальной машине имя, предоставленное мной, которое затем будет доступно, когда виртуальная машина будет запущена, но я недостаточно знаком с Hyper-V, чтобы знать, возможно это или нет. Установка дополнительных инструментов только для этого в гостевой системе приемлема, в хостовой — только при необходимости.

Все, что мне нужно, — это иметь возможность http://my-own-nameдоступа к работающей виртуальной машине без жесткого кодирования IP-номера где-либо.

Предложения?

решение1

Следующий скрипт PowerShell сгенерирует hostsфайл, содержащий IP-адреса и имена виртуальных машин для всех запущенных виртуальных машин:

get-vm | Get-VMNetworkAdapter | ? IPAddresses -ne $null | % {Write-Output "$($_.ipaddresses[0]) $($_.VMName)"} | Set-Content -Path ".\hosts"

Некоторые моменты, на которые следует обратить внимание:

  • Скрипт необходимо запускать от имени администратора.

  • TheНабор-Контент команде нужен лучший параметр Path, так как в настоящее время она перезаписывает файл hostsв текущей папке.

  • Если вы не хотите, hostsчтобы файл был перезаписан, а добавлен, используйте Добавить контент вместо этого команду. Таким образом, вы можете начать с исходного hostsфайла и просто добавить к нему.

  • The Запись-Вывод команда выводит первую запись в ipaddressesполе. Если включены и IPv4, и IPv6, список будет содержать две записи, где первая запись обычно относится к IPv4.

Пример hostsфайла, который был сгенерирован для моей работающей виртуальной машины с помощью этого скрипта:

172.17.223.121 Windows10Test

(Вероятно, лучше избегать пробелов в именах виртуальных машин, иначе потребуется больше работы над скриптом.)

решение2

Добавьте IP-адрес в файл HOSTS Windows. Полный путь — C:\Windows\System32\drivers\etc\hosts. Запустите Блокнот (или любой текстовый редактор) от имени администратора и откройте этот файл с помощью Ctrl+ O. Затем добавьте IP-адрес. Формат будет следующим: IP-адрес, затем гостевое имя. Вот пример:

# This is a comment
# 127.0.0.1 localhost loopback
# ::1 localhost

192.168.0.1 myguest

Для получения дополнительной информации читайтеВикипедия: hosts(файл).

решение3

Я нашел способ подключаться по имени к гостевым виртуальным машинам из других гостевых виртуальных машин или с хоста, используя имена, которые автоматически управляются Hyper-V, следующим образом:

  1. Подключите гостевую машину к коммутатору по умолчанию (это коммутатор по умолчанию для новой виртуальной машины).
  2. Установите IP-адрес DHCP на гостевой машине (это значение по умолчанию для новой виртуальной машины).
  3. Задайте уникальное имя компьютера/хоста в гостевой ОС, например myfirstvm. DNS-суффикс не имеет значения.
  4. С другой виртуальной машины или хоста попробуйте связаться с <host_name>.mshome.net, например, если вы установили имя хоста на myfirstvm, попробуйте выполнить ping myfirstvm.mshome.netс хоста.

Объяснение:

В моей системе я нашел файл в том же каталоге, что и hostsфайл с именем hosts.ics. Он, похоже, содержал записи для всех моих гостей, прикрепленных кDefault Switch и запись для базовой системы, но все с суффиксом mshome.net. Я считаю, что сетевые адаптеры, подключенные к коммутатору по умолчанию, используют функцию общего доступа к подключению к Интернету, которая автоматически создает и поддерживает этот hosts.icsфайл. Когда ваш гость загружается, он запрашивает IP-адрес по DHCP и пытается зарегистрироваться на DNS-сервере, встроенном в Hyper-V. Я считаю, что Hyper-V берет имя, которое гость пытается зарегистрировать, и сохраняет его в этом hosts.icsфайле с новым суффиксом mshome.net. Если две из ваших гостевых виртуальных машин попытаются зарегистрировать одно и то же имя, то этот процесс прервется.

Не уверен, новая ли это функция или она всегда была. Найдено в Windows 11 Pro, Hyper-V 10.0.22000.1

решение4

Этот скрипт PowerShell основан наЛюк Шлатерответ (https://superuser.com/a/1485949/280673) на этот вопрос.

Самое важное отличие в том, что он не перезаписывает весь файл hosts IP-адресами ваших виртуальных машин, а вместо этого добавляет новые записи, если есть новые виртуальные машины, и перезаписывает адреса уже существующих записей. Это должно устранить необходимость в создании резервных копий и сохранить другие записи в файле hosts, которые вы могли сделать для локальной разработки или других целей.

#Requires -RunAsAdministrator

# Based on: https://superuser.com/a/1485949

Write-Host "Fix entries for local HyperV VMs in hosts file."

Set-StrictMode -Version 3.0
$ErrorActionPreference = "Stop"
$hostsFile = "${env:SystemRoot}/System32/drivers/etc/hosts"

$hostsFileContentOriginal = (Get-Content $hostsFile)
$hostsFileContent = $hostsFileContentOriginal

Write-Debug "Original hosts file content:"
Write-Debug ($hostsFileContent | Out-String)
Write-Debug "`n`n"

foreach ($vm in (Get-VM | Get-VMNetworkAdapter))
{
   $vmName = $($vm.VMName)
   $vmNameSanitized = $vm.VMName.ToLower() -replace '[. ]',''
   $hostName = "${vmNameSanitized}.local"
   Write-Verbose "Porcessing $vm."
   if (0 -lt $vm.IPAddresses.Length)
   {
      Write-Verbose "VM ${vmname} has IP addresses, updating hosts file."
      $address = $vm.IPAddresses[0]
      Write-Verbose "Selected IP Address for ${vmname}: $address."
      Write-Debug "All IP Addresses for ${vmname}: $($vm.IPAddresses)."

      $vmPreviouslyAddedToHostsFile = $hostsFileContent -match ".*$hostName.*"
      if($vmPreviouslyAddedToHostsFile)
      {
         Write-Verbose "VM $vmName already present in hosts, updating entry."
         # # Regex explanation
         # - `([^\d]*)` is a grouping `()` of 0 or more of the character group `[]*` that contains no digits `^\d`.
         # - `(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})` is a grouping `()` of 4 collections of 1 to 3 digits `\d{1,3}`, separated by a dot `\.`, which should match an ipv4 address.
         # - `(\s+$hostName.*)` is a grouping `()` that matches 1 or more spaces `\s+`, followed by the content of the hostname variable `$hostName`, followed by 0 or more of any characters `.*`.
         # # Substitution expression explanation
         # `${n}` is used to access the n-th (1 indexed) grouping from the regex.
         # Because we want to access the `$address` variable we can't use literal strings `''` but have to use normal strings instead `""`.
         # This results in having to escape the `$` character when doing the group substitution access.
         # # Caveat emptor
         # This only works for ipv4 addresses as written.
         # If you want to support ipv6 addresses, consider using `([a-f0-9:]+:+)+[a-f0-9]+` from https://stackoverflow.com/a/37355379 .
         # It will fail in interesting ways if the entry is commented out and there are digits in the comment in a position preceding the address.
         $hostsFileContent = $hostsFileContent -replace "([^\d]*)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(\s+$hostName.*)","`${1}$address`${3}" -join "`r`n"
      }
      else
      {
         Write-Verbose "VM $vmName not previously in hosts, appending entry."
         $hostsFileContent += "$address $hostName" -join "`r`n"
      }
   }
   else
   {
      Write-Verbose "VM ${vmname} doesn't have IP addresses, skipping."
   }
}

$originalAsString = ($hostsFileContentOriginal | Out-String)
$updatedAsString = ($hostsFileContent | Out-String)

Write-Debug "`n`nUpdated hosts file content:"
Write-Debug "$updatedAsString"

if($originalAsString -ne $updatedAsString)
{
   Write-Host "There are new addresses for VMs, updtating hosts file."

   # $datestring = (Get-Date -Format "o") -replace '[:\-]','-'
   # $backupHostsFile = "$hostsFile.${datestring}.bak"
   # Write-Verbose "Backing up hosts file to $backupHostsFile."
   # Copy-Item $hostsFile $backupHostsFile

   # Write-Verbose "Setting new hosts file content."

   Set-Content -Path $hostsfile -Value $hostsFileContent -Encoding UTF8
}
else
{
   Write-Host "No new VMs or addresses, exiting."
}

Примечания

В зависимости от вашей виртуальной машины вам может потребоваться установить дополнительные пакеты внутри виртуальной машины, например:hypervна arch, прежде чем вы сможете выкопать IP, который назначается виртуальной машине из HyperV и powershell. Это, скорее всего, будет отличаться в разных операционных системах, поэтому вам, скорее всего, придется поискать руководство для вашей системы (или задать новый вопрос), если вы не можете получить адрес со стороны хоста.

Я оставил раздел резервного копирования и просто закомментировал его, чтобы было легче экспериментировать и итерировать скрипт. Также, чтобы было легче делать резервные копии, если они нужны в более разумном месте (резервные копии не нужны, если не вносятся изменения, поэтому не делайте их до того, как изменения будут записаны).

Я также поместил комментарий о том, как работает регулярное выражение для подстановки адреса в код, а не здесь, в теле поста. Это сделано для того, чтобы было легче следовать коду, если ссылка на этот пост потеряется после копирования-вставки, и, надеюсь, поможет, если кто-то захочет внести в него изменения.

Связанный контент