Я установил 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, следующим образом:
- Подключите гостевую машину к коммутатору по умолчанию (это коммутатор по умолчанию для новой виртуальной машины).
- Установите IP-адрес DHCP на гостевой машине (это значение по умолчанию для новой виртуальной машины).
- Задайте уникальное имя компьютера/хоста в гостевой ОС, например
myfirstvm
. DNS-суффикс не имеет значения. - С другой виртуальной машины или хоста попробуйте связаться с
<host_name>.mshome.net
, например, если вы установили имя хоста наmyfirstvm
, попробуйте выполнить pingmyfirstvm.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. Это, скорее всего, будет отличаться в разных операционных системах, поэтому вам, скорее всего, придется поискать руководство для вашей системы (или задать новый вопрос), если вы не можете получить адрес со стороны хоста.
Я оставил раздел резервного копирования и просто закомментировал его, чтобы было легче экспериментировать и итерировать скрипт. Также, чтобы было легче делать резервные копии, если они нужны в более разумном месте (резервные копии не нужны, если не вносятся изменения, поэтому не делайте их до того, как изменения будут записаны).
Я также поместил комментарий о том, как работает регулярное выражение для подстановки адреса в код, а не здесь, в теле поста. Это сделано для того, чтобы было легче следовать коду, если ссылка на этот пост потеряется после копирования-вставки, и, надеюсь, поможет, если кто-то захочет внести в него изменения.